SQLPREPARE | |
---|---|
WiRuc Автор Сообщений: 1012 Дата регистрации: 09.04.2002 |
Привет сообществу
Хочу предостеречь фоксистов от использования SQLPREPARE в связке с MSSQL2000. Можете получить реальное замедление по сравнению с SQLEXEC |
Re: SQLPREPARE | |
---|---|
Igor Korolyov Сообщений: 34580 Дата регистрации: 28.05.2002 |
Факты? Пример приведи. Может быть ты его неправильно готовишь
------------------ WBR, Igor |
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. Первый вызов более быстрый и правильный. |
Re: SQLPREPARE | |
---|---|
B3ersn3V |
Цитата:Мне представляется, что оба варианта ПРАВИЛЬНЫЕ, ибо оба работают надежно. Умозрительно могу представить, почему первый вариант вызова (ODBC - синтаксис) может быть быстрее второго (SQL Server - синтаксис). НО, всегда ли это так и насколько это ощутимо для клиента? |
Re: SQLPREPARE | |
---|---|
WiRuc Автор Сообщений: 1012 Дата регистрации: 09.04.2002 |
Это всегда ТАК
Опять же откройте профайлер и убедитесь сами. Кроме того, можно еще почитать хелп ODBC, там объясняется почему правильнее использовать синтакис CALL - используется специальный протокол RPC, меньше различных конвертаций параметров, не происходит запуска батча и соответственно построения плана для него и т.д. Естественно, вариант с EXEC тоже будет выполняться, но, если вас интересует максимальная производительность, то нужно юзать CALL. |
Re: SQLPREPARE | |
---|---|
oleg_km Сообщений: 487 Откуда: СПб Дата регистрации: 02.12.2002 |
Я посмотрел в профайлере и мне показалось, что если использовать SQLEXEC с вопросительным знаком то:
1) он выполняется через ХП sp_executesql; 2) а sp_executesql уже VFP запускает ч/з {CALL}, т.к. в профайлере эти команды помечаются RPC:Completed |
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. Естественно, второй вариант предпочтительней и быстрее. |
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 и более мощная аппаратура. Но и тогда, и сейчас мне не удалось заметить РЕАЛЬНОЕ ухудшение производительности. Естественно, что в условиях моей конторы. |
Re: SQLPREPARE | |
---|---|
WiRuc Автор Сообщений: 1012 Дата регистрации: 09.04.2002 |
Естественно, я же говорил о получении МАКСИМАЛЬНОЙ производительности. Если у вас происходит вызов 10 процедур в минуту, то тут даже можно не задумываться об этом. А вот если у вас вызывается тысячи процедур в минуту (видел я одно такое приложение), то тут уже стоит задуматься об этом, тем более если пользователей много. А с подготовленными запросами еще хуже, т.к. построение плана достаточно длительная операция, особенно для SQL Server 2000.
|
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 |
© 2000-2024 Fox Club  |