SQL-запрос со связываемыми переменными, как использовать?

Программирование на Visual Basic, главный форум. Обсуждение тем программирования на VB 1—6.
Даже если вы плохо разбираетесь в VB и программировании вообще — тут вам помогут. В разумных пределах, конечно.
Правила форума
Темы, в которых будет сначала написано «что нужно сделать», а затем просьба «помогите», будут закрыты.
Читайте требования к создаваемым темам.
Wasup!
Продвинутый пользователь
Продвинутый пользователь
 
Сообщения: 120
Зарегистрирован: 21.06.2005 (Вт) 11:09

SQL-запрос со связываемыми переменными, как использовать?

Сообщение Wasup! » 17.10.2005 (Пн) 15:28

При многократном выполнении повторяющегося запроса с использованием связываемых переменных, скорость должна
повышаться в разы, по сравнению с обычным. По крайней мере, так происходит при выполнении в самой базе данных:
select * from table where a= :<parametr> выполняется намного быстрее(5-7 раз), чем "select * from table where a=" & "<parametr>"
В аналогичной ситуации на VB, ускорение получилось всего около 40%, в связи с чем появилась мысль: или я что-то неправильно
делаю или при выполнении в VB большая часть времени тратиться на передачу данных, открытие recordset`ов?


Код: Выделить всё

Sub fastquery()
Dim c As Date

Dim cnn As New ADODB.Connection
Dim prm As New ADODB.Parameter
Set cmd = New ADODB.Command

cnn.Open "Provider=MSDAORA.1;Data Source=<db>;User id=<login>;Password=<psw>"

Set cmd.ActiveConnection = cnn
Set rs = New ADODB.Recordset
 

a = Time()
cmd.CommandText = "Select * from orders where order_num = ?"
cmd.CommandType = adCmdText

Set prm = cmd.CreateParameter("order_num", adInteger, adParamInput)
cmd.Parameters.Append prm
cmd.Prepared = True
   
For i = 1 To10000
    prm.Value = CStr(i)
    rs.Open cmd 'правильно ли, что для каждого выполнения cmd нужно открывать и закрывать recordset?
    Do While Not rs.EOF
        tmp = CStr(Abs((rs!order_num * 10000) / (-9000) + 123456789) + Len(CStr(Abs((rs!amount * 10000) / (-9000) + 123456789)))) 'произвольная функция
        rs.MoveNext
   Loop
    rs.Close
Next
b = Time()
c = b - a
MsgBox Format(c)

Set rs = Nothing
cnn.Close
Set cnn = Nothing

End Sub

GSerg
Шаман
Шаман
 
Сообщения: 14286
Зарегистрирован: 14.12.2002 (Сб) 5:25
Откуда: Магадан

Сообщение GSerg » 17.10.2005 (Пн) 15:34

А ты и вычисления tmp тоже переложи на SQL...
В остальном нормально так. Разве что не prm.Value = CStr(i), а prm.Value = i.
Как только вы переберёте все варианты решения и не найдёте нужного, тут же обнаружится решение, простое и очевидное для всех, кроме вас

Wasup!
Продвинутый пользователь
Продвинутый пользователь
 
Сообщения: 120
Зарегистрирован: 21.06.2005 (Вт) 11:09

Сообщение Wasup! » 18.10.2005 (Вт) 8:32

А многократного rs.Open и rs.Close (особенно) избежать можно?

Ennor
Конструктивный критик
Конструктивный критик
 
Сообщения: 2504
Зарегистрирован: 18.12.2001 (Вт) 3:58
Откуда: Калуга -> Москва

Сообщение Ennor » 18.10.2005 (Вт) 10:11

10000 раз открывать/закрывать рекордсет??? Кошмар. Ты на одном сетевом трафике влетаешь я не знаю как.

Хранимку напиши, в нее весь код. Огакул, я слыхал, по курсорам быстро бегает, не то что сиквел...

Wasup!
Продвинутый пользователь
Продвинутый пользователь
 
Сообщения: 120
Зарегистрирован: 21.06.2005 (Вт) 11:09

Сообщение Wasup! » 19.10.2005 (Ср) 9:11

А если подставляемый параметр берется, предположим, из книги Excel (базы access и т.д.)?
Хранимая процедура сама его вытащить не сможет, поэтому надо его передавать извне.

Код: Выделить всё

cmd.CommandText = "Select * from orders where order_num = ?"

For i = 1 To10000
    prm.Value = .cells(i,1)
    rs.Open cmd
    Do While Not rs.EOF
        .cells(i,2) = CStr(Abs((rs!order_num * 10000) / (-9000) + 123456789) + Len(CStr(Abs((rs!amount * 10000) / (-9000) + 123456789)))) 'произвольная функция
        rs.MoveNext
   Loop
    rs.Close
Next


В таком повторяющемся запросе, связанные переменные должны сильно ускорять обработку. Но этого не происходит, т.е. возможно обработка и ускоряется, но большая часть времени тратится на операции вроде rs.open rs.close. Вопрос в том: можно ли избежать таких операций? Предположим просто замещать данные в recorset`е?

