Как лучше всего написать SQL-запрос?

Опубликовано: 6 Июля, 2021

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

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

Клиенты: Таблица «Клиенты» содержит подробную информацию о потенциальных покупателях магазина.

Пользовательский ИД Фамилия Имя Адрес Возраст
73001 Смит Джон Джамп-стрит, 45 21 год
73002 Паркер Анна 83 Wild Avenue 45
73003 Джеймс Джози 99 Chestnut Avenue 25
73004 белый Анна 55 Paper Street 72
73005 Искры Гарри Переулок Вистерия, 11 23
73006 Паркер Джейн Квентин-роуд, 12 50

Товары: Таблица "Товары" содержит подробную информацию о товарах, доступных в магазине.

Идантификационный номер продукта Наименование товара Цена продукта
1001 Шампунь 100
1002 Зубная паста 20
1003 Мыло 15
1004 Дезинфицирующее средство для рук 50
1005 Дезодорант 100

Заказы: таблица "Заказы" содержит подробную информацию о товарах, заказанных покупателями в магазине.

Пользовательский ИД Идантификационный номер продукта ProductQuantity
73001 1003 5
73001 1001 1
73003 1002 1
73004 1003 2
73004 1005 1

Теперь, когда мы проанализировали таблицы « Клиенты» , « Продукты» и « Заказы» , ниже приведены различные способы оптимизации запроса с примерами запросов из этих таблиц:

1. Обеспечьте правильное форматирование для запроса.

При написании запроса очень важно обеспечить правильное форматирование. Это улучшает читаемость запроса, а также упрощает просмотр и устранение неполадок. Некоторые правила форматирования запроса приведены ниже:

  • Поместите каждое утверждение в запросе в новую строку.
  • Вводите ключевые слова SQL в запрос в верхнем регистре.
  • Используйте в запросе заглавные буквы CamelCase и избегайте подчеркивания (пишите ProductName, а не Product_Name).

Пример: это запрос, который отображает CustomerID и LastName клиентов, которые в настоящее время заказали продукты и младше 50 лет.

Выберите отдельные Customers.CustomerID, Customers.LastName из Customers INNER присоединитесь к заказам на Customers.CustomerID = Orders.CustomerID, где Customers.Age <50;

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

ВЫБЕРИТЕ РАЗЛИЧНЫХ клиентов.CustomerID, Customers.LastName
ОТ клиентов ВНУТРЕННИЕ ПРИСОЕДИНЕНИЯ Заказы
ВКЛ. Customers.CustomerID = Orders.CustomerID
ГДЕ Клиенты. Возраст <50;

2. Укажите поля SELECT вместо использования SELECT *.

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

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

ВЫБРАТЬ * 
ОТ Заказчиков;

Для получения желаемого результата лучше использовать оператор select с полями CustomerID и LastName.

ВЫБЕРИТЕ CustomerID, LastName 
ОТ Заказчиков;

3. Удалите коррелированные подзапросы, если они не требуются.

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

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

ВЫБЕРИТЕ CustomerID
ОТ клиентов
ГДЕ СУЩЕСТВУЕТ (ВЫБРАТЬ * ИЗ ЗАКАЗОВ
              ГДЕ Customers.CustomerID = Orders.CustomerID);

В этом случае лучше использовать внутреннее соединение, чтобы получить тот же результат.

ВЫБЕРИТЕ РАЗЛИЧНЫХ клиентов.
ОТ клиентов ВНУТРЕННИЕ ПРИСОЕДИНЕНИЯ Заказы
ВКЛ. Customers.CustomerID = Orders.CustomerID;

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

4. Ограничьте результаты, полученные по запросу.

Если требуются только ограниченные результаты, лучше использовать оператор LIMIT. Этот оператор ограничивает количество записей и отображает только указанное количество записей. Например: если имеется большая база данных из миллиона записей и требуются только первые десять, лучше использовать оператор LIMIT, поскольку это гарантирует, что будут получены только соответствующие записи, не перегружая систему.

Пример: это запрос, который отображает сведения о клиенте с лимитом 3:

ВЫБРАТЬ *
ОТ клиентов 
LIMIT 3;

5. Удалите предложение DISTINCT, если оно не требуется.

Предложение DISTINCT используется для получения отличных результатов от запроса путем устранения дубликатов. Однако это увеличивает время выполнения запроса, поскольку все повторяющиеся поля сгруппированы вместе. Таким образом, лучше избегать предложения DISTINCT, насколько это возможно. В качестве альтернативы можно использовать предложение GROUP BY для получения различных результатов.

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

