SQL Server:通过许多连接关系优化效率

时间:2016-11-07 12:32:28

标签: sql-server

我有SQL Server代码,需要很长时间才能运行结果。在过去,花了15分钟。但最近,由于累积的销售数据,可能需要2个小时才能得到结果!!

因此,我想就如何优化代码获得一些建议:

代码结构很简单:只是为不同时间段和每个SKU获取不同地区的销售额。 (我在这里删除了一些代码,是为每种没有尺寸的材料找到不同的SKU)。

非常感谢您的帮助。

enter image description here

主要代码结构如下,因为它几乎相同,所以我只给出前两段作为例子:



SELECT SKU from [MATINFO]

-- Global Sales History Qty - All the years

			LEFT JOIN
			(
				SELECT SKU,SUM([SALES Qty]) as [Global Sales History Qty - All the years]
				from dbo.[SALES]
				
				where [PO] IS NOT NULL

				group by SKU

			)histORy

			on MATINFO.[SKU]=histORy.[SKU]


-- Global Sales History Qty - Past 2 years

	LEFT JOIN
			(
				SELECT (
					SELECT SKU,SUM([SALES Qty]) as [Global Sales History Qty - All the years]
						from dbo.[SALES]
				
						where [PO] IS NOT NULL

						group by SKU

				/* date range */
				and ([ORDER DATE] = '2015.11' OR [ORDER DATE] = '2015.12'  or [ORDER DATE] like '%2015%' OR [ORDER DATE] like '%2016%' ) 
				group by SKU
			)histORy2

			on MATINFO.[SKU]=histORy2.[SKU]

--Global Sales History Qty - Past 1 years

......SIMILAR TO THE CODE STRUCTURE AS ABOVE




2 个答案:

答案 0 :(得分:2)

性能不佳的最可能原因是使用字符串表示日期,如果是足够的索引则可能缺少。

喜欢'%2015%'

在全表扫描中使用具有相似结果的双端通配符,因此每次搜索不同的日期范围时子查询都会扫描整个表。使用临时表不能解决潜在的问题。

[稍后补充]

原始查询结构的另一个方面可能会减少您需要的数据扫描次数 - 使用“条件聚合”

e.g。这是原始查询的精简版

    SELECT
            SKU
    FROM [MATINFO]
    -- Global Sales History Qty - All the years
    LEFT JOIN (SELECT
                    SKU
                  , SUM([SALES Qty]) AS [Global Sales History Qty - All the years]
            FROM dbo.[SALES]
            WHERE [PO] IS NOT NULL
            GROUP BY
                    SKU) histORy ON MATINFO.[SKU] = histORy.[SKU]
    -- Global Sales History Qty - Past 2 years
    LEFT JOIN (SELECT
                    SKU
                  , SUM([SALES Qty]) AS [Global Sales History Qty - Past 2 years]
            FROM dbo.[SALES]
            WHERE [PO] IS NOT NULL
            /* date range */
            AND [ORDER DATE] >= '20151101' AND [ORDER DATE] < '20161101'
            GROUP BY
                    SKU) histORy2 ON MATINFO.[SKU] = histORy2.[SKU]

这需要在dbo中进行2次完整的数据传递[SALES],但如果你在SUM()函数中使用case表达式,则只需要传递一次数据(在本例中)

SELECT
        SKU
      , SUM([SALES Qty])          AS [Qty_all_years]
      , SUM(CASE
                WHEN [ORDER DATE] >= '20151101' AND [ORDER DATE] < '20161101' 
                THEN [SALES Qty]
        END)                      AS [Qty_past_2_years]
FROM dbo.[SALES]
WHERE [PO] IS NOT NULL
GROUP BY
        SKU

我怀疑您可以将此逻辑应用于大多数列,并在与日期列和适当的索引配合使用时显着提高查询效率。

答案 1 :(得分:1)

扩展我的评论。请注意,这只是一个建议,如果运行得更快,则无法保证。

采用以下派生表histORy

SELECT SKU,SUM([SALES Qty]) AS [Global Sales History Qty - All the years]
FROM dbo.[SALES]
WHERE [PO] IS NOT NULL
GROUP BY SKU

在运行查询之前,在临时表中实现派生表:

SELECT SKU,SUM([SALES Qty]) AS [Global Sales History Qty - All the years]
INTO #histORy
FROM dbo.[SALES]
WHERE [PO] IS NOT NULL
GROUP BY SKU

然后在查询中使用临时表:

LEFT JOIN #histORy AS h ON MATINFO.[SKU]=h.[SKU]

在这种情况下,您可能希望在SKU字段上有一个索引,因此您可以自己创建临时表,在其上打一个索引,填充INSERT INTO #history... SELECT ...等。