聚合 SQL SELECT 语句中的重复 CASE WHEN
Repetitive CASE WHEN in Aggregate SQL SELECT Statements
我正在努力降低我经常使用的查询的成本和大小,它看起来过于重复,不是最有效的处理方式。
简化表示如下:
SELECT [Year],
[Month],
COUNT(CASE WHEN Type = 'Quotation' THEN clientID ELSE NULL END),
COUNT(CASE WHEN Type = 'Purchase' THEN ClientID ELSE NULL END),
SUM(CASE WHEN Type = 'Purchase' THEN Cost ELSE NULL END)
...
FROM dbo.Example
GROUP BY [Year],[Month]
就尺寸和成本而言,我认为我必须能够 trim 缩小 CASE WHEN ... THEN ELSE NULL END
。有什么建议吗?
我正在使用 SQL Server 2008 R2,谢谢。
按类型制作视图怎么样? (报价、采购等)。这样,您可以逐个视图优化并进行连接查询以获得您想要的结果。
我认为这是 'rotate' 一个 table 的推荐方式。
查看 Microsoft 的这篇文章 -> https://support.microsoft.com/en-us/kb/175574
成本可能在 'Type' 列中,也许您可以将其编入索引 -> How to create an index for a string column in sql?
嗯,怎么了:
SELECT [Year],
[Month],
[Type],
COUNT(ClientID) "Count",
SUM(Cost) "TotalCost",
...
FROM dbo.Example
GROUP BY [Year],[Month],[Type]
你这样做的方式是去规范化它。这就是性能如此差的原因。当然,您在 Type = 'Quotation'
时生成 SUM(Cost)
并且您可能不需要它,但是添加通常不是查询性能的限制因素。
有什么理由让你必须每个[Year],[Month]
只有一个记录吗?
根据我的经验,当您遇到如此复杂且具有大量条件聚合的内容时,如果您以逐步的方式构建它,它会更快、更清晰。也就是说,拥有一个具有所需数据结构的 table 变量,并使用避免使用 CASE 语句的单个查询向其添加记录,并(希望)根据索引列进行记录选择。
因此,如果您有一个名为 @TypeTotals
的 table 变量,您可以这样做(使用您的简化示例):
INSERT INTO @TypeTotals
SELECT [Year],
[Month],
[Type],
COUNT(ClientID),
Null,
Null
FROM dbo.Example
WHERE [Type] = 'Quotation'
GROUP BY
[Year], [Month]
INSERT INTO @TypeTotals
SELECT [Year],
[Month],
[Type],
Null,
COUNT(ClientID),
SUM(Cost)
FROM dbo.Example
WHERE [Type] = 'Purchase'
GROUP BY
[Year], [Month]
... etc ...
然后您可以总结 @TypeTotals
的内容。
提高速度的关键是避免那些 CASE 语句(正如您已经知道的那样)并充分利用索引。
并进行实验。如果可以,请使用 Profiler,因为执行计划并不总是代表您真正获得的速度。
我正在努力降低我经常使用的查询的成本和大小,它看起来过于重复,不是最有效的处理方式。
简化表示如下:
SELECT [Year],
[Month],
COUNT(CASE WHEN Type = 'Quotation' THEN clientID ELSE NULL END),
COUNT(CASE WHEN Type = 'Purchase' THEN ClientID ELSE NULL END),
SUM(CASE WHEN Type = 'Purchase' THEN Cost ELSE NULL END)
...
FROM dbo.Example
GROUP BY [Year],[Month]
就尺寸和成本而言,我认为我必须能够 trim 缩小 CASE WHEN ... THEN ELSE NULL END
。有什么建议吗?
我正在使用 SQL Server 2008 R2,谢谢。
按类型制作视图怎么样? (报价、采购等)。这样,您可以逐个视图优化并进行连接查询以获得您想要的结果。
我认为这是 'rotate' 一个 table 的推荐方式。
查看 Microsoft 的这篇文章 -> https://support.microsoft.com/en-us/kb/175574
成本可能在 'Type' 列中,也许您可以将其编入索引 -> How to create an index for a string column in sql?
嗯,怎么了:
SELECT [Year],
[Month],
[Type],
COUNT(ClientID) "Count",
SUM(Cost) "TotalCost",
...
FROM dbo.Example
GROUP BY [Year],[Month],[Type]
你这样做的方式是去规范化它。这就是性能如此差的原因。当然,您在 Type = 'Quotation'
时生成 SUM(Cost)
并且您可能不需要它,但是添加通常不是查询性能的限制因素。
有什么理由让你必须每个[Year],[Month]
只有一个记录吗?
根据我的经验,当您遇到如此复杂且具有大量条件聚合的内容时,如果您以逐步的方式构建它,它会更快、更清晰。也就是说,拥有一个具有所需数据结构的 table 变量,并使用避免使用 CASE 语句的单个查询向其添加记录,并(希望)根据索引列进行记录选择。
因此,如果您有一个名为 @TypeTotals
的 table 变量,您可以这样做(使用您的简化示例):
INSERT INTO @TypeTotals
SELECT [Year],
[Month],
[Type],
COUNT(ClientID),
Null,
Null
FROM dbo.Example
WHERE [Type] = 'Quotation'
GROUP BY
[Year], [Month]
INSERT INTO @TypeTotals
SELECT [Year],
[Month],
[Type],
Null,
COUNT(ClientID),
SUM(Cost)
FROM dbo.Example
WHERE [Type] = 'Purchase'
GROUP BY
[Year], [Month]
... etc ...
然后您可以总结 @TypeTotals
的内容。
提高速度的关键是避免那些 CASE 语句(正如您已经知道的那样)并充分利用索引。
并进行实验。如果可以,请使用 Profiler,因为执行计划并不总是代表您真正获得的速度。