Как заставить оракул использовать сканирование диапазона индекса?
У меня есть серия чрезвычайно похожих запросов, которые я выполняю против таблицы в 1,4 миллиарда записей (с индексами), единственная проблема заключается в том, что по меньшей мере 10% этих запросов занимают > 100 раз больше времени для выполнения, чем другие.
Я запустил план объяснений и заметил, что для быстрых запросов (примерно 90%) Oracle использует сканирование диапазона индексов; на медленных, используя полное сканирование индекса.
Есть ли способ заставить Oracle делать сканирование диапазона индекса?
Ответы
Ответ 1
Я предлагаю следующий подход: -
- Получить план объяснения медленного оператора
- Используя подсказку INDEX, получите план объяснения использования индекса
Вы заметите, что стоимость плана INDEX больше. Вот почему Oracle не выбирает индексный план. Стоимость - оценка Oracle, основанная на статистике и различных допущениях.
Если расчетная стоимость плана больше, но на самом деле выполняется быстрее, оценка неверна. Ваша задача - выяснить, почему оценка неверна и правильно. Затем Oracle выберет правильный план для этого утверждения и другие на нем.
Чтобы понять, почему это неправильно, посмотрите количество ожидаемых строк в плане. Вы, вероятно, найдете один из них на порядок. Это может быть связано с неравномерно распределенными значениями столбцов, старой статистикой, столбцами, которые взаимосвязаны друг с другом и т.д.
Чтобы решить эту проблему, вы можете заставить Oracle собирать лучшую статистику и намекать на нее с лучшими исходными предположениями. Затем он оценит точные затраты и придумает самый быстрый план.
Если вы разместите дополнительную информацию, я могу прокомментировать дальше.
Ответ 2
Чтобы "заставить" Oracle использовать сканирование диапазона индекса, просто используйте подсказку оптимизатора INDEX_RS_ASC
. Например:
CREATE TABLE mytable (a NUMBER NOT NULL, b NUMBER NOT NULL, c CHAR(10)) NOLOGGING;
INSERT /*+ APPEND */ INTO mytable(a,b,c)
SELECT level, mod(level,100)+1, 'a' FROM dual CONNECT BY level <= 1E6;
CREATE INDEX myindex_ba ON mytable(b, a);
EXECUTE dbms_stats.gather_table_stats(NULL,'mytable');
SELECT /*+ FULL(m) */ b FROM mytable m WHERE b=10; -- full table scan
SELECT /*+ INDEX_RS_ASC(m) */ b FROM mytable m WHERE b=10; -- index range scan
SELECT /*+ INDEX_FFS(m) */ b FROM mytable m WHERE b=10; -- index fast full scan
Будет ли это делать ваш запрос на самом деле быстрее, зависит от многих факторов, таких как селективность индексированного значения или физический порядок строк в вашей таблице. Например, если вы измените запрос на WHERE b BETWEEN 10 AND <xxx>
, в планах выполнения моей машины появятся следующие затраты:
b BETWEEN 10 AND 10 20 40 80
FULL 749 750 751 752
INDEX_RS_ASC 29 325 865 1943
INDEX_FFS 597 598 599 601
Если вы немного измените запрос, чтобы не только выбрать индексированный столбец b
, но и другие столбцы без индекса, затраты резко меняются:
b BETWEEN 10 AND 10 20 40 80
FULL 749 750 751 754
INDEX_RS_ASC 3352 40540 108215 243563
INDEX_FFS 3352 40540 108215 243563
Ответ 3
Если вы хотите знать, почему оптимизатор принимает решения, вам нужно использовать трассировку 10053.
SQL> alter session set events '10053 trace name context forever, level 1';
Затем запустите объяснение планов быстрого запроса запроса и примерного медленного запроса. В каталоге дампа пользователя вы получите файлы трассировки с подробным описанием деревьев решений, которые проходят CBO. Где-то в этих файлах вы найдете причины, по которым он выбирает полный индексный сканирование по сканированию диапазона индексов.
Я не говорю, что файлы трассировки легко читаются. Лучшим ресурсом для их понимания является Вольфганг Брейтлинг, отличный документ "Взгляд под капотом CBO" (PDF)
Ответ 4
вы можете использовать подсказки oracle sql. вы можете заставить использовать определенный индекс или исключить индекс
проверьте документацию
http://psoug.org/reference/hints.html
http://www.adp-gmbh.ch/ora/sql/hints/index.html
как
выберите /* + index (scott.emp ix_emp) */из scott.emp emp_alias
Ответ 5
Я видел, что подсказка игнорируется Oracle.
В последнее время наш DBA использует "optimizer_index_cost_adj", и он использовал индекс.
Это параметр Oracle, но вы можете использовать его как уровень сеанса.
100 - значение по умолчанию, и мы использовали параметр 10.