
24)Правила конструирования эффективного sql-кода.
К общепринятым рекомендациям по использованию различных типов индексов и конструированию SQL-запросов относятся следующие:
Правило 1. Для индекса целесообразно выбирать атрибуты, имена которых часто указываются в предложении WHERE.
Правило 2. Необходимо производить индексирование атрибутов, которые применяются при выполнении операции соединения.
Правило 3. При использовании ограничения ссылочной целостности данных необходимо создавать индекс для внешнего ключа.
Правило 4. Не рекомендуется создавать индексы для атрибутов с низкой селективностью. Низкая селективность предполагает небольшое количество различных значений атрибута. Критерий низкой селективности - самое редкое значение атрибута встречается не более 10 процентов среди всех значений атрибута. В этом случае атрибут должен быть проиндексирован как битовый индекс.
Правило 5. Не рекомендуется создавать индексы для таблиц малой размерности. Критерием малой размерности таблицы является ее размещение в одном блоке дискового пространства. Для информирования СУБД о необходимости игнорирования индекса используются две формы конструирования запросов.
Первая форма предполагает применение подсказки, которая указывает на необходимость полного сканирования таблицы:
SELECT /*+ FULL (<имя таблицы>)*/ <атр 1>, <атр 2>
FROM <таблица>
WHERE <условие>;
Вторая форма:
SELECT <атр 1>, <атр 2>
FROM <таблица>
WHERE <атр 3> + 0 = <значение>;
где конструкция <атр 3> + 0 указывает на необходимость игнорирования индекса.
Правило 6. Применение индексов эффективно при выполнении агрегатных функций MIN и МАХ. Однако одновременное использование этих функций в одном предложении условия приводит к подавлению индекса и, как следствие, к необходимости просмотра всех кортежей таблицы.
Правило 7. Рекомендуется операцию сравнения «неравно»<> заменять на два оператора - «больше» > и «меньше» <, соединенных логическим оператором «ИЛИ» - OR:
SELECT* |
|
SELECT* |
FROM <таблица> |
|
FROM <таблица> |
WHERE <атр 1> <><значение>; |
|
WHERE <атр 1> > <значение> OR <атр 1> < <значение>; |
Правило 8. Для неиндексированных атрибутов вместо сложного условия в предложении WHERE, включающего логический оператор OR, рекомендуется применять конструкцию объединения результатов независимых запросов с помощью оператора UNION.
Для индексированных атрибутов:
SELECT fio
FROM sotr
WHERE city_pr = ‘РОСТОВ’
OR vosr > 60;
Для неиндексированных атрибутов:
SELECT fio
FROM sotr
WHERE city_pr = ‘РОСТОВ’
UNION
SELECT fio
FROM sotr
WHERE vosr > 60;
Правило 9. Составные индексы рекомендуется применять только в том случае, когда атрибуты такого индекса включены в одно предложение WHERE. Для лидирующего атрибута составного индекса не следует конструировать самостоятельный индекс.
Правило 10. В том случае, если в индексированном столбце содержится большое количество неопределенных значений, а разрабатываемый запрос включает условие на выбор кортежей, у которых значения такого атрибута определены, то вместо условия WHERE <имя атр> IS NOT NULL целесообразно использовать следующее: WHERE <атр> >= ‘ ’.
Правило 11. Нецелесообразно индексировать атрибуты, включенные в предложение WHERE и содержащие функции или операторы. В частности, индекс по атрибуту lastname будет подавляться, если этот атрибут применяется в функции UPPER (lastname). Аналогичная реакция СУБД произойдет при проверке условия WHERE 10 * salary > 2000.
Правило 12. Не рекомендуется использование для индексированных атрибутов шаблона, в котором не определен первый символ. Например,
WHERE fio LIKE ‘%ИЧ’.
Правило 13. Активно обновляемые атрибуты нецелесообразно выбирать для индексации, т.к. для поддержания индексного дерева в актуальном состоянии требуется дополнительная обработка.
Правило 14. Нецелесообразно использовать условие соответствия шаблону LIKE в том случае, если достаточно проверки на равенство значений атрибута ‘=’.
Правило 1 5. Необходимо в предложении WHERE для числовых параметров указывать числовое значение для сравнения, а для символьных параметров - символьное значение. В частности,
WHERE tab_num = 101, WHERE pod = ‘АСУ’.
Правило 16. Вместо оператора NOT IN в предложениях WHERE и HAVING рекомендуется использовать оператор NOT EXISTS.
Правило 17. Для уменьшения числа выборок в таблице при проектировании приложения в среде Oracle целесообразно применять функцию DECODE.
Правило 18. Необходимо информировать СУБД об игнорировании индекса и использовании стратегии полного просмотра таблицы в том случае, если запрос возвращает более двадцати процентов кортежей таблицы.
Правило 19. При ссылке на атрибуты необходимо использовать алиасы таблиц.
Правило 20. Приоритетным является применение операции соединения таблиц по сравнению с конструкцией вложенных запросов.
Правило 21. При наличии двух равнозначных по семантике запросов - использование вложенных либо коррелированных подзапросов - необходимо учитывать следующее:
если главный запрос возвращает относительно небольшое число кортежей, то коррелированный подзапрос будет выполняться быстрее по сравнению с вложенным;
если подзапрос возвращает небольшое число строк, то вложенный подзапрос будет выполняться быстрее коррелированного.
Правило 22. Необходимо активно применять массивы-коллекции, т.к. их обработка существенно сокращает количество операций ввода-вывода. В частности, при обновлении в таблице 2000 строк следует произвести 2000 операций чтения и 2000 операций обновления. При обработке массива размерностью 100 будет выполнено 20 операций чтения и 20 операций обновления. Для СУБД Oracle увеличение размерности массива свыше 100 не приводит к значительному повышению производительности.
Правило 23. Во вложенных запросах вместо «больше каждого» >= ALL рекомендуется применять оператор сравнения «больше максимального» >=max (<атр>).
SELECT* |
SELECT* |
FROM r1 |
FROM r1 |
WHERE u1>= ALL |
WHERE u1>= |
(SELECT z1 |
(SELECT MAX (z1) |
FROM r2 |
FROM r2 |
WHERE s1>= ‘a’); |
WHERE s1 >= ‘a’); |
Правило 24. В предложении WHERE, содержащем сложное условие, в котором простые условия соединены между собой логическим оператором OR, первым необходимо указывать условие, которому удовлетворяет меньшее количество кортежей.
Пример. Заявив таблица prep (рис. 5.2).
Cod |
Fio |
Dol |
Vosr |
usv |
Требуется получить информацию о преподавателях, находящихся на должности доцента возраст которых превышает 75 лет.
Корректная форма представления запроса имеет следующий вид:
SELECT*
FROM prep
WHERE vosr > 75
OR dol= ‘Д0ЦЕНТ;
В этом запросе первым в предложении WHERE указано условие vosr > 75, т.к. количество преподавателей в таком возрасте меньше количества преподавателей, работающих на должности доцента. В случае использования в сложном условии логического оператора AND условие, которому удовлетворяет меньшее количество кортежей, указывается последним в предложении WHERE.
Правило 25. В предложении WHERE необходимо минимизировать перечисление длинных серий при использовании операции принадлежности множеству значений: WHERE <атр> IN (<знач 1> <знач 2>).
Пример. Из отношения рreр (см. рис. 5.2) следует получить сведения о преподавателях
с кодом от 105 до 115, за исключением кода, равного 110:
SELECT*
FROM prep
WHERE cod IN (105,106,107, 108,109, 111, 112,113,114,115);
Рекомендуется следующий SQL-оператор
SELECT*
FROM prep
WHERE (cod BETWEEN 105 AND 115 ) AND cod <> 110;
Правило 26. При выполнении операции соединения двух таблиц в качестве ведущей должна быть указана таблица с меньшим количеством кортежей. Такая таблица должна быть приведена последней в предложении FROM и первой в предложении WHERE.
Пример. Заданы две таблицы S и R, число кортежей в таблице R меньше, чем в S. В качестве атрибутов соединения применяются атрибуты R.C и S.С. Тогда, с точки зрения производительности, эффективный SQL-код представляется следующим образом:
SELECT*
FROM St R
WHERE R.C = S.C;
Правило 27. В том случае, если при выполнении вложенного запроса внутренний запрос возвращает сдублированные значения атрибутов, то вместо вложенных запросов рекомендуется использовать операцию соединения.
Правило 28. При применении вложенных запросов необходимо стремиться к уменьшению количества проверок на наличие хотя бы одного кортежа, удовлетворяющего условию, приведенному в подзапросе.