выберите отдельную фамилию
от клиентов;

Отдельные фамилии клиентов также можно получить с помощью предложения GROUP BY, что демонстрируется в следующем примере:

ВЫБЕРИТЕ Фамилию
ОТ ЗАКАЗЧИКОВ
ГРУППА ПО ФАМИЛИ;

6. Избегайте функций в предикатах.

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

Пример: это запрос, который отображает подробную информацию о продуктах, название которых начинается с « Ша ».

ВЫБРАТЬ *
ИЗ ПРОДУКТОВ
ГДЕ SUBSTR (ProductName, 1, 3) = 'Sha';

Лучше избегать этой функции и использовать вместо нее предложение LIKE, чтобы получить тот же результат.

ВЫБРАТЬ *
ИЗ ПРОДУКТОВ
ГДЕ ProductName НРАВИТСЯ "Sha%";

7. По возможности избегайте операторов OR, AND, NOT.

При использовании операторов OR, AND, NOT весьма вероятно, что индексы не используются. В случае больших баз данных лучше найти им замену, чтобы ускорить время выполнения запроса.

Примеры этого для операторов OR и AND приведены ниже:

Пример 1: Это запрос, который отображает сведения о клиентах с CustomerID 73001, 73004 и 73005 с использованием оператора OR.

ВЫБРАТЬ * 
ОТ клиентов
ГДЕ CustomerID = 73001
ИЛИ CustomerID = 73004
ИЛИ CustomerID = 73005;

В этом случае лучше использовать оператор IN, чтобы получить тот же результат.

ВЫБРАТЬ * 
ОТ клиентов
ГДЕ CustomerID IN (73001, 73004, 73005);

Пример 2: Это запрос, который отображает подробную информацию о клиентах в возрасте от 25 до 50 с использованием оператора AND.

ВЫБРАТЬ * 
ОТ клиентов
ГДЕ возраст> = 25 И возраст <= 50;

В этом случае лучше использовать оператор BETWEEN, чтобы получить тот же результат.

ВЫБРАТЬ * 
ОТ клиентов
ГДЕ возраст от 25 до 50 лет;

8. По возможности используйте предложение WHERE вместо предложения HAVING.

Предложение HAVING используется с предложением GROUP BY для обеспечения выполнения условий, поскольку предложение WHERE не может использоваться с агрегатными функциями. Однако предложение HAVING не позволяет использовать индексы, что замедляет время выполнения запроса. Поэтому лучше по возможности использовать предложение WHERE вместо предложения HAVING.

Пример. Это запрос, который отображает имена клиентов с указанием количества клиентов, у которых они есть, для клиентов старше 25 лет. Это делается с помощью предложения HAVING.

ВЫБЕРИТЕ FirstName, COUNT (*)
ОТ клиентов
ГРУППА ПО ИМЕНИ
ИМЕЮЩИЙ возраст> 25 лет;

В этом случае лучше использовать предложение WHERE, поскольку оно применяет условие к отдельным строкам, а не предложение HAVING, которое применяет условие к результату из предложения GROUP BY.

ВЫБЕРИТЕ FirstName, COUNT (*)
ОТ клиентов
где Возраст> 25
ГРУППА ПО имени;

9. Используйте INNER JOIN вместо предложения WHERE для создания объединений.

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

Пример: это запрос, который отображает CustomerID клиентов, которые в настоящее время заказали продукты, используя предложение WHERE.

ВЫБЕРИТЕ РАЗЛИЧНЫХ клиентов.
ОТ Клиентов, Заказы
ГДЕ Customers.CustomerID = Orders.CustomerID;

В этом случае лучше использовать внутреннее соединение, чтобы получить тот же результат.

ВЫБЕРИТЕ РАЗЛИЧНЫХ клиентов.
ОТ клиентов ВНУТРЕННИЕ ПРИСОЕДИНЕНИЯ Заказы
ВКЛ. Customers.CustomerID = Orders.CustomerID;

10. Избегайте использования подстановочных знаков в начале шаблона предложения LIKE.

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

Пример:

ВЫБРАТЬ * ОТ клиентов
ГДЕ FirstName КАК "% A%"

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

ВЫБРАТЬ * ОТ клиентов
ГДЕ FirstName КАК 'A%'
SQL