Sql-Server
左外連接 - 查詢計劃中的排序操作 - 調整這個簡單查詢的任何方法?
在處理以下查詢以回答此問題時:
具有以下表格:
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
我在下面得到類似這張圖片的東西,這正是我想要的。
但是生成的執行計劃有幾個排序和嵌套循環操作,如下圖所示。
這是一個非常簡單的操作,兩個表之間的左外連接,索引已經排序,因此我想知道是否可以簡化查詢計劃。
或者,我可以更改查詢程式碼。
為什麼我們在查詢計劃中需要
nested loops
2 次和2 次?sort
您有一個提供排序的索引,
B.DT
但
THE_ROW
該計劃首先使用此順序進行評估- 然後右手排序順序
F.DT
進行評估THE_NUMBER_OF_RECORDS_ON_THIS_DAY
- 最後,左手排序使事情恢復
B.DT
正常THE_TOTAL_VALUE_FOR_THE_DAY
。您可以通過簡單地更改 CTE 中列的順序來擺脫其中一種排序,以便
F.DT
最後出現的列(此不必要排序的連接項在此處)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
但是您可以通過更改 to 的定義來擺脫兩者CASE WHEN F.DT IS NULL THEN 0 ELSE COUNT(*) OVER (PARTITION BY B.DT ) END
因此它使用與其餘功能相同的分區定義。
這不應該改變您的範例中的任何內容,因為您的
CASE
表達式0
無論如何都會分配給任何不匹配的行。至於計劃的其餘部分,請參閱分區和公共子表達式假離線
(事後計劃沒有排序)