Andrey Fedorov
Член-корреспондент академии VBStreets
Член-корреспондент академии VBStreets
 
Сообщения: 3287
Зарегистрирован: 21.05.2004 (Пт) 9:28
Откуда: Москва

Сообщение Andrey Fedorov » 19.10.2005 (Ср) 9:22

Wasup! писал(а):но большая часть времени тратится на операции вроде rs.open rs.close. Вопрос в том: можно ли избежать таких операций? Предположим просто замещать данные в recorset`е?


Бить надо по лапам за такое написание.

Если табличка на сервере большая и надо последовательно вытащить из нее данные пробегаясь, скажем, по записям таблицы Excel, то я бы вначале пробежался по записям и сформировал клиентский Recordset основанный на запросе в виде:

SELECT * FROM ... WHERE ID IN(...)

А если таблица на сервере не очень большая, то можно и просто

SELECT * FROM ...

Ну а далее - еще один проход по записям Excel-я с поиском Find (или Filter) записей в этом Recordset-е.

В итоге имеем минимальную загрузку сети, всего одно открытие Recordset-a и максимальную скорость...
Фиг Вам! - Сказал Чебурашка, обгладывая Крокодила Гену...

alibek
Большой Человек
Большой Человек
 
Сообщения: 14205
Зарегистрирован: 19.04.2002 (Пт) 11:40
Откуда: Russia

Сообщение alibek » 19.10.2005 (Ср) 9:24

Еще одно дополнение.
Если ты используешь параметрический запрос, который вызывается много раз, имеет смысл выставить свойство Prepared.
Lasciate ogni speranza, voi ch'entrate.

Wasup!
Продвинутый пользователь
Продвинутый пользователь
 
Сообщения: 120
Зарегистрирован: 21.06.2005 (Вт) 11:09

Сообщение Wasup! » 21.10.2005 (Пт) 11:55

Если табличка на сервере большая и надо последовательно вытащить из нее данные пробегаясь, скажем, по записям таблицы Excel, то я бы вначале пробежался по записям и сформировал клиентский Recordset основанный на запросе в виде:

SELECT * FROM ... WHERE ID IN(...)


А если записей в Excel будет много и табличка на сервере большая?
Тогда запрос для клиентского recordsetа получиться очень большой длинны.

SELECT * FROM ... WHERE ID IN(1,5, <еще 1000 id > , 114532)

Загрузить такой запрос разом не получиться.
Или я не так понял смысл?

Andrey Fedorov
Член-корреспондент академии VBStreets
Член-корреспондент академии VBStreets
 
Сообщения: 3287
Зарегистрирован: 21.05.2004 (Пт) 9:28
Откуда: Москва

Сообщение Andrey Fedorov » 21.10.2005 (Пт) 12:01

Wasup! писал(а):А если записей в Excel будет много и табличка на сервере большая?Тогда запрос для клиентского recordsetа получиться очень большой длинны.

SELECT * FROM ... WHERE ID IN(1,5, <еще 1000 id > , 114532)

Загрузить такой запрос разом не получиться.


Ну вообще-то 1000 это не столь и много - все должно загрузиться.

Если десятки тысяч, то можем нарваться на ограничение длины запроса, тогда все эти ID-шки кинуть во временную табличку и запрос по ней.

А вообще по месту смотреть надо что там - от мелочей во многом зависит подход.
Фиг Вам! - Сказал Чебурашка, обгладывая Крокодила Гену...

alibek
Большой Человек
Большой Человек
 
Сообщения: 14205
Зарегистрирован: 19.04.2002 (Пт) 11:40
Откуда: Russia

Сообщение alibek » 21.10.2005 (Пт) 12:01

Тогда скидываешь нужные ID во временную табличку и в запросе добавляешь связывание по этому полю с временной табличкой.
При тех вводных, что ты дал, клиентский курсор будет лучше всего.
Lasciate ogni speranza, voi ch'entrate.


Вернуться в Visual Basic 1–6

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 139

    TopList