Настройка производительности PL / SQL для LIKE "% ...%" запросов с подстановочными знаками - PullRequest
15 голосов
/ 03 июня 2011

Мы используем базу данных Oracle 11g.
Как вы можете знать, а может и не знать, если вы используете подстановочный запрос с «%» перед строкой, индекс столбца не используется и происходит полное сканирование таблицы 1005 *.

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

SELECT * 
  FROM myTable 
 WHERE UPPER(CustomerName) like '%ABC%' 
    OR UPPER(IndemnifierOneName) like '%ABC%' 
    OR UPPER(IndemnifierTwoName) like '%ABC%';

... где все 3 столбца имеют тип varchar2 (100) и ABC - значение переменного входного параметра.

@ Все предлагают индекс CONTEX , обратите внимание, что мои данные обновляются в любое время суток каждый день, и этот индекс требует повторной синхронизации, поэтому не хороший вариант для таблица 1,5 миллиона строк , извините.

P.S. Я буду одобрять каждый ответ, поэтому, пожалуйста, продолжайте их ждать.

Ответы [ 5 ]

7 голосов
/ 11 июля 2011

Как уже упоминалось, вы можете добавить контекстный индекс ctx к столбцам имен.

при условии обновления небольшого числа записей, 1 вариант - ежедневно обновлять индекс. (и запишите, когда это произошло)

затем добавьте столбец даты последнего обновления и индекс к вашей таблице, в которой ведется поиск.

Должна быть возможность отсканировать ваш индекс ctx на предмет большинства старых неизмененных данных. и выберите из небольшого процента обновленных данных, используя традиционный LIKE например:

WHERE (lastupdated<lastrefresh AND contains(name,'%ABC%')) 
   OR (lastupdated>lastrefresh AND name like '%ABC%')

ПРИМЕЧАНИЕ: вы можете обнаружить, что ваш план запроса выглядит немного неуместно (много растровых преобразований в идентификаторы строк), в этом случае разбейте две части ИЛИ на запрос UNION ALL. * 1010 например *

SELECT id FROM mytable   
    WHERE 
    (lastupdate>lastrefresh and name LIKE '%ABC%')
    UNION ALL
    SELECT id FROM mytable   
    WHERE lastupdate<lastrefresh and CONTAINS(name, '%ABC%', 1) > 0
6 голосов
/ 03 июня 2011

Единственная оптимизация состоит в том, чтобы не использовать этот тип запроса, а вместо этого использовать собственные возможности платформы базы данных:

См. Oracle Text: http://www.oracle.com/technetwork/database/enterprise-edition/index-098492.html

Общим ответом на вопросы, связанные с SQL Server, будет полнотекстовый поиск ... приятно видеть, что у Oracle есть что-то хорошее или лучшее.

3 голосов
/ 06 июня 2011

UPPER() убивает ваши индексы раньше всего, подумайте об использовании регулярного выражения.Начальное % может избежать обычного сканирования индекса, но не всегда приводит к полному сканированию таблицы, но к полному сканированию индекса, которое быстрее, чем FTS.

Я полагаю, что 'ABC' является переменной.Если нет, то индекс функции - это путь.

0 голосов
/ 17 августа 2016

Используйте текст Oracle, НО немного более новый вариант CTXCAT - этот индекс домена обновляется как часть транзакции, которая вставляет / обновляет соответствующую строку, и, следовательно, всегда актуален - подробности см. В документации Oracle для Oracle.

0 голосов
/ 03 июня 2011

Иногда такого рода запросы неизбежны - извлечение домена из URL или, возможно, корня из слова с префиксом и суффиксом.

Вы можете использовать полнотекстовый индекс с пользовательским токенизатором или без него.

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

http://www.akadia.com/services/ora_function_based_index_2.html

...