Найти в Дзене
Столяров Филипп

Оптимизируй SQL запросы, как Senior (MS SQL)

Содержимое статьи направлено на умение работать с планом запроса и понимание работы физических джойнов.
Для выполнения задания необходимо выполнить подготовительные работы. Установить SQL Server, MS Studio и подключиться к учебной БД AdventureWorks2014.
Как это делать можно посмотреть в видео:
https://dzen.ru/video/watch/66b0c55e88415d023ffbdba1
Вводные данные:
Есть рандомно взятый запрос из книги SQL Server Execution Plans by By Grant Fritchey (3-е издание):
SELECT e.JobTitle, a.City,
p.LastName + ', ' + p.FirstName AS EmployeeName
FROM HumanResources.Employee AS e
INNER JOIN Person.BusinessEntityAddress AS bea
ON e.BusinessEntityID = bea.BusinessEntityID
INNER JOIN Person.Address AS a
ON bea.AddressID = a.AddressID
INNER JOIN Person.Person AS p
ON e.BusinessEntityID = p.BusinessEntityID;
Который, выполняется со следующим планом Цель разобрать план выполнения и проверить можно ли что - то улучшить. Перед разбором этого плана, важно вспомнить, что существует всего 3 физических джо

Содержимое статьи направлено на умение работать с планом запроса и понимание работы физических джойнов.

Для выполнения задания необходимо выполнить подготовительные работы. Установить SQL Server, MS Studio и подключиться к учебной БД AdventureWorks2014.
Как это делать можно посмотреть в видео:

https://dzen.ru/video/watch/66b0c55e88415d023ffbdba1

Вводные данные:
Есть рандомно взятый запрос из книги SQL Server Execution Plans by By Grant Fritchey (3-е издание):

SELECT e.JobTitle, a.City,
p.LastName + ', ' + p.FirstName AS EmployeeName
FROM HumanResources.Employee AS e
INNER JOIN Person.BusinessEntityAddress AS bea
ON e.BusinessEntityID = bea.BusinessEntityID
INNER JOIN Person.Address AS a
ON bea.AddressID = a.AddressID
INNER JOIN Person.Person AS p
ON e.BusinessEntityID = p.BusinessEntityID;

Который, выполняется со следующим планом

План запроса
План запроса

Цель разобрать план выполнения и проверить можно ли что - то улучшить.

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

  • Nested Loops: хорош для малых данных; прост, но плохо масштабируется.
  • Hash Match: мощный, устойчив к большим объемам, но требует много памяти.
  • Merge Join: используется, если данные отсортированы, — очень быстрый.

    В случае, когда оптимизатор ошибается с выбором оптимального вида соединения, можно написать
    OPTION (Name JOIN), где Name название соединения (Loop, Hash или Merge), которое вы рекомендуете использовать оптимизатору. Но, предпочтительнее решать задачу оптимизации при помощи создания или удаления индексов в соединяемых таблицах.

    Итак, в плане выполнения указано:
  • Стоимость запроса: 100% (поскольку он один в пакете).
  • Смотрим на стрелки — их толщина показывает объем данных
  • Используются след типы соединений: Два раза вложенные циклы (Nested Loops) это верное решение, так как таблицы маленькие и Hash Match между ними для соединения
    Employee (e)
    INNER JOIN BusinessEntityAddress (bea)

    При текущем состоянии таблиц, это также верное решение поскольку:

1) У таблицы BusinessEntityAddress нет индекса по BusinessEntityID.

2) Таблицы не отсортированы, поэтому Merge Join невозможен.

3) Nested Loops здесь был бы менее эффективным, потому что при отсутствии индекса пришлось бы делать сканирование.

Именно, в этом запросе нет критически затратных по операциям шагов, все в пределах 0%–36%. Поэтому, время выполнения составляет доли секунд.

Если эта тема
вызывает интерес и пост наберет больше 10 лайков, то будет разобран запрос, который работает больше 5 минут и при помощи плана мы сможем внести изменения, которые позволят существенно ускорить его выполнение.

Благодарю за прочтение!
По вопросам сотрудничества обращайтесь на почту: mypj@ya.ru