T-SQL | Пример оптимизации выгрузки данных

Пример выполнен на базе данных AdventureWorks (см. Примеры БД MS SQL Server); основная таблица – Sales.SalesOrderDetail.

 

Перед выполнением примера объем данных таблицы Sales.SalesOrderDetail увеличен в несколько раз (с 121 318 до 3 429 928 записей; пример скрипта есть в Примерах INSERT INTO).

 


Например, есть задача отобрать суммы заказов, введенных в базу в 2015-м году, по определенным типам спец. предложений и категориям продуктов, примерно такой отчет:

 

 

 

Для отчета нужны таблицы:

 

Sales.SalesOrderDetail – детали заказа (основная таблица, 3.5 млн. записей; из нее нужны только только те заказы, которые были введены в 2015-м году)

Sales.SalesOrderHeader – заголовок заказа;

Sales.SpecialOffer – справочник спец. предложений (нужны только заказы "без скидок" и "по новым продуктам");

Production.Product – справочник продуктов;

Production.ProductSubcategory – справочник подкатегорий продуктов;

Production.ProductCategory – справочник категорий продуктов (нужны только котегории "Одежда" и "Компоненты")

 

 


Традиционный SELECT отбора данных для отчета – результат 21 840 записей, выданных за 21 секунду

(SQL для копирования в конце статьи):

 

 

 


Оптимизация запроса с помощью CTE-выражений – результат 21 840 записей, выданных за 16 секунд

(SQL для копирования в конце):

 

Каждое CTE-выражение содержит только требуемые для отчета поля и записи, это оптимально для JOIN-ов

 

 


 

SQL-1:

 

USE AdventureWorks

GO

SELECT

soh.SalesOrderNumber

,sum(sod.OrderQty) AS OrderQty

,sum(sod.LineTotal) AS LineTotal

,so.Type AS SpecOrderType

,psc.Name AS ProductSubCategory

,pc.Name AS ProductCategory

FROM Sales.SalesOrderDetail sod

INNER JOIN Sales.SalesOrderHeader soh ON soh.SalesOrderID = sod.SalesOrderID

INNER JOIN Sales.SpecialOffer so ON so.SpecialOfferID = sod.SpecialOfferID

INNER JOIN Production.Product p ON p.ProductID = sod.ProductID

INNER JOIN Production.ProductSubcategory psc ON psc.ProductSubcategoryID = p.ProductSubcategoryID

INNER JOIN Production.ProductCategory pc ON pc.ProductCategoryID = psc.ProductCategoryID

WHERE

sod.ModifiedDate >= '2015-01-01' AND sod.ModifiedDate <= '2015-12-31' AND --ââåäåíû â áàçó â 2015-ì ãîäó

(pc.ProductCategoryID = 3 OR pc.ProductCategoryID = 2) AND --Îäåæäà è Êîìïîíåíòû

(so.Type = 'No Discount' OR so.Type = 'New Product') --áåç ñêèäîê èëè íîâûé ïðîäóêò

GROUP BY

soh.SalesOrderNumber

,so.Type

,psc.Name

,pc.Name

 


 

SQL-2:

 

USE AdventureWorks

GO

WITH

SalesOrder (SalesOrderNumber, LineTotal, OrderQty, SpecOrderType, ProductID) AS

(

SELECT  

soh.SalesOrderNumber

,sod.LineTotal

,sod.OrderQty

,so.Type AS SpecOrderType

,sod.ProductID

FROM Sales.SalesOrderDetail sod

INNER JOIN Sales.SalesOrderHeader soh ON soh.SalesOrderID = sod.SalesOrderID

INNER JOIN Sales.SpecialOffer so ON so.SpecialOfferID = sod.SpecialOfferID

WHERE sod.ModifiedDate >= '2015-01-01' AND sod.ModifiedDate <= '2015-12-31' AND

(so.Type = 'No Discount' OR so.Type = 'New Product')

), --SalesOrder

 

Product (ProductID, ProductSubCategory, ProductCategory) AS

(

SELECT  

p.ProductID

,psc.Name AS ProductSubCategory

,pc.Name AS ProductCategory

FROM Production.Product p

INNER JOIN Production.ProductSubcategory psc ON psc.ProductSubcategoryID = p.ProductSubcategoryID

INNER JOIN Production.ProductCategory pc ON pc.ProductCategoryID = psc.ProductCategoryID

WHERE pc.ProductCategoryID = 3 OR pc.ProductCategoryID = 2

) --Product

 

SELECT  

SalesOrder.SalesOrderNumber

,sum(SalesOrder.LineTotal) AS LineTotal

,sum(SalesOrder.OrderQty) AS OrderQty

,SpecOrderType

,Product.ProductSubCategory

,Product.ProductCategory

FROM SalesOrder

INNER JOIN Product ON Product.ProductID = SalesOrder.ProductID

GROUP BY

SalesOrder.SalesOrderNumber

,SpecOrderType

,Product.ProductSubCategory

,Product.ProductCategory


 



© 2018 | Анна Петросян | pashelp@yandex.ru