:: Архив конференции по VFP до 2005 года
SQLPREPARE
WiRuc
Автор

Сообщений: 1012
Дата регистрации: 09.04.2002
Привет сообществу
Хочу предостеречь фоксистов от использования SQLPREPARE в связке с MSSQL2000.
Можете получить реальное замедление по сравнению с SQLEXEC
Ratings: 0 negative/0 positive
Re: SQLPREPARE
Igor Korolyov

Сообщений: 34580
Дата регистрации: 28.05.2002
Факты? Пример приведи. Может быть ты его неправильно готовишь




------------------
WBR, Igor
Ratings: 0 negative/0 positive
Re: SQLPREPARE
WiRuc
Автор

Сообщений: 1012
Дата регистрации: 09.04.2002
Без проблем.
Сделай параметизированный запрос (собственно, для которых HELP особенно рекомендует использовать SQLPREPARE) и посмотри в профайлере как он выполняется. Для полноты представления можешь воспользоваться любым из трайсеров вызовов API ф-ций, например из DevPartner Studio.

m.id = 1

SQLPREPARE(nConn, select * from some_table where id=?m.id)

SQLEXEC(nConn)

m.id = 2

SQLEXEC(nConn)

При первом вызове SQLEXEC с помощью вызова системной ХП sp_prepexec произойдет подготовка процедуры на сервере и ее выполнение. Эта процедура кеширует план выполнения запроса и возвращает ID плана для последующего "быстрого" выполнения. Однако, повторный вызов SQLEXEC() вместо повторного использования уже построенного плана вызывает удаление старого с помощью ХП sp_unprepare и построение нового.
В результате мы имеем, что при каждом последующем выполнении запроса вызывается exec sp_unprepare и exec sp_prepexec, что никак не может увеличивать скорость выполнения запроса (падение скорости в районе 20-30%). Получается, что лучше просто выполнить неподготовленный SQLEXEC, особенно, с учетом того, что SQL2000 умеет кешировать динамические запросы.
Кстати, тут тоже есть нюанс. Дело в том, что вызов SQLEXEC(nConn, 'select * from table where name=?m.name') с m.name='a' и m.name = 'ab' приведет к созданию в кеше ДВУХ планов, вместо одного как ожидалось. Это относится, только к параметрам символьного типа, для других типов будет создан один план. А кэш то не резиновый и при большом кол-ве пользователей/запросов мы будем иметь низкий показатель попаданий в кеш динамических запросов.

А теперь, попробуем другой вариант, без применения параметров

SQLPREPARE(nConn, select * from some_table where id=1)
SQLEXEC(nConn)
SQLEXEC(nConn)

Вот здесь будет четкое выполнение подготовленного запроса. Т.е. первый вызов подготовит план с помощью sp_prepexec, а все последующие вызовы будут выполнять процедуру sp_execute, которая собственно и выполняет подготовленный запрос.
Но имейте в виду, что даже здесь вы получите выигрыш от использования подготовленного запроса ТОЛЬКО в случае достаточно сложного запроса, а не простенького как в примере.

Чтобы разобраться в ситуации, необходимо обратиться к тому, как VFP выполняет вызовы ODBC.
Оказывается, что при КАЖДОМ вызове SQLEXEC(nConn) происходит binding параметров, а не только в первый вызов, как необходимо при параметрезированных вызовах ODBC. Соответственно, это приводит к уничтожению подготовленного запроса и построению нового плана. Было бы неплохо, если бы MS поправила бы этот баг.

Одним словом, все это четко можно увидеть, посмотрев профайлер.
И напоследок, вызывайте серверные ХП посредством конструкции {CALL proc}, а не EXEC proc. Первый вызов более быстрый и правильный.
Ratings: 0 negative/0 positive
Re: SQLPREPARE
B3ersn3V
Цитата:
вызывайте серверные ХП посредством конструкции {CALL proc}, а не EXEC proc. Первый вызов более быстрый и правильный
Мне представляется, что оба варианта ПРАВИЛЬНЫЕ, ибо оба работают надежно. Умозрительно могу представить, почему первый вариант вызова (ODBC - синтаксис) может быть быстрее второго (SQL Server - синтаксис). НО, всегда ли это так и насколько это ощутимо для клиента?
Ratings: 0 negative/0 positive
Re: SQLPREPARE
WiRuc
Автор

