按月和年分组的正确方法?

Eri*_*tas 2 performance sql-server sql-server-2012 query-performance

我需要按月(和年)分组,我在想:

GROUP BY CAST(YEAR(tDate) AS NVARCHAR(4)) + '-' + CAST(MONTH(tDate) AS NVARCHAR(2))
Run Code Online (Sandbox Code Playgroud)

但是我在网上找到了类似的东西:

GROUP BY YEAR(tDate), Month(tDate)
Run Code Online (Sandbox Code Playgroud)

两者是等价的吗?用第二种比较好?

Jos*_*ell 6

你应该采用第二种方法。所有的字符串连接和类型转换只是将不必要的 CPU 监听添加到查询中。

我可以在 Stack Overflow 模式上试试这个。我将查询用户的表,并在日期字段上创建一个支持的非聚集索引:

CREATE NONCLUSTERED INDEX IX_CreationDate ON dbo.Users (CreationDate);
Run Code Online (Sandbox Code Playgroud)

这是第一种方法的示例:

SELECT 
    CAST(YEAR(u.CreationDate) AS NVARCHAR(4)) 
        + '-' 
        + CAST(MONTH(u.CreationDate) AS NVARCHAR(2)), 
    COUNT(*)
FROM dbo.Users u
GROUP BY 
    CAST(YEAR(u.CreationDate) AS NVARCHAR(4)) 
        + '-' 
        + CAST(MONTH(u.CreationDate) AS NVARCHAR(2));
Run Code Online (Sandbox Code Playgroud)

以及计划和统计数据:

查询 1 的计划

Table 'Worktable'. Scan count 0, logical reads 0
Table 'Workfile'. Scan count 0, logical reads 0
Table 'Users'. Scan count 1, logical reads 675

 SQL Server Execution Times:
   CPU time = 203 ms,  elapsed time = 258 ms.
Run Code Online (Sandbox Code Playgroud)

将其与第二种方法进行比较:

SELECT 
    YEAR(u.CreationDate), Month(u.CreationDate), 
    COUNT(*)
FROM dbo.Users u
GROUP BY YEAR(u.CreationDate), Month(u.CreationDate);
Run Code Online (Sandbox Code Playgroud)

以下是该计划的计划和统计数据:

查询 2 的计划

Table 'Worktable'. Scan count 0, logical reads 0
Table 'Workfile'. Scan count 0, logical reads 0
Table 'Users'. Scan count 1, logical reads 675

 SQL Server Execution Times:
   CPU time = 125 ms,  elapsed time = 229 ms.
Run Code Online (Sandbox Code Playgroud)

如您所见,字符串 concat / cast 方法使用的 CPU 略多。其他一切都是一样的。


顺便说一下,dbo.Users 表中只有大约 300,000 行。在 dbo.Posts 表上执行相同的练习,其中包含大约 3,700,000 行,查询并行进行,并且第二种方法的 CPU 节省变得更加重要。

因此,在一般情况下,第二种方法不仅在 CPU 方面更好,而且随着数据大小的增加,它似乎也能更好地扩展。