Зачем Oracle игнорировать «идеальный» индекс?
-
20-09-2019 - |
Вопрос
У меня есть эта таблица:
create table demo (
key number(10) not null,
type varchar2(3) not null,
state varchar2(16) not null,
... lots more columns ...
)
И этот индекс:
create index demo_x04 on demo(key, type, state);
Когда я запускаю этот запрос
select * from demo where key = 1 and type = '003' and state = 'NEW'
EXPLAIN PLAN
показывает, что он выполняет полное сканирование таблицы. Поэтому я уронил индекс и создал его снова. EXPLAIN PLAN
Все еще говорит полное сканирование стола. Как это может быть?
Некоторый фон: это исторические данные, так что это происходит, так это то, что я смотрю ряд с состоянием CLEARED
и вставьте новый ряд в состояние NEW
(плюс я копирую несколько значений из старой строки). Старый ряд затем обновляется до USED
. Анкет Так что стол всегда растет. Я заметил, что кардинальность индекса составляет 0 (несмотря на то, что у меня тысячи различных значений). После воссоздания кардинальность росла, но CBO не понравился индекс лучше.
На следующее утро Oracle внезапно понравилось индекс (вероятно, спал над ним) и начал использовать его, но не надолго. Через некоторое время обработка упала с 50 рядов до 3 рядов/с, и я снова увидел «полное сканирование таблицы». Что здесь происходит?
В моем случае мне нужно обработать около миллиона строк. Я совершаю изменения в партиях ок. 50. Есть ли какая -то команда, которую я должен запустить после обновления/повторного индекса или что -то в этом роде?
Я на Oracle 10G.
РЕДАКТИРОВАТЬ] У меня есть 969'491 отдельные ключи в этой таблице, 3 типа и 3 состояния.
Решение
Что произойдет, если вы указали подсказку индекса? Попробуй это:
SELECT /*+ INDEX (demo demo_x04) */ *
FROM demo
WHERE key = 1
AND type = '003'
AND state = 'NEW';
Похоже, что произошло в одночасье, так это то, что стол был проанализирован. Затем, когда вы запустили свою обработку против таблицы, было обновлено достаточное количество индекса, чтобы статистика таблицы Oracle снова стала устареть, и оптимизатор перестал использовать индекс.
Добавьте подсказку и посмотрите, дает ли Plan Exply Plan другой план, и запрос работает лучше.
О, и ответ Тони в отношении анализа таблицы является общей хорошей практикой, хотя с 10G база данных довольно хороша в выполнении самообслуживания в этом отношении. Если ваш процесс делает много обновлений, индекс может быстро стать устаревшим. Если запуск анализа, когда ваш процесс начинает идти в канаве на некоторое время улучшает ситуацию, вы бы знали, что это проблема.
Чтобы обновить статистику для таблицы, используйте dmbs_stats.gather_table_stats упаковка.
Например:
exec dbms_stats.gather_table_stats ('the владелец', 'demo');
Другие советы
Таблица была проанализирована недавно? Если Oracle считает, что это очень мало, это может даже не рассмотреть возможность использования индекса.
Попробуй это:
select last_analyzed, num_rows
from user_tables
where table_name = 'DEMO';
Num_rows сообщает вам, сколько рядов думает, что Oracle считает, что таблица содержит.
«На следующее утро Oracle внезапно понравилось индекс (вероятно, спал над ним)», вероятно, DBMS_STATS работает в течение ночи.
Как правило, я бы видел одну из трех причин для полного сканирования таблицы по индексу. Во -первых, оптимизатор считает, что стол пуст или, по крайней мере, очень маленький. Я подозреваю, что это была первоначальная проблема. В этом случае было бы быстрее полным сканированием таблицы, состоящей только из нескольких блоков, а не использовать индекс.
Второе - когда запрос такой, что индекс не может быть практически использован.
"select * from demo where key = 1 and type = '003' and state = 'NEW'"
Вы на самом деле используете литералы, жестко кодируемые в запросе. Если нет, то ваши переменные данные дата могут быть неверными (например, ключ - это символ). Это потребовало бы преобразования цифрового ключа в символ для сравнения, что сделало бы индекс почти бесполезным.
Третья причина - это то, где он думает, что запрос будет обрабатывать большую часть рядов в таблице. Тип и состояние кажутся довольно низкой кардинальностью. Возможно, у вас есть большое количество конкретного значения «ключа»?
Комментарий к обработке, которую вы описываете: звучит так, как будто вы делаете обработку с рядовыми рядами с прерывистыми коммитами, и я бы призвал вас переосмыслить это, если сможете. Механизм обновления/вставки вполне может быть преобразован в оператор MERGE, и весь набор данных может быть обработан в одном операторе с одним коммитом в конце. Это почти наверняка будет быстрее и использовать меньше ресурсов, чем ваш текущий метод.
Всегда ли значение ключа столбца 1? Если это так, я не уверен, что консалтинг индекса оптимизирует запрос, так как каждая строка должна быть рассмотрена в любом случае. Если так, объявите индекс без столбца ключа. Вы также можете попробовать:
select key, type, state from demo where key = 1 and type = '003' and state = 'NEW'
Что (если я предполагаю правильное), все равно нужно смотреть на каждую строку, но которая может перейти к индексу, поскольку все столбцы в наборе результатов теперь покрываются.
Я просто угадываю на основе вашего утверждения, что индекс показывает кардинальность 0.