Оптимизация производительности SQL-запросов (TimesTen)

Мне нужна помощь с оптимизацией запросов TimesTen DB. Я сделал некоторые измерения с помощью профилировщика Java и нашел раздел кода, который занимает большую часть времени (этот раздел кода выполняет запрос SQL). Что странно, этот запрос становится дорогим только для каких-то конкретных входных данных.

Вот пример. У нас есть две таблицы, которые мы запрашиваем, одна представляет объекты, которые мы хотим получить (T_PROFILEGROUP), другая представляет ссылку многие-ко-многим из какой-то другой таблицы (T_PROFILECONTEXT_PROFILEGROUPS). Мы не запрашиваем связанную таблицу.

Это запросы, которые я выполнил с запущенным профилировщиком БД (они одинаковы, за исключением идентификатора):

Command> select G.M_ID from T_PROFILECONTEXT_PROFILEGROUPS CG, T_PROFILEGROUP G where CG.M_ID_EID = G.M_ID and CG.M_ID_OID = 1464837998949302272;
< 1169655247309537280 >
< 1169655249792565248 >
< 1464837997699399681 >
3 rows found.

Command> select G.M_ID from T_PROFILECONTEXT_PROFILEGROUPS CG, T_PROFILEGROUP G where CG.M_ID_EID = G.M_ID and CG.M_ID_OID = 1466585677823868928;
< 1169655247309537280 >
1 row found.

Вот что у меня есть в профилировщике:

12:14:31.147       1 SQL      2L    6C  10825P Preparing: select G.M_ID from T_PROFILECONTEXT_PROFILEGROUPS CG, T_PROFILEGROUP G where CG.M_ID_EID = G.M_ID and CG.M_ID_OID = 1464837998949302272
12:14:31.147       2 SQL      4L    6C  10825P sbSqlCmdCompile ()(E): (Found already compiled version: refCount:01, bucket:47) cmdType:100, cmdNum:1146695.
12:14:31.147       3 SQL      4L    6C  10825P Opening: select G.M_ID from T_PROFILECONTEXT_PROFILEGROUPS CG, T_PROFILEGROUP G where CG.M_ID_EID = G.M_ID and CG.M_ID_OID = 1464837998949302272;
12:14:31.147       4 SQL      4L    6C  10825P Fetching: select G.M_ID from T_PROFILECONTEXT_PROFILEGROUPS CG, T_PROFILEGROUP G where CG.M_ID_EID = G.M_ID and CG.M_ID_OID = 1464837998949302272;
12:14:31.148       5 SQL      4L    6C  10825P Fetching: select G.M_ID from T_PROFILECONTEXT_PROFILEGROUPS CG, T_PROFILEGROUP G where CG.M_ID_EID = G.M_ID and CG.M_ID_OID = 1464837998949302272;
12:14:31.148       6 SQL      4L    6C  10825P Fetching: select G.M_ID from T_PROFILECONTEXT_PROFILEGROUPS CG, T_PROFILEGROUP G where CG.M_ID_EID = G.M_ID and CG.M_ID_OID = 1464837998949302272;
12:14:31.228       7 SQL      4L    6C  10825P Fetching: select G.M_ID from T_PROFILECONTEXT_PROFILEGROUPS CG, T_PROFILEGROUP G where CG.M_ID_EID = G.M_ID and CG.M_ID_OID = 1464837998949302272;
12:14:31.228       8 SQL      4L    6C  10825P Closing: select G.M_ID from T_PROFILECONTEXT_PROFILEGROUPS CG, T_PROFILEGROUP G where CG.M_ID_EID = G.M_ID and CG.M_ID_OID = 1464837998949302272;
12:14:35.243       9 SQL      2L    6C  10825P Preparing: select G.M_ID from T_PROFILECONTEXT_PROFILEGROUPS CG, T_PROFILEGROUP G where CG.M_ID_EID = G.M_ID and CG.M_ID_OID = 1466585677823868928
12:14:35.243      10 SQL      4L    6C  10825P sbSqlCmdCompile ()(E): (Found already compiled version: refCount:01, bucket:44) cmdType:100, cmdNum:1146697.
12:14:35.243      11 SQL      4L    6C  10825P Opening: select G.M_ID from T_PROFILECONTEXT_PROFILEGROUPS CG, T_PROFILEGROUP G where CG.M_ID_EID = G.M_ID and CG.M_ID_OID = 1466585677823868928;
12:14:35.243      12 SQL      4L    6C  10825P Fetching: select G.M_ID from T_PROFILECONTEXT_PROFILEGROUPS CG, T_PROFILEGROUP G where CG.M_ID_EID = G.M_ID and CG.M_ID_OID = 1466585677823868928;
12:14:35.243      13 SQL      4L    6C  10825P Fetching: select G.M_ID from T_PROFILECONTEXT_PROFILEGROUPS CG, T_PROFILEGROUP G where CG.M_ID_EID = G.M_ID and CG.M_ID_OID = 1466585677823868928;
12:14:35.243      14 SQL      4L    6C  10825P Closing: select G.M_ID from T_PROFILECONTEXT_PROFILEGROUPS CG, T_PROFILEGROUP G where CG.M_ID_EID = G.M_ID and CG.M_ID_OID = 1466585677823868928;

