Подвыбор (вместо числовой константы) ухудшает оптимизацию
Мой вопрос похож на Отбирать или не отбирать? но я хотел бы продолжать использовать два существующих представления (следовательно, я не хочу перемещать подвыбор непосредственно в логику представления).
Медленно (1,5 секунды)
SELECT h.n
FROM v_headers h
WHERE h.n >= (select 3000 from dual);
Запрос выполняется быстро при непосредственном использовании значения из подвыбора:
SELECT h.n
FROM v_headers h
WHERE h.n >= 3000;
Немного подробнее: n не уникально, имеет значения от 0 до 4000; для каждого n существует около 50 строк. 11 значений из разных строк поворачиваются в столбцы вдоль n.
Есть ли решение без извлечения выборок за представлениями (или изменения таблиц)? Может оптимизатор намекает?
Первый - медленный, второй - быстрый:
Л.Э.: Я упростил запросы.
Упрощенные запросы работают быстро благодаря @nop77svk. Более сложный запрос не (пока):
Быстро:
with xyz$ as (select 3986 as n from dual)
SELECT h.hw_number
FROM xyz$ X
JOIN v_headers h
ON h.hw_number >= x.n
Медленно (и все еще несколько упрощено):
with xyz$ as ((SELECT nvl(MAX(n), 0) AS n
FROM (SELECT h.hw_number AS n,
Rank() OVER(ORDER BY h.hw_number DESC) rnk
FROM x_data h
GROUP BY h.hw_number)
WHERE rnk = 50))
SELECT h.hw_number
FROM xyz$ X
JOIN v_headers h
ON h.hw_number >= x.n;
Немного подробнее о представлении v_headers:
WITH s AS
(
SELECT a.n,
b.col_name,
a.value,
b.col_id
FROM qa_data a
JOIN column_def b
ON b.col_id = a.col_id
WHERE b.master_dynamic_data = 'M' )
SELECT "n","c1","c2","c3","c4","c4","c5","c6","c7","c8","c9","c10"
FROM s PIVOT( Max(value)
keep(dense_rank first ORDER BY col_id) FOR col_name IN (
'c1' c1,
'c2' c2,
'c3' c3,
'c4' c4,
'c5' c5,
'c6' c6,
'c7' c7,
'c8' c8,
'c9' c9,
'c10' c10,
'c11' c11) )
column_def
- 72 ряда
- 57 строк с master_dynamic_data = 'M'
- column_def.col_id: уникальный 1..100 (с пробелами)
- column_def.col_name: c1, c2, c3,... (фактически 20 символов вместо 'cx')
qa_data:
- 450 тыс. Строк
- среднее количество строк для каждого qa_data.n составляет 112 строк. (n от 1 до 4000)
- средняя длина qa_data.value составляет 18 символов
1 ответ
В упрощенном варианте...
SELECT --+ leading(X) use_hash(H)
H.n
FROM (select 3000 as n from dual) X
JOIN v_headers H
ON H.n >= X.n
;
... >= 3000
Предикат правильно разрешен как предикат доступа, что приводит к срабатыванию индексов хранилища Exadata.
Однако в полной версии нужно принудительно распространять предикат на внутреннее представление, чего, похоже, не происходит. Быстрая проверка настройки теста показывает, что распространение такого предиката (для вычисленного значения, а не константного значения) в представление объединения выполняется в порядке, а распространение предиката в поворотное представление соединения - нет.
Тот же сценарий верен при использовании (детерминированной) функции, которая предварительно вычисляет значение n
вместо использования встроенного представления - предикат не переносится в представление с поворотным соединением (пробовал в 12.1.0.2).
Было бы интересно увидеть файл трассировки события 10053, чтобы понять, что происходит. (Домашнее задание для читателя.;-))