Единственный способ, которым я могу думать, чтобы получить такую разницу в скорости исполнения будет (а) иметь индекс на field4
, и (б) имею много пустых блоки данных; возможно, с высокой отметки воды, установленной очень высоко при повторных нагрузках прямого пути.
Первый запрос будет по-прежнему использовать индекс и выполнять так, как ожидалось. Но поскольку нулевые значения не индексируются, индекс не может использоваться для проверки состояния or field4 is null
, поэтому он вернется к полному сканированию таблицы.
Это само по себе не должно быть проблемой здесь, поскольку полное сканирование таблицы из 7000 строк не должно занять много времени. Но так как это так долго, что-то еще происходит. Полное сканирование таблицы должно проверять каждый блок данных, выделенный для таблицы, чтобы увидеть, содержат ли они какие-либо строки, и время, которое он принимает, предполагает, что существует намного больше блоков, чем вам нужно иметь 7000 строк, даже с встроенным хранилищем CLOB.
Самый простой способ получить много пустых блоков данных - это иметь много данных, а затем удалить большую часть его. Но я считаю, что вы сказали в недавно удаленном комментарии к более раннему вопросу о том, что производительность была в порядке и ухудшилась. Это может произойти, если вы делаете direct-path inserts, особенно если вы обновляете данные, удалив их, а затем вставляя новые данные в режим прямого пути. Вы можете сделать это со вставками, которые содержат подсказку /*+ append */
; или параллельно; или через SQL * Loader. Каждый раз, когда вы делали это, знак высокой воды двигался, поскольку старые пустые блоки не могли быть повторно использованы; и каждый раз производительность запроса, который проверяет нулевые значения, немного ухудшится. После много итераций, которые действительно начнут складываться.
Вы можете проверить словарь данных, чтобы узнать, сколько места выделено вашей таблице (user_segments
и т. Д.) И сравнить это с размером данных, которые вы на самом деле имеете. Вы можете сбросить HWM, восстановив таблицу, например.г, выполнив: (! предпочтительно в окне обслуживания)
alter table mytable move;
В демке я провел цикл прямого пути вставки и удаления 7000 строк более ста раз, а затем побежал как ваши запросы , Первое заняло 0,06 секунды (большая часть из которых - служебные данные SQL Devleoper); второе заняло 1.260. (Я также управлял Гордоном, который получил аналогичное время, поскольку он все еще должен делать FTS). С большим количеством итераций разница станет еще более заметной, но у меня закончилось пространство ... Затем я сделал alter table move
и повторно выполнил второй запрос, который затем занял 0,05 секунды.
Есть ли в первом запросе полное сканирование таблицы или есть индекс в поле4, который он может использовать? И если есть, была ли таблица неоднократно удалена (не усечена) и повторно заполнена вставками прямого пути (то есть с подсказкой '/ * + append * /')? –
Как насчет плана для первого запроса? – nilsman
Условие 'IS NULL' будет игнорировать индекс, поскольку вы не можете индексировать значения NULL. Хорошо, что вы, конечно, могли бы обмануть оптимизатор, установив постоянное значение вместе с столбцом NULLABLE при индексировании. Но, чтобы ответить в рамках вашего вопроса, ваш второй запрос пойдет за ** FULL TABLE SCAN **, если вы не обманете оптимизатора, как я сказал ранее. Ваш первый запрос может использовать индексы и избегать FTS. 1. Пожалуйста, опубликуйте план объяснения для первого запроса. 2. Обновлена ли статистика? –