#sql #oracle #query-performance
#sql #Oracle #запрос-производительность
Вопрос:
Я пытался повысить производительность моего запроса, который выполняется довольно долгое время. Я уже проверил план объяснения, и он выглядит нормально (два вложенных цикла, использование индекса), Можете ли вы найти какие-либо возможности улучшения? Может быть, некоторые из функций, которые я использую, не слишком быстры? Или, может быть, это просто проблема большого набора данных, и я мало что могу сделать? Спасибо за любой совет!
SELECT COUNT(*),
TRUNC(a_tab.some_date) ,
TO_CHAR(MIN(a_tab.some_date),'dd/MM/YYYY HH24:mm:ss') ,
TO_CHAR(MAX(a_tab.some_date),'dd/MM/YYYY HH24:mm:ss')
FROM TABLE_A a_tab
JOIN TABLE_B b_tab
ON a_tab.id = b_tab.a_tab_id
where b_tab.keyword_name = 'NAME_X'
AND b_tab.keyword_value = 'VALUE_X'
AND a_tab.some_date BETWEEN to_date('01/05/2014','dd/MM/YYYY') AND to_date('01/06/2014','dd/MM/YYYY')
AND extract (hour FROM a_tab.some_date) BETWEEN 0 AND 13
GROUP BY TRUNC(a_tab.some_date)
ORDER BY TRUNC(a_tab.some_date);
Комментарии:
1. Пожалуйста, поделитесь планом выполнения и некоторой ключевой информацией, такой как количество строк в table_a и table_b, и насколько избирательны предикаты. Кроме того, как долго это «довольно долго» и какую продолжительность вы считаете приемлемой?
2. table_a содержит 44371435 строк, а table_b — 88837780 и выполняется более часа (70 минут) с интервалом в один месяц
3. объясните план: tinypic.com/r/fnb635/8
4. Следующий шаг: насколько избирательным является каждый предикат. Итак, насколько выборочно «b_tab.keyword_name = ‘NAME_X'» и «b_tab.keyword_value = ‘VALUE_X'» и так далее.
Ответ №1:
Индекс мог бы помочь в этом запросе, но может быть трудно определить, какие именно, потому что вы фильтруете по обеим таблицам. Вот два варианта, которые можно попробовать:
table_b(keyword_name, keyword_value, a_tab_id)
table_a(some_date, id)
Сначала я бы попробовал тот, что включен table_b
.
Однако, учитывая размер объединяемых таблиц, возможно, что выполнение запроса может занять много времени. В одной таблице 44 миллиона строк, а в другой 88 миллионов. Если where
предложения не являются выборочными, то Oracle приходится обрабатывать много данных.
Ответ №2:
Попробуйте SELECT /* FULL(A_TAB) */ ...
определить, не является ли один из индексов неэффективным. Если это поможет, то, возможно, стоит разобраться, почему Oracle выбирает индекс вместо полного сканирования таблицы. Возможно, необходимо повторно собрать статистику или, возможно, параметру, такому как OPTIMIZER_INDEX_COST_ADJ, присвоено необычное значение, например, 1.
Индексы Btree полезны только при выборе небольшого процента строк. Каждое значение, полученное в результате сканирования диапазона индексов, требует обхода древовидной структуры данных по одному блоку за раз. Это идеально подходит для выбора небольшого объема данных. Для большого объема данных полное сканирование таблицы с помощью многоблочного ввода-вывода выполняется намного быстрее. Чтение данных за целый месяц может оказаться «слишком большим объемом» данных для индекса.
Индексы Btree также могут быть неэффективными в некоторых случаях, если коэффициент кластеризации индексов низкий. Oracle извлекает данные по одному блоку за раз, обычно это 8 КБ данных. Если данные физически хранятся в случайном порядке, то для выбора 1% строк может потребоваться чтение 100% блоков.
Индексы не всегда являются ответом, вот почему Oracle использует хэш-соединения.