Как я могу оптимизировать динамический поисковый запрос в Oracle - PullRequest
1 голос
/ 16 июня 2009

Я пишу хранимую процедуру для выполнения динамического поиска, который охватывает более 10 таблиц базы данных. С миллионами записей в каждой таблице и динамическим набором параметров поиска * у меня возникли проблемы с оптимизацией процедуры.

Существует ли "наилучшая практика" для создания таких запросов? Например. Используйте строки для построения динамического запроса, используйте огромный список операторов IF THEN .. ELSE и т. Д.? Кто-нибудь может привести простой пример или указать мне литературу, которая поможет? Вот некоторый psuedocode для хранимой процедуры, которую я разрабатываю, которая принимает коллекцию параметров и курсор ref.

v_query = "SELECT .....";
v_name = ... -- retrieve "name" parameter from collection
if v_name is not null then
   v_query := v_query || ' AND table.Name = ' || v_name;
end if;
open search_cursor for v_query;
...

* Под «динамическим набором параметров поиска» я подразумеваю, что я передаю набор параметров. Я подумал, что это будет проще, чем заставить вызывающего передать 20 параметров, если они хотят искать только по одному.

Ответы [ 4 ]

4 голосов
/ 17 июня 2009

Есть проблемы с использованием подхода статического запроса; также будьте очень осторожны при использовании параметра CURSOR_SHARING = FORCE - он может действительно поднять вашу систему, если вы не провели тест покрытия, чтобы гарантировать, что все ваши другие запросы будут работать так, как вы хотите.

Проблемы со статическими запросами:

  1. Предикаты (x равен нулю или x = col), как правило, убивают любой шанс использования индексов. Поскольку план запроса вычисляется при первом анализе запроса, используемые вами индексы будут основаны на значениях для первого запуска запроса; последующие прогоны, которые могут не ограничиваться теми же столбцами, будут по-прежнему использовать те же индексы.

  2. Наличие одного статического оператора с переменными подстановки не позволит оптимизатору сделать разумный выбор в отношении того, какой индекс использовать на основе распределения данных. В динамическом запросе (или при первом запуске запроса с переменными связывания) Oracle увидит, насколько избирательным является ваше ограничение; очень избирательное ограничение станет основным кандидатом на использование индекса. Например, если в вашей таблице есть строка для каждого человека в США, STATE = 'Аляска' будет гораздо более вероятно использовать индекс STATE, чем STATE = 'Калифорния'.

Конечно, в обоих этих случаях, если динамические столбцы в предложении WHERE все равно не проиндексированы, это не имеет значения, хотя я был бы удивлен, если бы это было в базе данных того размера, о котором вы говорите о.

Кроме того, учтите реальную стоимость всего этого сложного анализа. Да, жесткий анализ сериализует системные ресурсы, что делает их дорогими, но только в контексте запросов большого объема . По своей природе специальные запросы выполняются не очень часто. Стоимость, которую вы платите за все сложные анализы, которые вы выполняете за целый день, вероятно, будет в сотни раз меньше стоимости одного запроса, который использует неправильные индексы.

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

Стоит учесть одну вещь: если эта система в основном автономна (другими словами, она не постоянно обновляется или не вставляется - заполняется периодическими загрузками объемных данных), вам может понадобиться использовать индексы BITMAP. Растровые индексы отличаются от обычных индексов b-дерева тем, что несколько индексов в одной таблице могут использоваться одновременно, и индексы битовой карты на диске намного, намного меньше, чем b-деревья. Они очень хорошо работают для таких приложений, как здесь, где у вас будет множество ограничений, которые не могут быть определены во время разработки. Вам нужно будет размещать растровые индексы только в столбцах с относительно небольшим количеством различных значений, скажем, одно значение составляет не менее 1/1000 таблицы, поэтому не используйте растровые изображения для уникальных столбцов.

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

2 голосов
/ 16 июня 2009

За исключением очень особых случаев, я не думаю, что целесообразно (или даже возможно) попытаться сгенерировать оптимизированный запрос. Мой совет - не использовать динамический SQL, если вы можете: трудно читать, трудно отлаживать, трудно оптимизировать, трудно поддерживать.

Сначала напишите общий запрос, который будет работать с любым параметром, отправленным в вашу процедуру. Согласно вашему примеру, это даст что-то вроде:

SELECT * FROM table WHERE ((v_name IS NULL) OR (table.Name=v_name));

Как видите, вы можете легко добавить другие параметры в этот запрос без использования динамического SQL. Этот запрос намного легче читать и отлаживать. Спросите у администратора базы данных советы по оптимизации.

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

IF particular_set
THEN
    /* Specific query */
ELSE
    /* Generic query */
END IF;

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

1 голос
/ 16 июня 2009
1 голос
/ 16 июня 2009

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

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

Один вопрос / проблема, которую вам нужно будет решить, вы жестко закодировали критерии (например, WHERE SURNAME='SMITH') или используете переменные связывания? Использование переменных связывания уменьшает трудоемкий анализ, что снижает нагрузку на сервер базы данных; однако может быть непрактично использовать переменные связывания, когда SQL генерируется динамически. В итоге мы установили CURSOR_SHARING=FORCE (что имеет свои недостатки), что было разумным компромиссом в нашем случае.

...