web-dev-qa-db-ja.com

月と年でグループ化する正しい方法は?

月(および年)でグループ化する必要があり、次のことを考えていました。

GROUP BY CAST(YEAR(tDate) AS NVARCHAR(4)) + '-' + CAST(MONTH(tDate) AS NVARCHAR(2))

しかし、私はウェブで次のようなものを見つけました:

GROUP BY YEAR(tDate), Month(tDate)

どちらも同等ですか? 2番目を使用する方が良いですか?

2

2番目のアプローチを使用する必要があります。文字列の連結と型変換はすべて、クエリに不要なCPUオーバーヘッドを追加するだけです。

Stack Overflowスキーマでこれを試すことができます。ユーザーのテーブルをクエリして、日付フィールドにサポートする非クラスター化インデックスを作成します。

CREATE NONCLUSTERED INDEX IX_CreationDate ON dbo.Users (CreationDate);

最初のアプローチの例を次に示します。

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));

そして 計画 と統計:

plan for query 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.

それを2番目のアプローチと比較します。

SELECT 
    YEAR(u.CreationDate), Month(u.CreationDate), 
    COUNT(*)
FROM dbo.Users u
GROUP BY YEAR(u.CreationDate), Month(u.CreationDate);

計画 とその統計は次のとおりです。

plan for query 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.

ご覧のとおり、文字列の連結/キャストのアプローチでは、わずかに多くのCPUが使用されます。他はすべて同じです。


ちなみに、dbo.Usersテーブルには約300,000行しかありません。約3,700,000行が含まれているdbo.Postsテーブルでこれと同じ演習を行うと、クエリが並列になり、2番目のアプローチのCPU節約がはるかに大きくなります。

したがって、一般的なケースでは、CPUに関して2番目のアプローチの方が優れているだけでなく、データサイズが大きくなるほど、スケーリングが向上するように見えます。

5
Josh Darnell