[closed]

kill-still

Есть такой запрос:

SELECT *
FROM (
SELECT a1, a2, a3 .. a30, b, MAX(b) OVER(PARTITION BY p1, p2 .. p14 ORDER BY p15) AS bM
FROM t1, t2, t3
WHERE усл1
and усл2
and усл3
)m
WHERE
m.b = m.bM

Первый рекорд он одаёт через 1.5 минуты. и дальше ноностопом очень быстро их выплёвывает.
Такой же запрос отдаёт первый отклик очень быстро (что в принципе логично):

SELECT a1, a2, a3 .. a30, b, MAX(b) OVER(PARTITION BY p1, p2 .. p14 ORDER BY p15) AS bM
FROM t1, t2, t3
WHERE усл1
and усл2
and усл3

Есть необходимость ускорить выдачу первого отклика.
Общее время выполнения запроса в результате преобразования может вырасти в пределах разумного.

uncle17

а индексы обозначать пушкен будет? Ну и where тоже

dava

ну ты первым запросом всегда фактически фуллскан заставляешь делать - ищешь же максимум по всем партициям фактически
если для любого b выдача будет заведомо непустая, то можно пойти на изменение логики: сделать индекс по b, искать по нему и лишь затем применять оконную функцию, но если есть случаи, когда для b может быть ничего не найдено в первом запросе, то результат у исходного запроса и у переписанного будет отличаться
короче, без изменения логики быстро первую запись не получить, ну а без знания того, какие данные хранятся и как они вносятся - логику не переписать без ущерба

dava

хотя можно сделать вот как:
1. индекс по b
2. индекс по полям в partition by
3. добавляем в запрос условие not exist'ом, что для найденного b в указанных условиях партиции нет члена большего, чем b.
4. ограничиваем по rownum (или делаем top 1)
5. возможно придётся принудительно указать хинт, чтобы джойн шёл не хешом, а через nested loops
тогда получится то же самое в любом случае
p.s. в этом случае понадобится формально два прохода таблицы, но так как по индексам, то пох

kill-still

1 2 все индексы есть
3 не совсем понял о чём ты, но уже не актуально - переделали запрос на без окна
4 там и так /*+ FIRST_ROWS */ стоит
5 хз что с этим запросом надо сделать, чтобы там хэшджойн был.
И вопрос был совсеееем не по оптимизации, если ты заметишь. В общем как обычно на фл, заходим в тему, придумываем сами себе вопрос и отвечаем на него, не важно, что было в начале топика.

dava

жаль, что ты нихуя не понял, но рад, что всё получилось

Andbar

4 там и так /*+ FIRST_ROWS */ стоит
это хинт, но в данном случае от него мало пользы...
У меня на работе запросов, требующих получения записей по максимуму/минимуму значения море (правда, в большинстве случаев, такое значение одно) и почти всегда используется форма
select ...
from tbl t
where .....
and tbl.field1 = (select max(field1) from tbl where ....)

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

dava

Ну на самом деле та конструкция, которую ты привёл в общем случае будет медленнее аналитической функции за счёт двух проходов таблицы. При наличии покрывающего индекса, у которого вставлено desc по полю с максимумом - быстрее будет, да, но так можно и аналитическую подогнать, а использований таблицы/индекса в случае аналитической будет меньше.
Ну а что кротишка first_rows приводит - так это от незнания того факта, что у оракла есть только два подхода: rule и all_rows, а хинты choose и first_rows просто заставляют выбирать наиболее подходящий режим.

mbolik1

у оракла есть только два подхода: rule и all_rows, а хинты choose и first_rows просто заставляют выбирать наиболее подходящий режим.
Что-то ты странное говоришь.

ALL_ROWS
The optimizer uses a cost-based approach for all SQL statements in the session regardless of the presence of statistics and optimizes with a goal of best throughput (minimum resource use to complete the entire statement). This is the default value.
FIRST_ROWS_n
The optimizer uses a cost-based approach, regardless of the presence of statistics, and optimizes with a goal of best response time to return the first n number of rows, where n equals 1, 10, 100, or 1000.
FIRST_ROWS
The optimizer uses a mix of cost and heuristics to find a best plan for fast delivery of the first few rows.
Note that using heuristics sometimes leads the optimizer to generate a plan with a cost that is significantly larger than the cost of a plan without applying the heuristic. FIRST_ROWS is available for backward compatibility and plan stability; use FIRST_ROWS_n instead.

ppp6663669

WHERE усл1 and усл2 and усл3
у тебя тут только условия соединения, или же есть какие-либо условия ограничения на отдельные таблицы, типа where a.сиськи = 3 или там a.prodate > 8.03.2012?

dava

Я могу ошибаться в деталях, но суть в том, что хинты - это не отдельные режимы работы оптимизатора. Можно либо применять cost-based подход, либо использовать rule-based подход, либо комбинировать их. В данной конкретной задаче предельно ясно как придётся работать с партициями, и на каких множествах осуществлять поиск, чтобы это заняло наименьшее время. Вся задача - это заставить оптимизатор отработать по той схеме, которую для него придумаешь.
На этой фразе, кстати, я обнаружил недостаток собственных знаний:
cost-based approach, regardless of the presence of statistics
в моём представлении такое возможно при использовании разве что DYNAMIC_SAMPLING:
The DYNAMIC_SAMPLING hint lets you control dynamic sampling to improve server performance by determining more accurate predicate selectivity and statistics for tables and indexes. You can set the value of DYNAMIC_SAMPLING to a value from 0 to 10. The higher the level, the more effort the compiler puts into dynamic sampling and the more broadly it is applied. Sampling defaults to cursor level unless you specify a table.
но так как в описании этого явно не указано, то хз.
Оставить комментарий
Имя или ник:
Комментарий: