【发布时间】:2018-11-14 10:04:29
【问题描述】:
需要使用以下查询从单个阶段表中获取数据。但是,查询需要大量时间来执行。如何优化以下查询? 执行计划说有一个table spool,占12.22总成本和预计运营成本的50%。
CREATE TABLE #Enrollment_grp
(
rowcounts int,
CustomerID NVARCHAR(100),
EWSPurchaseDate DATETIME,
EWSPlanType nvarchar(200),
ContractStatus nvarchar(200),
TerminationDate DATETIME,
StoreId [nvarchar](100) NULL,
CreatedDate DATETIME NULL,
ProductSKU [nvarchar](200) NULL,
ClientEWSWarrantySKU [nvarchar](100) NULL,
COUNTSL int null
)
CREATE CLUSTERED INDEX IDX_Enrollment_GRP_CustomerID ON #Enrollment_grp(CustomerID)
CREATE NONCLUSTERED INDEX IDX_Enrollment_GRP_EWSPUR ON #Enrollment_grp(EWSPurchaseDate)
CREATE NONCLUSTERED INDEX IDX_Enrollment_GRP_TERMDATE ON #Enrollment_grp(TerminationDate)
insert INTO #Enrollment_grp(CustomerID,EWSPurchaseDate,rowcounts,EWSPlanType,ContractStatus,TerminationDate,StoreID,CreatedDate,ProductSKU,ClientEWSWarrantySKU,COUNTSL)
(
SELECT CustomerID,EWSPurchaseDate,rowcounts,EWSPlanType,ContractStatus,temp.TerminationDate,temp.StoreID,temp.CreatedDate,temp.ProductSKU,temp.ClientEWSWarrantySKU,COUNTSL
from
(
SELECT x.CustomerID,x.EWSPurchaseDate,ROW_NUMBER() over(PARTITION BY x.CustomerID,x.EWSPlanType ORDER BY x.CreatedDate DESC) as rowcounts,
count(EWSPlanType) over (PARTITION BY x.CustomerID,x.EWSPlanType ORDER BY x.CreatedDate) COUNTSL,x.EWSPlanType,x.ContractStatus
,x.TerminationDate,X.StoreID,X.CreatedDate,x.ProductSKU,x.ClientEWSWarrantySKU
FROM STAGE_ENROLLMENT AS x (NOLOCK) WHERE x.ClientID = 1
) AS temp WHERE temp.rowcounts=1 AND cast(temp.TerminationDate AS DATE)>='2018-10-01'
)
CREATE TABLE #tmp
(
ID int IDENTITY(1,1) PRIMARY KEY,
TransactionNo [nvarchar](100) NULL,
StoreName [nvarchar](100) NULL,
EWSPlan NVARCHAR(200),
EventDate DATETIME NULL,
ProductType [nvarchar](200) NULL,
PlanStartDate [varchar](50) NULL,
PlanEndDate [varchar](50) NULL
)
CREATE NONCLUSTERED INDEX IX_tmp_TN
ON #tmp(TransactionNo)
INSERT INTO #tmp
(TransactionNo,
StoreName,
EWSPlan,
ProductType,
PlanStartDate,
PlanEndDate
)
(SELECT DISTINCT
stg.CustomerID AS TransactionNo,
stg.StoreID AS StoreName,
CASE WHEN SUM(DISTINCT CAST(stg.ClientEWSWarrantySKU AS INT)) = 6 THEN 'AA'
WHEN SUM(DISTINCT CAST(stg.ClientEWSWarrantySKU AS INT)) = 15 THEN 'BB'
WHEN SUM(DISTINCT CAST(stg.ClientEWSWarrantySKU AS INT)) = 33 THEN 'CC'
WHEN SUM(DISTINCT CAST(stg.ClientEWSWarrantySKU AS INT)) = 42 THEN 'DD'
END AS EWSPlan,
stg.ProductSKU AS ProductType,
cast(format(stg.EWSPurchaseDate,'yyyy/MM/dd') as VARCHAR) AS PlanStartDate ,
'' AS PlanEndDate--,
FROM STAGE_ENROLLMENT AS stg (NOLOCK)
WHERE stg.ClientID = 1
AND stg.EWSPurchaseDate<='2018-10-31' AND stg.TerminationDate>='2018-10-01'
AND stg.ContractStatus = 1
AND stg.CustomerID IN (SELECT CustomerID FROM #Enrollment_grp where EWSPurchaseDate<='2018-10-31' AND TerminationDate>='2018-10-01' GROUP BY CustomerID HAVING COUNT(DISTINCT EWSPlanType) = 3 )
AND stg.ProductSKU IN (SELECT ProductSKU FROM #Enrollment_grp where EWSPurchaseDate<='2018-10-31' AND TerminationDate>='2018-10-01' GROUP BY ProductSKU HAVING COUNT(DISTINCT EWSPlanType) = 3 )
AND stg.StoreID IN (SELECT StoreID FROM #Enrollment_grp where EWSPurchaseDate<='2018-10-31' AND TerminationDate>='2018-10-01' GROUP BY StoreID HAVING COUNT(DISTINCT EWSPlanType) = 3 )
GROUP BY stg.CustomerID,stg.EWSPurchaseDate,stg.StoreID,stg.ProductSKU
HAVING COUNT(DISTINCT stg.EWSPlanType) = 3
AND
(CASE WHEN SUM(DISTINCT CAST(stg.ClientEWSWarrantySKU AS INT)) = 6 THEN 'AA'
WHEN SUM(DISTINCT CAST(stg.ClientEWSWarrantySKU AS INT)) = 15 THEN 'BB'
WHEN SUM(DISTINCT CAST(stg.ClientEWSWarrantySKU AS INT)) = 33 THEN 'CC'
WHEN SUM(DISTINCT CAST(stg.ClientEWSWarrantySKU AS INT)) = 42 THEN 'DD'
END) IS NOT NULL
)
任何人都可以对上述情况提供任何建议吗?
【问题讨论】:
-
您能注意一下批处理中每个查询的执行时间吗?
-
8.5 分钟此插入 #tmp 表
-
首先删除 *
NOLOCK。这并不意味着快速或不锁定,它意味着“读取脏数据和重复数据,同时占用过多的锁并完全错过一些行” -
该查询存在许多问题 - 将日期转换为 字符串、WHERE 或 HAVING 子句中的求和和强制转换、子查询 中的组。那个单表线轴是最少的问题。将函数应用于字段可防止服务器使用任何覆盖它的索引。
ClientEWSWarrantySKUet 似乎是 flags 并且那个大 CASE 正试图确定这些标志的值。使用单独的表而不是case来通过简单的连接确定EWSPlan的值。 -
感谢您的建议!而不是下面的 case 语句 (CASE WHEN SUM(DISTINCT CAST(stg.ClientEWSWarrantySKU AS INT)) = 6 THEN 'AA' WHEN SUM(DISTINCT CAST(stg.ClientEWSWarrantySKU AS INT)) = 15 THEN 'BB' WHEN SUM(DISTINCT CAST (stg.ClientEWSWarrantySKU AS INT)) = 33 THEN 'CC' WHEN SUM(DISTINCT CAST(stg.ClientEWSWarrantySKU AS INT)) = 42 THEN 'DD' END) IS NOT NULL 下面使用和 SUM(DISTINCT CAST(stg.ClientEWSWarrantySKU AS INT)) 在 (6,15,33,42) 中。这样会好吗?
标签: sql sql-server tsql indexing