Работа с подготовленными запросами (QSqlQuery::prepare) (Firebird 2.1), оптимизация запросов, кэширование, транзакции |
Здравствуйте, гость ( Вход | Регистрация )
Работа с подготовленными запросами (QSqlQuery::prepare) (Firebird 2.1), оптимизация запросов, кэширование, транзакции |
Steklova Olga |
3.2.2014, 19:23
Сообщение
#1
|
Участник Группа: Участник Сообщений: 198 Регистрация: 27.9.2011 Из: Санкт-Петербург Пользователь №: 2912 Спасибо сказали: 5 раз(а) Репутация: 4 |
Всем привет
Пишу класс для работы с БД. Написала метод класса, выполняющий подключение к БД. Написала метод класса, выполняющий вставку записей в таблицу. В таком виде он работает. Метод insertToDB() в процессе работы программы вызывается многократно.В результате, каждый раз подготавливается один и тот же запрос. Как сделать так, чтобы запрос подготавливался только один раз? Я хотела вынести подготовку запроса в другой метод класса, который можно будет вызвать однократно. Насколько я понимаю, для этого queryIns_T_BLOCK должно быть известно в обоих этих методах. Еще не написав доп. метод, а только выполнив перенос описания QSqlQuery queryIns_T_BLOCK сюда у меня перестала работать подготовка запроса. prepare стал выдавать ошибку Driver not loaded. Не понимаю, в чем дело. Экземпляры класса QSqlQuery могут быть только локальными переменными? Сообщение отредактировал Steklova Olga - 7.2.2014, 18:45 |
|
|
Steklova Olga |
7.2.2014, 18:36
Сообщение
#2
|
Участник Группа: Участник Сообщений: 198 Регистрация: 27.9.2011 Из: Санкт-Петербург Пользователь №: 2912 Спасибо сказали: 5 раз(а) Репутация: 4 |
Чем дальше пишешь, тем больше вопросов Подскажите, пожалуйста, кто знает.
1) Как работает кэширование запросов в Firebird - к сожалению, не нашла. Где бы про это почитать? у Хелен Бори есть У Хелен много написано “про кэш в общем”, еще на стр. 414-417 есть про подготовку запросов, а вот конкретно про кэширование запросов я ничего там не нашла.2) Вы уже сказали, что подготовленные запросы кэшируются (рассматривались запросы с параметрами). А какие из запросов q1 и q2 будут кэшироваться? Если кэшироваться будет только q2, то не лучше ли будет для ускорения работы использовать q2 вместо q1? 3) Обрамить всю пачку prepare-bind в транзакцию - существенно увеличить скорость выполнения этой пачки (для любой БД), а для Firebird-а ещё и меньше мусорить, т.к. он версии состояний хранит. То есть так? см код
И при qntRec = 10, и при qntRec = 20000? А почему это приводит к увеличению скорости? Где почитать про это? 4) Дополнение к предыдущему пункту. У Хелен Борри на стр. 417 сказано: “При помещении в базу данных большого количества данных в пакете предпочтительным является разбиение их на группы и подтверждение работы приблизительно через каждые 5000-10000 строк.” То есть надо стартовать транзакцию, объявить запрос, подготовить его, забиндить значения параметров и выполнить запрос для первых 10000 записей, закоммитить, потом опять стартовать транзакцию, объявить запрос, подготовить его, забиндить значения параметров и выполнить запрос для следующих 10000 записей, закоммитить? Так? 5) Прочла сейчас в документации в разделе Executing SQL Statements | Transactions, что When using transactions you must start the transaction before you create your query. Раньше не знала, поэтому у меня в программе было примерно такое: см код
объявить запрос (и использовать это объявление для нескольких запросов), выполнить неподготовленный запрос, стартовать транзакцию, выполнить неподготовленный запрос, подготовить запрос, забиндить значения параметров и выполнить его, закоммитить. Запрос на выборку, как я понимаю, выполнялся в рамках “транзакции по умолчанию”. Запросы на удаление и вставку должны либо выполниться оба, либо не выполниться совсем. Получается, что надо перенести перед А что вытворяла программа в том варианте, как был у меня? Она не выдавала ошибок, но, вероятно, делала что-то не то… 6) Т.к. Firebird версионник, он работает сильно не так как MySql. Недействительным план запроса может стать в других ситуациях. В каких? Это надо как-то дополнительно проверять?Недостаточно просто объявить запрос, подготовить его, проверить результат prepare, забиндить значения параметров запроса и выполнить его? Притом обрамив все это в транзакцию. 7) Тут говорят, что “Если некий сеанс запустил и закоммитил удаление 100500 записей, по возможности пусть он же выполнит после этого и select count(*) from t where <тот же критерий, что был при удалении этих 100500 записей>. Всё таки правило "мусор убирают те, кто его породил" - лучше, чем "... те, кто на него напоролся". ” А если у меня в таблице, например, 15000 записей. Надо их почти все удалить. Значит надо делать так? И транзакция здесь тоже нужна? см код
8 ) У Жасмин Бланшет на стр. 321 написано, что “Класс QSqlQuery содержит некоторые другие функции [кроме next()] для просмотра результирующего набора: first(), last(), previous() и seek(). Эти функции удобны, но для некоторых баз данных они могут выполняться медленнее и расходовать памяти больше, чем функция next(). При работе с большими наборами данных мы можем осуществить простую оптимизацию, вызывая функцию QSqlQuery::setForwardOnly(true) перед вызовом exec(), и только затем использовать next() для перемещения по результирующему набору.” А в доке по QSqlQuery::setForwardOnly написано, что “For this to be true, you must call setForwardOnly() before the query is prepared or executed. Note that the constructor that takes a query and a database may execute the query. Forward only mode is off by default. Calling setForwardOnly after execution of the query will result in unexpected results at best, and crashes at worst.” А если я выполняю несколько запросов, используя один QSqlQuery q, то мне каждый раз надо вызывать setForwardOnly? То есть, так? см код
Буду очень благодарна за помощь Сообщение отредактировал Steklova Olga - 10.2.2014, 12:14 |
|
|
Текстовая версия | Сейчас: 28.11.2024, 6:36 |