Подводя итог: ваш запрос работает с полным набором МЕР. Он соответствует времени каждой записи MEASURES для записи INTERVALS. Если время, время, затраченное на INTERVALS, примерно похоже на окно, натянутое на MEASURES, тогда ваш запрос также работает против полного набора INTERVALS, в противном случае он работает с подмножеством.
Почему это важно, потому что это уменьшает возможности для настройки, поскольку полное сканирование таблицы, вероятно, является самым быстрым способом получения всех строк. Таким образом, если ваши реальные таблицы MEASURES или INTERVALS не содержат гораздо больше столбцов, чем вы даете нам, маловероятно, что любые индексы дадут много преимуществ.
Возможные стратегии не являются:
- нет индексов на всех
- индекса МЕР (TIME, МЕРА)
- индекса МЕР (TIME)
- не индекс МЕР
- индекс на INTERVALS (ENTRY_TIME, EXIT_TIME)
- индекс на INTERVALS (ENTRY_TIME)
- нет индекса на отрезках
- параллельный запрос
Я не собираюсь представить тестовые случаи для всех перестановок, потому что результаты в значительной степени, как можно было бы ожидать.
Вот данные испытаний. Как видите, я использую несколько большие наборы данных. Окно INTERVALS больше, чем окна MEASURES, но не намного. Интервалы составляют 10000 секунд в ширину, и меры принимаются каждые 15 секунд.
SQL> select min(entry_time), max(exit_time), count(*) from intervals;
MIN(ENTRY MAX(EXIT_ COUNT(*)
--------- --------- ----------
01-JAN-09 20-AUG-09 2001
SQL> select min(ts), max(ts), count(*) from measures;
MIN(TS) MAX(TS) COUNT(*)
--------- --------- ----------
02-JAN-09 17-JUN-09 1200001
SQL>
NB В моих тестовых данных я предположил, что ИНТЕРВАЛ запись не перекрывается. Это имеет важное значение: запись MEASURES объединяется только с одним INTERVAL.
Benchmark
Вот тест без каких-либо индексов.
SQL> exec dbms_stats.gather_table_stats(user, 'MEASURES', cascade=>true)
PL/SQL procedure successfully completed.
SQL> exec dbms_stats.gather_table_stats(user, 'INTERVALS', cascade=>true)
PL/SQL procedure successfully completed.
SQL> set timing on
SQL>
SQL> select m.measure
2 , m.ts as "TIME"
3 , i.entry_time
4 , i.exit_time
5 from
6 intervals i
7 inner join
8 measures m
9 on (m.ts between i.entry_time and i.exit_time)
10 order by m.ts asc
11/
1200001 rows selected.
Elapsed: 00:05:37.03
SQL>
МЕРЫ тестирует
Теперь давайте создадим уникальный индекс на отрезках (ENTRY_TIME, EXIT_TIME) и опробовать различные стратегии индексирования для МЕР. Сначала введите только индекс MEASURES TIME.
SQL> create index meas_idx on measures (ts)
2/
Index created.
SQL> exec dbms_stats.gather_table_stats(user, 'MEASURES', cascade=>true)
PL/SQL procedure successfully completed.
SQL>
SQL> set autotrace traceonly exp
SQL>
SQL> set timing on
SQL>
SQL> select m.measure
2 , m.ts as "TIME"
3 , i.entry_time
4 , i.exit_time
5 from
6 intervals i
7 inner join
8 measures m
9 on (m.ts between i.entry_time and i.exit_time)
10 order by m.ts asc
11/
1200001 rows selected.
Elapsed: 00:05:20.21
SQL>
Теперь давайте индекс MEASURES.TIME и МЕРА Колонны
SQL> drop index meas_idx
2/
Index dropped.
SQL> create index meas_idx on measures (ts, measure)
2/
Index created.
SQL> exec dbms_stats.gather_table_stats(user, 'MEASURES', cascade=>true)
PL/SQL procedure successfully completed.
SQL> select m.measure
2 , m.ts as "TIME"
3 , i.entry_time
4 , i.exit_time
5 from
6 intervals i
7 inner join
8 measures m
9 on (m.ts between i.entry_time and i.exit_time)
10 order by m.ts asc
11/
1200001 rows selected.
Elapsed: 00:05:28.54
SQL>
Теперь без индекса на МЕР (но по-прежнему показатель на отрезках)
SQL> drop index meas_idx
2/
Index dropped.
SQL> exec dbms_stats.gather_table_stats(user, 'MEASURES', cascade=>true)
PL/SQL procedure successfully completed.
SQL> select m.measure
2 , m.ts as "TIME"
3 , i.entry_time
4 , i.exit_time
5 from
6 intervals i
7 inner join
8 measures m
9 on (m.ts between i.entry_time and i.exit_time)
10 order by m.ts asc
11/
1200001 rows selected.
Elapsed: 00:05:24.81
SQL>
Так какая разница сделать параллельный запрос?
SQL> select /*+ parallel (4) */
2 m.measure
3 , m.ts as "TIME"
4 , i.entry_time
5 , i.exit_time
6 from
7 intervals i
8 inner join
9 measures m
10 on (m.ts between i.entry_time and i.exit_time)
11 order by m.ts asc
12/
1200001 rows selected.
Elapsed: 00:02:33.82
SQL>
МЕРЫ Заключение
Не большая разница в истекшего времени для различных показателей. Я был немного удивлен тем, что построение индекса MEASURES (TS, MEASURE) привело к полному сканированию таблицы и несколько более медленному времени выполнения. С другой стороны, неудивительно, что работа в параллельном запросе намного быстрее. Поэтому, если у вас есть Enterprise Edition, и у вас есть запасные части для процессоров, использование PQ, безусловно, сократит время, затраченное на то, что оно не изменит стоимость ресурсов (и фактически делает более лот).
INTERVALS тесты
Так что разница может различные индексы на отрезках сделать? В следующих тестах мы сохраним индекс для MEASURES (TS). Прежде всего, мы поместим первичный ключ на оба столбца INTERVALS и заменим его только ограничением на INTERVALS (ENTRY_TIME).
SQL> alter table intervals drop constraint ivl_pk drop index
2/
Table altered.
SQL> alter table intervals add constraint ivl_pk primary key (entry_time) using index
2/
Table altered.
SQL> exec dbms_stats.gather_table_stats(user, 'INTERVALS', cascade=>true)
PL/SQL procedure successfully completed.
SQL> select m.measure
2 , m.ts as "TIME"
3 , i.entry_time
4 , i.exit_time
5 from
6 intervals i
7 inner join
8 measures m
9 on (m.ts between i.entry_time and i.exit_time)
10 order by m.ts asc
11/
1200001 rows selected.
Elapsed: 00:05:38.39
SQL>
Наконец без индекса на отрезках при всех
SQL> alter table intervals drop constraint ivl_pk drop index
2/
Table altered.
SQL> exec dbms_stats.gather_table_stats(user, 'INTERVALS', cascade=>true)
PL/SQL procedure successfully completed.
SQL> select m.measure
2 , m.ts as "TIME"
3 , i.entry_time
4 , i.exit_time
5 from
6 intervals i
7 inner join
8 measures m
9 on (m.ts between i.entry_time and i.exit_time)
10 order by m.ts asc
11/
1200001 rows selected.
Elapsed: 00:05:29.15
SQL>
ИНТЕРВАЛОВ заключение
Индекс на отрезках делает небольшую разницу. То есть индексирование (ENTRY_TIME, EXIT_TIME) приводит к более быстрому выполнению. Это связано с тем, что он обеспечивает быстрое сканирование полного индекса, а не полное сканирование таблицы. Это было бы более значительным, если бы временное окно, обозначенное INTERVALS, было значительно шире, чем временное окно MEASURES.
Общие выводы
Поскольку мы делаем полную таблицу запросов ни один из индексов существенно не изменилось время выполнения. Поэтому, если у вас есть Enterprise Edition и несколько процессоров, Parallel Query даст вам наилучшие результаты. В противном случае самыми лучшими индексами будут INTERVALS (ENTRY_TIME, EXIT_TIME) и MEASURES (TS). Решение вложенных циклов определенно быстрее, чем параллельный запрос - см. Редактировать 4 ниже.
Если вы работаете против подмножества МЕР (скажем, ценность недели), то наличие индексов будет иметь большее влияние, это, вероятно, что два я рекомендовал в предыдущем пункте, остаются наиболее эффективными,
Последнее наблюдение: я использовал это на стандартном двухъядерном ноутбуке для болота с SGA всего 512 МБ. Но все мои запросы заняли менее шести минут. Если ваш запрос действительно занимает час, то в вашей базе данных есть серьезные проблемы. Хотя это долгое время может быть артефактом перекрывающихся INTERVALS, что может привести к декартовому продукту.
** Редактировать **
Первоначально я включил выход из
SQL> set autotrace traceonly stat exp
Но увы SO сильно усеченный мой пост. Поэтому я переписал его, но без исполнения или статистики. Те, кто хочет подтвердить мои выводы, должны будут запускать запросы к ним.
Edit 4 (предыдущий редактировать вынимается по причинам пространства)
На третьей попытке я был в состоянии воспроизвести дэ улучшение производительности для решения Quassnoi в.
SQL> set autotrace traceonly stat exp
SQL>
SQL> set timing on
SQL>
SQL> select
2 /*+ LEADING (i) USE_NL(i, m) */
3 m.measure
4 , m.ts as "TIME"
5 , i.entry_time
6 , i.exit_time
7 from
8 intervals i
9 inner join
10 measures m
11 on (m.ts between i.entry_time and i.exit_time)
12 order by m.ts asc
13/
1200001 rows selected.
Elapsed: 00:00:18.39
Execution Plan
----------------------------------------------------------
Plan hash value: 974071908
---------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time |
---------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 6003K| 257M| | 973K (1)| 03:14:46 |
| 1 | SORT ORDER BY | | 6003K| 257M| 646M| 973K (1)| 03:14:46 |
| 2 | NESTED LOOPS | | | | | | |
| 3 | NESTED LOOPS | | 6003K| 257M| | 905K (1)| 03:01:06 |
| 4 | TABLE ACCESS FULL | INTERVALS | 2001 | 32016 | | 2739 (1)| 00:00:33 |
|* 5 | INDEX RANGE SCAN | MEAS_IDX | 60000 | | | 161 (1)| 00:00:02 |
| 6 | TABLE ACCESS BY INDEX ROWID| MEASURES | 3000 | 87000 | | 451 (1)| 00:00:06 |
---------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
5 - access("M"."TS">="I"."ENTRY_TIME" AND "M"."TS"<="I"."EXIT_TIME")
Statistics
----------------------------------------------------------
66 recursive calls
2 db block gets
21743 consistent gets
18175 physical reads
0 redo size
52171689 bytes sent via SQL*Net to client
880416 bytes received via SQL*Net from client
80002 SQL*Net roundtrips to/from client
0 sorts (memory)
1 sorts (disk)
1200001 rows processed
SQL>
Так что вложенные петли - это, безусловно, путь.
Полезные уроки упражнения
- Запуск диагностических тестов является гораздо более ценны, чем гадать и теоретизирования
- Понимание данных имеет решающее значение
- Даже с 11g мы еще soemtimes необходимость использовать подсказки для создания оптимизатора в некоторых случаях
Являются ли столбцы, на которые вы ссылаетесь, индексируются? вы также должны запустить свой запрос в анализаторе запросов для своей системы баз данных и опубликовать вывод здесь. – nos
hi marc_s: oracle 10.2.0.3 nos: да, это индексировано, я попытаюсь сделать это, тогда omg ponies: я собираюсь взглянуть на него – user235693
Проходят ли интервалы? – Quassnoi