Сообщений: 1012
Дата регистрации: 09.04.2002
Это всегда ТАК
Опять же откройте профайлер и убедитесь сами. Кроме того, можно еще почитать хелп ODBC, там объясняется почему правильнее использовать синтакис CALL - используется специальный протокол RPC, меньше различных конвертаций параметров, не происходит запуска батча и соответственно построения плана для него и т.д.
Естественно, вариант с EXEC тоже будет выполняться, но, если вас интересует максимальная производительность, то нужно юзать CALL.
Ratings: 0 negative/0 positive
Re: SQLPREPARE
oleg_km

Сообщений: 487
Откуда: СПб
Дата регистрации: 02.12.2002
Я посмотрел в профайлере и мне показалось, что если использовать SQLEXEC с вопросительным знаком то:
1) он выполняется через ХП sp_executesql;
2) а sp_executesql уже VFP запускает ч/з {CALL}, т.к. в профайлере эти команды помечаются RPC:Completed
Ratings: 0 negative/0 positive
Re: SQLPREPARE
WiRuc
Автор

Сообщений: 1012
Дата регистрации: 09.04.2002
Во-первых, VFP никаким боком к sp_executesql отношения не имеет. Всем этим рулит драйвер ODBC. Т.е. для параметризованных запросов драйвер ODBC начинает батч, содержащий вызов вышего запроса через sp_executesql. Именно эта ХП отвечает за кеширование динамических параметризированных запросов. Если запрос непараметризирован, то просто вызывается батч, содержащий ваш запрос. При использовании CALL никакой батч не стартует, просто происходит вызов процедуры посредством RPC.

Т.е. получается такая цепочка:
1) EXEC p_test ?m.id

Драйвер считает, что это обычный запрос (а не вызов процедуры) и пускает вот такой батч
EXEC sp_executesql N'p_test @p1', @P1
Этот батч собственно ничего не делает кроме запуска процедуры. НО, т.к. используется sp_excutesql, то предварительно будет строиться и кешироваться план запроса. А строить и кешировать то его и не надо, потому-что кроме вызова процедуры он ничего не содержит.

2) {CALL p_test (?m.id)}
Вот в этом случае никаких батчей запускаться не будет, т.к. драйвер знает, что мы пытаемся вызвать процедуру. MSSQL не будет строить план выполнения и кешировать его, а просто вызовет процедуру посредством RPC. Естественно, второй вариант предпочтительней и быстрее.
Ratings: 0 negative/0 positive
Re: SQLPREPARE
B3ersn3V
2WiRuc, oleg_km
В известной книге "Client/Server Application with Visual FoxPro and SQL Server" отмечаются 2 небольших (в оригинале "two small advantages") преимущества CALL - вызова хранимых процедур SQL Server. Там же упоминается роль sp_executesql как в этом деле, так и при выполнении параметризованных запросов. При этом приводятся соответствующие распечатки профайлера.
Все это излагалось для VFP 6.0 и SQL Server 7.0. Сейчас же уже VFP 8.0, SQL Server 2000 и более мощная аппаратура. Но и тогда, и сейчас мне не удалось заметить РЕАЛЬНОЕ ухудшение производительности. Естественно, что в условиях моей конторы.
Ratings: 0 negative/0 positive
Re: SQLPREPARE
WiRuc
Автор

Сообщений: 1012
Дата регистрации: 09.04.2002
Естественно, я же говорил о получении МАКСИМАЛЬНОЙ производительности. Если у вас происходит вызов 10 процедур в минуту, то тут даже можно не задумываться об этом. А вот если у вас вызывается тысячи процедур в минуту (видел я одно такое приложение), то тут уже стоит задуматься об этом, тем более если пользователей много. А с подготовленными запросами еще хуже, т.к. построение плана достаточно длительная операция, особенно для SQL Server 2000.
Ratings: 0 negative/0 positive
Re: SQLPREPARE
Igor Korolyov

Сообщений: 34580
Дата регистрации: 28.05.2002
Очень любопытно - возможно это проблема ODBC драйвера? Или какая-то
особенность работы конкретно этой версии SQL сервера... Оно на других
версиях MS SQL-я присутствует? И есть ли какие альтернативные ODBC драйверы?

Кстати ради интереса потестировал на Oracle (с драйвером от MS кстати ) -
простейший запрос (выборка 1-й или 0 записей по PK из весьма малой таблицы -
порядка 500 записей) - разница между SQLPREPARE() и "прямыми" вызовами
SQLEXEC() - почти в 2 раза! А для MS SQL действительно полная лажа - в 1.6
раза медленнее
Что-то не так в Датском королевстве




------------------
WBR, Igor
Ratings: 0 negative/0 positive


Извините, но у вас нет прав для того, чтобы оставлять сообщения в этом форуме.

On-line: 4 (Гостей: 4)

© 2000-2024 Fox Club 
Яндекс.Метрика