SQL Server 中的 SQL 查询优化
Posted
技术标签:
【中文标题】SQL Server 中的 SQL 查询优化【英文标题】:SQL query optimization in SQL Server 【发布时间】:2016-12-29 13:43:10 【问题描述】:在 SQL Server 中,查询执行计划,两个操作(并行和哈希匹配)分别占总成本的 30% 和 45%。
并行和哈希匹配是什么意思?
对于并行度,我检查了on this link 并行度数会影响查询的性能,我如何检查服务器的并行度数是多少?
如何降低这个成本?我不知道如何才能降低此成本。
我的查询返回 4200 万行并连接 5 个表;没有where
条件,没有group by
,order by
子句。
我在连接列上有非聚集索引。
我的查询是:
SELECT
[INV].SKU AS [INV_SKU],
[INV].LOCATION_ID AS [INV_LOCATION_ID],
[INV].DATE AS [INV_BALANCE_DATE],
[INV].COST AS INV_COST,
[ITEM].ITEM_ID,
[ITEM].ITEM_NAME,
[SPITEM].ITEMNumber As SP_ITEMID,
[SPITEM].NAME,
[SPITEM_DEPT].[SKEY],
[SPITEM_DEPT].[DEPT_NAME],
[Time].[DATE] AS [CAL_DATE],
[Time].[CAL_NAME] AS [CAL_NAME],
[Time].[YEAR_NAME] AS [YEAR_NAME],
[Time].[YEAR_NUM] AS [YEAR_NUM],
[Time].[YEAR_START_DT] AS [YEAR_START_DT],
ISNUL(convert(INT, convert(varchar, [Time].[WEEK_END_DT], 112)), 0) AS [WEEK_END_DT_SKEY],
CASE
WHEN [ITEM].DEPARTMENT IS NULL
THEN (CASE
WHEN [SPITEM_DEPT].SPITEM_DEPT_NAME = 'UNSPECIFIED'
THEN 0
ELSE [SPITEM_DEPT].SPITEM_DEPT_NAME
END)
ELSE [ITEM].DEPARTMENT
END AS [DEPARTMENTNUM],
CASE
WHEN [ITEM].[DEPARTMENT_DESCRIPTION] IS NULL
THEN [SPITEM_DEPT].[DESCRIPTION]
ELSE [ITEM].[DEPARTMENT_DESCRIPTION]
END AS [ITEM_DEPARTMENT_DESC],
[LOCATION].LOCATION_NAME,
[LOCATION].COUNTRY,
[LOCATION].CURRENCY,
[CURRENCY].BASE_CURRENCY
FROM
[dbo].[Table1] [INV]
LEFT JOIN
dbo.Table2 AS [ITEM] ON ([INV].SKU = [ITEM].SKU )
LEFT JOIN
dbo.Table3 AS [LOCATION] ON ([INV].LOCATION_ID = [LOCATION].LOCATION_ID)
INNER JOIN
dbo.Table4 [Time] ON ([INV].DATE = [Time].DATE)
LEFT JOIN
dbo.Table5 [SPITEM] ON ([INV].SKU = SPITEM.NAME)
LEFT JOIN
[dbo].[Table6] [SPITEM_DEPT] ON ([SPITEM].[WS_KPI_ITEM_MERCHANDISE_DEPARTMENT_SKEY] = [SPITEM_DEPT].[SKEY])
LEFT JOIN
[dbo].[Table7] [CURRENCY] ON ([INV].DATE BETWEEN [CURRENCY].BEGIN_DT AND [CURRENCY].END_DT AND [LOCATION].CURRENCY= [CURRENCY].LOCAL_CURRENCY)
我们在连接列上也有非聚集索引。
请提出可能的解决方案,我可以试试。
我是 SQL Server 查询优化的新手。
【问题讨论】:
返回 4200 万行需要花费大量时间,即使查询本身非常快。你应该问问自己你需要这些行来做什么...... 能否提供您查询的执行计划? 使用brentozar.com/pastetheplan分享您的执行计划 不要掉入直接跳到 MAXDOP 的陷阱,过度并行通常是索引问题的症状。 请使用COALESCE()
或ISNULL()
而不是CASE WHEN ??? IS NULL THEN ...
;)。
【参考方案1】:
行数很大,对我来说,主要问题是你没有任何 where 条件,即使你有索引但没有谓词也是一个糟糕的场景。并行度数由你的DBA设置,表示算子的阈值是并行还是串行。
https://technet.microsoft.com/es-es/library/ms181007%28v=sql.105%29.aspx?f=255&MSPPError=-2147217396
我建议您阅读 Grant Fritchey 的这本关于执行计划的免费书籍: https://www.red-gate.com/library/sql-server-execution-plans-2nd-edition
不过,我的建议是: 1) 在查询中添加过滤器 (Where) 2) 审查您的索引策略
【讨论】:
【参考方案2】:用这些索引做一些测试(不是一次全部)。
首先关注较大的桌子。
同样在您加入 table7 中尝试将您的 BETWEEN 语句更改为下面的示例
[INV].DATE >= [CURRENCY].BEGIN_DT
AND
[INV].DATE <= [CURRENCY].END_DT
CREATE NONCLUSTERED INDEX idx1 ON [dbo].[Table1](SKU)
CREATE NONCLUSTERED INDEX idx2 ON [dbo].[Table1](LOCATION_ID)
CREATE NONCLUSTERED INDEX idx3 ON [dbo].[Table1](DATE) INCLUDE(COST)
CREATE NONCLUSTERED INDEX idx1 ON [dbo].[Table2](SKU) INCLUDE(ITEM_ID,ITEM_NAME,DEPARTMENT,DEPARTMENT_DESCRIPTION)
CREATE NONCLUSTERED INDEX idx1 ON [dbo].[Table3](LOCATION_ID,CURRENCY) INCLUDE(LOCATION_NAME,COUNTRY)
CREATE NONCLUSTERED INDEX idx1 ON [dbo].[Table4](DATE) INCLUDE(CAL_NAME,YEAR_NAME,YEAR_NUM,YEAR_START_DT,WEEK_END_DT)
CREATE NONCLUSTERED INDEX idx1 ON [dbo].[Table5](NAME,WS_KPI_ITEM_MERCHANDISE_DEPARTMENT_SKEY) INCLUDE(ITEMNumber)
CREATE NONCLUSTERED INDEX idx1 ON [dbo].[Table6](SKEY) INCLUDE(DEPT_NAME,SPITEM_DEPT_NAME,DESCRIPTION)
CREATE NONCLUSTERED INDEX idx1 ON [dbo].[Table7](LOCAL_CURRENCY,BEGIN_DT,END_DT) INCLUDE(BASE_CURRENCY)
如果您已经用尽了所有可能的索引选项,那么您始终可以通过在查询的基础上使用 MAXDOP 选项来限制查询使用的处理器数量。 我不喜欢这个,因为你的系统会随着时间而改变,你必须相应地关注它。
有趣的是,如果 HASH MATCH 实际数据与估计数据有很大差异,这可能意味着您的统计数据已过时,您现有的索引需要重建。
【讨论】:
以上是关于SQL Server 中的 SQL 查询优化的主要内容,如果未能解决你的问题,请参考以下文章
WHERE 子句中的 SQL 查询子选择优化 (SQL Server)