crossplatform.ru

Здравствуйте, гость ( Вход | Регистрация )

> Работа с подготовленными запросами (QSqlQuery::prepare) (Firebird 2.1), оптимизация запросов, кэширование, транзакции
Steklova Olga
  опции профиля:
сообщение 3.2.2014, 19:23
Сообщение #1


Участник
**

Группа: Участник
Сообщений: 198
Регистрация: 27.9.2011
Из: Санкт-Петербург
Пользователь №: 2912

Спасибо сказали: 5 раз(а)




Репутация:   4  


Всем привет :)
Пишу класс для работы с БД.
Написала метод класса, выполняющий подключение к БД.
Написала метод класса, выполняющий вставку записей в таблицу. В таком виде он работает.
QString DBFunctions::insertToDB()
{
    QString squery;
    QSqlQuery queryIns_T_BLOCK;
    squery = "INSERT INTO T_BLOCK (A, B, C) VALUES (:A, :B, :C)";
    if (!queryIns_T_BLOCK.prepare(squery))
        return "QUERY_PREP_ERR: " + QString("'%1' %2")
          .arg("INSERT INTO T_BLOCK").arg(queryIns_T_BLOCK.lastError().text());

    for (int i = 1; i <= 3; i++) {
        queryIns_T_BLOCK.bindValue(":A", 100 * i + 1); //тестовый вариант
        queryIns_T_BLOCK.bindValue(":B", 100 * i + 2);
        queryIns_T_BLOCK.bindValue(":C", 100 * i + 3);
        queryIns_T_BLOCK.exec();
        if (!queryIns_T_BLOCK.isActive())
            return "QUERY_EXEC_ERR: " + QString("'%1' %2")
              .arg("INSERT INTO T_BLOCK").arg(queryIns_T_BLOCK.lastError().text());
        }        

    return "";
}
Метод insertToDB() в процессе работы программы вызывается многократно.
В результате, каждый раз подготавливается один и тот же запрос.
Как сделать так, чтобы запрос подготавливался только один раз?
Я хотела вынести подготовку запроса в другой метод класса, который можно будет вызвать однократно.
Насколько я понимаю, для этого queryIns_T_BLOCK должно быть известно в обоих этих методах.
Еще не написав доп. метод, а только выполнив перенос описания QSqlQuery queryIns_T_BLOCK сюда
class DBFunctions
{
...
private:
    QSqlQuery queryIns_T_BLOCK;
};
у меня перестала работать подготовка запроса.
prepare стал выдавать ошибку Driver not loaded. Не понимаю, в чем дело.
Экземпляры класса QSqlQuery могут быть только локальными переменными?

Сообщение отредактировал Steklova Olga - 7.2.2014, 18:45
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
 
Начать новую тему
Ответов
Steklova Olga
  опции профиля:
сообщение 4.2.2014, 19:11
Сообщение #2


Участник
**

Группа: Участник
Сообщений: 198
Регистрация: 27.9.2011
Из: Санкт-Петербург
Пользователь №: 2912

Спасибо сказали: 5 раз(а)




Репутация:   4  


Вы правы, Юрий, вот так prepare работает.
код с указателем
class DBFunctions
{
...
private:
    QString squery;
    QSqlQuery *q;
};
QString DBFunctions::prepareQueries()
{
    q = new QSqlQuery();
    squery = "INSERT INTO T_BLOCK (A, B, C) VALUES (:A, :B, :C)";
    if (!q->prepare(squery))
        return "QUERY_PREP_ERR: " + QString("'%1' %2")
          .arg("INSERT INTO T_BLOCK").arg(q->lastError().text());
    return "";
}
QString DBFunctions::insertToDB(const int x)
{
    for (int i = 1; i <= 3; i++) {
        q->bindValue(":A", 100 * i + x); //тестовый вариант
        q->bindValue(":B", 100 * i + x);
        q->bindValue(":C", 100 * i + x);
        q->exec();
        if (!q->isActive())
            return "QUERY_EXEC_ERR: " + QString("'%1' %2")
              .arg("INSERT INTO T_BLOCK").arg(q->lastError().text());
    }
    return "";
}


Прочитала про Кэш_запросов_(СУБД)

Как работает кэширование запросов в Firebird - к сожалению, не нашла. Где бы про это почитать?


Нашла только Кэш запросов в MySQL
Там написано:
"В процессе работы кэш запросов хранит текст запроса SELECT вместе с соответствующим результатом, который посылался клиенту.
При получении другого идентичного запроса сервер извлечет результаты из кэша запросов, а не будет анализировать и выполнять снова тот же самый запрос."
А в Firebird (в отличие от MySQL) отправляются в кэш не запросы SELECT, а все запросы, для которых делаем prepare?
А обычные запросы, выполняемые как q.exec(sQuery), отправляются в кэш?
И новый подготавливаемый запрос заносится в кэш, если в данный момент в кэше нет точно такого же действительного запроса?

и
Как работает кэширование запросов в MySQL
Там написано:
"При изменениях таблицы (INSERT, UPDATE, DELETE, TRUNCATE, ALTER или DROP TABLE|DATABASE),
все кэшированные запросы, использовавшие данную таблицу, становятся недействительными и удаляются из кэша."
То есть, в MySQL при этом становятся недействительными запросы SELECT, связанные с этой таблицей?

Насколько я понимаю, в Firebird уже подготовленный запрос тоже может стать недействительным.
Например, если
1) подготовить запрос на вставку записей в таблицу,
2) подготовить запрос на выборку данных из этой таблицы,
3) если выполнить запрос на вставку, то запрос на выборку, подготовленный заранее, станет недействительным, и хотя он и не выдаст ошибок, но не вернет ни одной записи из таблицы (так у меня получилось при проверке),
4) поэтому для выполнения запроса на выборку (после выполнения запроса на вставку) надо заново подготовить запрос на выборку.
Видимо, действительно, проще будет лишний раз подготовить запрос, чем разбираться, где он может стать недействительным.

А я и не думала, что надо учитывать такие вещи, мне только хотелось оптимизировать работу, чтобы не загружать БД разборкой одинаковых запросов.
А если я второй раз подготовлю один и тот же запрос, хотя он не стал к этому времени недействительным, то БД не будет отправлять его второй раз в кэш?

И еще вопрос про запросы, которые выполняются в программе больше одного раза.
Лучше будет для оптимизации вообще все эти запросы делать с prepare? Или есть случаи, когда лучше их выполнить сразу, без подготовки, как q.exec(sQuery) ?
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение

Сообщений в этой теме


Быстрый ответОтветить в данную темуНачать новую тему
Теги
Нет тегов для показа


1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0




RSS Текстовая версия Сейчас: 28.11.2024, 8:29