Подсказки о кэшировании запросов

Для исключения трансляции и выполнения часто повторяющихся SQL-запросов пользователь может подсказать СУБД о необходимости кэширования запросов и результатов их выполнения.

Для поддержки механизма кэширования запросов СУБД ЛИНТЕР создает в оперативной памяти две структуры данных для хранения ссылок (идентификаторов) на:

  • тексты кэшируемых запросов (ссылки на исходный и оттранслированный текст SQL-запроса);

  • результаты выполнения кэшируемых запросов;

  • тексты запросов и результаты их выполнения хранятся в рабочих файлах СУБД.

Управление кэшированием выполняется в утилите gendb (см. документ «СУБД ЛИНТЕР. Создание и конфигурирование базы данных»).

При поступлении на обработку очередного SQL-запроса ядро СУБД ищет текст этого запроса в кэше текстов SQL-запросов.

В случае успешного поиска повторная трансляция запроса отменяется, и, если для этого запроса задан режим кэширования результата, то результат выполнения запроса извлекается из кэша результатов (в противном случае запрос обрабатывается ядром СУБД).

В случае изменения данных в таблице (таблицах) кэшированного запроса, при удалении используемых синонимов, при изменении прав пользователя и тому подобных изменениях, оказывающих влияние на результат выполнения кэшированного запроса, результат запроса удаляется из кэша результатов. При следующей попытке получить результат выполнения кэшируемого запроса этот запрос заново обрабатывается ядром СУБД.

СУБД ЛИНТЕР поддерживает кэширование только DML-запросов (select, insert, update, delete).

Спецификация
     
< подсказка об отмене кэширования select-запроса >::=
/* +NOCACHE */
< подсказка о кэшировании запроса >::=
/* +CACHE */
< подсказка о кэшировании результата запроса >::=
/* +ANSCACHE */
Синтаксические правила
  1. Подсказка NOCACHE отменяет кэширование текста конкретного select-запроса (по умолчанию, если задан режим кэширования текстов запроса, то кэшируются тексты всех select-запросов).

  2. Подсказка CACHE заставляет кэшировать текст запроса на модификацию объекта БД (SQL-запросы на модификацию объектов БД по умолчанию не кэшируются).

  3. Подсказка ANSCACHE заставляет кэшировать результат выполнения конкретного select-запроса (по умолчанию результаты select-запросов не кэшируются).

Общие правила
  1. Кэширование запросов построено на побайтовом сравнении претранслированных запросов: если пришедший от пользователя (или от транслятора SQL) претранслированный запрос совпадает с одним из претранслированных запросов в кэше запросов, то результат выполнения запроса:

    • выбирается из кэша результатов, если в СУБД установлен режим кэширования результатов и для данного запроса использовалась подсказка о кэшировании его результата;

    • формируется ядром СУБД путем выполнения запроса.

  2. Запросы, имеющие одинаковый текст, но поданные от имени разных пользователей, являются разными запросами для кэша текстов запросов и для кэша результатов запросов.

  3. Запрещается кэшировать следующие запросы:

    • запросы к таблицам на удалённом узле. При попытке кэшировать такой запрос на консоль ядра СУБД будет выдано сообщение: «INFO: can't place answer of remote query into cache. Ignored.». Запрос будет обработан корректно, но его ответ в кэш результатов запросов занесён не будет;

    • запросы с модификаторами FOR UPDATE и FOR BROWSE, поскольку использование этих модификаторов предполагает наложение блокировок на исходную таблицу. В случае обнаружения попытки кэшировать такой запрос на консоль ядра СУБД будет выдано сообщение: «INFO: can't place answer of select query with 'for update' or 'for browse' option into cache. Ignored.». Запрос будет обработан корректно, но его ответ в кэш результатов запросов занесён не будет;

    • запросы для событий типа SELECT, например,

      create event "Select_All_From_Auto_Person" as select * from auto,person where auto.personid=person.personid;

      Это ограничение связано с необходимостью выполнять определённые действия при выдаче ответа на такой select-запрос. При попытке кэшировать такой запрос на консоль ядра СУБД будет выдано сообщение: «INFO: can't place answer of event query into cache. Ignored.». Запрос будет обработан корректно, но его ответ в кэш результатов запросов занесён не будет;

    • запросы с модификаторами, ограничивающими выборку FETCH FIRST и LIMIT. При попытке кэшировать такой запрос на консоль ядра СУБД будет выдано сообщение: «INFO: can't place part of query answer into cache. Ignored.». Запрос будет обработан корректно, но его ответ в кэш результатов запросов занесён не будет;

    • для запросов, результат которых был взят из кэша результатов запросов, нельзя выполнить команды позиционного обновления и удаления (WHERE CURRENT OF). При попытке выполнить такой запрос будет выдан код завершения 1037 («Запрос необновляемый»), а на консоль ядра СУБД будет выдано сообщение «INFO: can't execute 'current of cursor' query because answer of 'select' query was placed into answer cache. Ignored.»;

    • запросы, выбирающие BLOB-столбцы. При попытке кэшировать такой запрос на консоль ядра СУБД будет выдано сообщение: «INFO: can't place answer into cache because answer contains BLOB. Ignored.». Запрос будет обработан корректно, но его ответ в кэш результатов запросов занесён не будет.

  4. Запрещено использовать чужие кэшируемые:

    • результаты выполнения select-запросов;

    • претранслированные запросы.