Понятно, что первый запрос занял почти 100 мс, а второй выполнился мгновенно. Дело не в прекомпиляции запросов (первый тоже прекомпилируется, так как такие же запросы были и раньше). У нас есть индексы БД для всех используемых здесь столбцов: T_PROFILEGROUP.M_ID, T_PROFILECONTEXT_PROFILEGROUPS.M_ID_OID и T_PROFILECONTEXT_PROFILEGROUPS.M_ID_EID.

Мои вопросы:

  • Почему запросы к одному и тому же набору таблиц дают такую ​​разную производительность для разных параметров?
  • Какие индексы здесь задействованы?
  • Есть ли способ улучшить этот простой запрос и/или БД, чтобы сделать его быстрее?

ОБНОВЛЕНИЕ: чтобы создать ощущение размера:

Command> select count(*) from T_PROFILEGROUP;
< 183840 >
1 row found.

Command> select count(*) from T_PROFILECONTEXT_PROFILEGROUPS;
< 2279104 >
1 row found.

person Sergey Mikhanov    schedule 01.06.2010    source источник


Ответы (3)


Я не знаком с TimesTen, но предполагаю, что он работает как другие реляционные БД (за исключением того, что он находится в памяти), одной из возможных причин является либо отсутствие индекса в столбцах T_PROFILECONTEXT_PROFILEGROUP.M_ID_OID или T_PROFILEGROUP.M_ID, либо несбалансированный индекс двоичного дерева. .

Без индекса результаты будут зависеть от порядка данных относительно того, насколько быстро он их найдет.

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

Я не могу честно сказать, применимо ли это к TimesTen, потому что я никогда не использовал его, и мои поиски в Интернете не дают много информации.

person Alan Macdonald    schedule 30.11.2011

Я не очень хорошо знаком с базой данных TimesTen, но, поскольку здесь она составляет менее 1/10 секунды, может ли это быть просто разница округления в двух запросах или какая-то икота?

Вот ссылка, в которой рассматриваются некоторые методы настройки производительности базы данных TimesTen. В нем есть некоторая общая информация (использование подготовки и т. д.), а также информация о настройке конкретных запросов. Я надеюсь, что это помогает.

person Tom H    schedule 01.06.2010
comment
Конечно нет. Я профилировал код Java, который выполняет этот запрос тысячи раз, и он явно становится узким местом производительности ТОЛЬКО для идентификаторов, которые приводят к нескольким строкам, возвращаемым этим соединением. - person Sergey Mikhanov; 01.06.2010

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

Можете ли вы выполнить это с тремя (или десятью?) запросами и отчитаться?

person Dean J    schedule 26.08.2010