この質問に答えるために以下のクエリに取り組んでいる間:
データベースにとらわれない方法でグラフデータをクエリする方法
次のテーブルがあります。
CREATE TABLE [dbo].[#foo] (
[creation] DATETIME NOT NULL,
[value] MONEY NULL,
[DT] AS (CONVERT([date],[CREATION])) PERSISTED)
-- add a clustered index on the dt column
CREATE CLUSTERED INDEX CI_FOO ON #FOO(DT)
GO
参加のためのこの他のテーブル:
create table #bar (dt date primary key clustered)
go
しかし、次のクエリを実行すると:
WITH RADHE AS (
SELECT THE_ROW=ROW_NUMBER() OVER(PARTITION BY B.DT ORDER BY B.DT),
THE_DATE=B.dt,
THE_NUMBER_OF_RECORDS_ON_THIS_DAY=CASE WHEN F.DT IS NULL THEN 0 ELSE COUNT(*) OVER (PARTITION BY F.DT ) END ,
THE_TOTAL_VALUE_FOR_THE_DAY=COALESCE(SUM(F.VALUE) OVER (PARTITION BY b.DT ),0)
FROM #BAR B
LEFT OUTER JOIN #FOO F
ON B.dt = F.dt
)
--get rid of the duplicates and present the result
SELECT
THE_DATE,
THE_NUMBER_OF_RECORDS_ON_THIS_DAY,
THE_TOTAL_VALUE_FOR_THE_DAY
FROM RADHE
WHERE THE_ROW = 1
下の写真のようになりました。これはまさに私が探していたものです。
ただし、以下の図に示すように、生成された実行プランにはいくつかのソートおよびネストされたループ操作があります。
これは非常に単純な操作で、2つのテーブル間の左外部結合であり、インデックスは既に順序付けされているため、クエリプランを簡略化できるかどうか疑問に思っていました。
または、クエリコードを変更することもできます。
なぜ正確にnested loops
クエリプランで2回とsort
2回ですか?
B.DT
による順序付けを提供するインデックスがありますが、
THE_ROW
を評価しますF.DT
で並べ替えて、THE_NUMBER_OF_RECORDS_ON_THIS_DAY
を評価しますB.DT
のTHE_TOTAL_VALUE_FOR_THE_DAY
順に並べ替えます。CTEの列の順序を変更するだけで、並べ替えの1つを取り除くことができるので、F.DT
1が最後に表示されます( この不要な並べ替えの接続項目はここにあります )
WITH RADHE AS (
SELECT THE_ROW=ROW_NUMBER() OVER(PARTITION BY B.DT ORDER BY B.DT),
THE_DATE=B.dt ,
THE_TOTAL_VALUE_FOR_THE_DAY=COALESCE(SUM(F.VALUE) OVER (PARTITION BY b.DT ),0),
THE_NUMBER_OF_RECORDS_ON_THIS_DAY=CASE WHEN F.DT IS NULL THEN 0 ELSE COUNT(*) OVER (PARTITION BY F.DT ) END
FROM #BAR B
LEFT OUTER JOIN #FOO F
ON B.dt = F.dt
)
ただし、THE_NUMBER_OF_RECORDS_ON_THIS_DAY
の定義を次のように変更することで、両方を取り除くことができます。
CASE WHEN F.DT IS NULL THEN 0 ELSE COUNT(*) OVER (PARTITION BY B.DT ) END
したがって、他の関数と同じパーティション定義を使用します。
CASE
式はとにかく一致しない行に0
を割り当てるだけなので、この例では何も変更されません。
残りの計画については パーティショニングと共通部分式スプール を参照してください
(後でソートなしで計画)
あなたはこれを必要以上に難しくしていると思います
SELECT THE_DATE = B.dt,
THE_NUMBER_OF_RECORDS_ON_THIS_DAY = COUNT(F.DT),
THE_TOTAL_VALUE_FOR_THE_DAY = SUM(ISNULL(F.VALUE, 0))
FROM #BAR B
LEFT OUTER JOIN #FOO F
ON B.dt = F.dt
GROUP BY B.dt