Примеры
  1. Удалить данные недельной давности:

    delete /* +CACHE */  from tst where d=sysdate-7;
  2. create or replace table t(i int);
    insert into t values(1) /* +CACHE */;
    select * from t where i= 1 /* +NOCACHE */;
    insert into t values(1) /* +CACHE */;
    select * from t where i= 1 /* +NOCACHE */;
    alter table t rename to t1;
    insert into t values(1) /* +CACHE */;
    drop table t1;
  3. Запустить утилиту gendb и выполнить команду
    set answercache 4;
    (4 элемента кэша взято для примера).
    Запустить ядро СУБД ЛИНТЕР с ключом «/trace=decomp» для задания трассировки исполнения SQL-запросов.
    create or replace table test(id int, ch char(10));
    insert into test values(1,'a1');
    insert into test select id + 1,'a' + to_char(id + 1) from test;
    ! задаем кэширование результата запроса:
    select id, ch from test /* +ANSCACHE */;
    !код завершения 1037 – запрос не обновляемый:
    update test set id=-1 where current of cursor;
    !результат этого запроса берется из кэша результатов – см. файл 'lintrace.log':
    select id, ch from test /* +ANSCACHE */;
    !добавление новой записи приводит к очистке кэша результата запроса:
    insert into test;
    !результат выполнения этого запроса берется не из кэша – см. файл 'lintrace.log':
    select id, ch from test /* +ANSCACHE */;
    ! результат выполнения этого запроса берется уже из кэша – см. файл 'lintrace.log':
    select id, ch from test /* +ANSCACHE */;

Комментарии к трассировочному файлу.

Первый select-запрос c подсказкой ANSCACHE выполняет запрос и помещает результат запроса в кэш. Для выдачи результата запроса использует элемент этого кэша. Соответствующий вывод в файле «lintrace.log»:

C#2 QUERY:
  SELECT
    T_0."ID",
    T_0."CH"
  FROM
    < TABLE "SYSTEM"."TEST" AS T_0 >;
C#2 DECOMP.C (Start_Cur_Dec): Now computing derived set #0.
C#2 DECOMP.C (End_Dekart): Derived set #0 is computed, Rows count: 2.
C#2 FORMOTW.C (FORMOTW): The result of query has been taken from answer cache.
C#2 FORMOTW.C (FORMOTW): Read: 18 blocks, write: 33 blocks.
 Additional statistics for read blocks:
  converter 1,index 11,data 5,work 0,sorting 0,blob 0,other 1.
C#2 FORMOTW.C (FORMOTW): Read logical: 82 blocks, write logical: 65 blocks.
C#2 FORMOTW.C (FORMOTW): Journal read: 1 blocks, written: 17 blocks.
C#2 FORMOTW.C (FORMOTW): Time of query execution: 00:00:00:00.02

Второй select-запрос с подсказкой ANSCACHE уже не выполняет запрос, он использует результат из кэша:

C#2 QUERY:
  SELECT
    T_0."ID",
    T_0."CH"
  FROM
    < TABLE "SYSTEM"."TEST" AS T_0 >;
C#2 FORMOTW.C (FORMOTW): The result of query has been taken from answer cache.
C#2 FORMOTW.C (FORMOTW): Read: 18 blocks, write: 33 blocks.
 Additional statistics for read blocks:
  converter 1,index 11,data 5,work 0,sorting 0,blob 0,other 1.
C#2 FORMOTW.C (FORMOTW): Read logical: 84 blocks, write logical: 65 blocks.
C#2 FORMOTW.C (FORMOTW): Journal read: 1 blocks, written: 17 blocks.
C#2 FORMOTW.C (FORMOTW): Time of query execution: 00:00:00:00.00

После выполнения insert-запроса элемент кэша результатов запросов очищается. Последующий select-запрос c подсказкой ANSCACHE заново выполняет запрос и помещает результат запроса в кэш:

C#2 QUERY:
  SELECT
    T_0."ID",
    T_0."CH"
  FROM
    < TABLE "SYSTEM"."TEST" AS T_0 >;
C#2 DECOMP.C (Start_Cur_Dec): Now computing derived set #0.
C#2 DECOMP.C (End_Dekart): Derived set #0 is computed, Rows count: 3.
C#2 FORMOTW.C (FORMOTW): The result of query has been taken from answer cache.
C#2 FORMOTW.C (FORMOTW): Read: 18 blocks, write: 40 blocks.
 Additional statistics for read blocks:
  converter 1,index 11,data 5,work 0,sorting 0,blob 0,other 1.
C#2 FORMOTW.C (FORMOTW): Read logical: 104 blocks, write logical: 86 blocks.
C#2 FORMOTW.C (FORMOTW): Journal read: 1 blocks, written: 23 blocks.
C#2 FORMOTW.C (FORMOTW): Time of query execution: 00:00:00:00.00

Четвёртый (последний) select-запрос c подсказкой ANSCACHE не выполняет запрос, он использует результат из кэша:

C#2 QUERY:
  SELECT
    T_0."ID",
    T_0."CH"
  FROM
    < TABLE "SYSTEM"."TEST" AS T_0 >;
C#2 FORMOTW.C (FORMOTW): The result of query has been taken from answer cache.
C#2 FORMOTW.C (FORMOTW): Read: 18 blocks, write: 40 blocks.
 Additional statistics for read blocks:
  converter 1,index 11,data 5,work 0,sorting 0,blob 0,other 1.
C#2 FORMOTW.C (FORMOTW): Read logical: 106 blocks, write logical: 86 blocks.
C#2 FORMOTW.C (FORMOTW): Journal read: 1 blocks, written: 23 blocks.
C#2 FORMOTW.C (FORMOTW): Time of query execution: 00:00:00:00.00