[英]How to speed up this SQL query
首先,感謝提前的任何提示或建議。 我不是程序員,但我也沒有任何其他方式來訪問我的數據進行分析,所以我一直在學習(大多數是通過搜索StackOverflow和Google)。
所以下面的查詢按預期工作,但它只是很慢。 我認為我有可以優化代碼的地方,但我已經在拍攝自己的背面,因為它使它工作,所以我沒有想法。 關於如何加快速度的任何想法?
基本思想是它需要預算數據和ID的實際數據,每個時間的零時間(因此它是一個與時間無關的比較),並計算預算與實際累積性能的比率。
編輯 :使用SQL Server Management Studio 2008 R2,添加了執行計划
注意 :表變量僅用於測試代碼。 全尺寸代碼中使用的永久表。
DECLARE @DailyBudget TABLE ( ID varchar(30), D_Date datetime, A float, B float)
DECLARE @DailyActuals TABLE ( ID varchar(30), D_Date datetime, A float, B float)
Insert into @DailyActuals (ID, D_Date, A, B)
Values
('J3PJKFWDBK', '5/20/2013', 300,1301)
,('J3PJKFWDBK', '5/21/2013', 290,1351)
,('J3PJKFWDBK', '5/23/2013', 283,1320)
Insert into @DailyBudget (ID, D_Date, A, B)
Values
('J3PJKFWDBK', '5/1/2013', 263,1401)
,('J3PJKFWDBK', '5/2/2013', 260,1390)
,('J3PJKFWDBK', '5/3/2013', 257,1380)
;WITH Budgets AS
(SELECT ID, D_Date, A, B,
ROW_NUMBER() OVER(PARTITION BY ID ORDER BY D_DATE ASC) as 'RowNum' from @DailyBudget where not (A = 0 and B = 0) and D_Date > CONVERT(datetime, '2013-01-01 00:00:00.000', 102)
)
, Actuals AS
(SELECT ID, D_DATE, A, B,
ROW_NUMBER() OVER(PARTITION BY ID ORDER BY D_DATE ASC) as 'RowNum' from @DailyActuals where not (A = 0 and B = 0) and D_Date > CONVERT(datetime, '2013-01-01 00:00:00.000', 102)
)
, BudgetSum AS
(select t1.ID, t1.RowNum, SUM(t2.A) as [A], SUM(t2.B) as [B]
from Budgets as t1
inner join Budgets as t2 on t1.RowNum >= t2.RowNum and t1.ID = t2.ID
group by t1.ID, t1.RowNum, t1.A
)
, ActualSum AS
(select t1.ID, t1.RowNum, SUM(t2.A) as [A], SUM(t2.B) as [B]
from Actuals as t1
inner join Actuals as t2 on t1.RowNum >= t2.RowNum and t1.ID = t2.ID
group by t1.ID, t1.RowNum, t1.A
)
SELECT Budgets.ID, Budgets.D_DATE as [Budget_Date], Actuals.D_DATE as [Actual_Date],
--A
Budgets.A as [Budget_A], BudgetSum.A as [SumBudget_A],
Actuals.A as [Actual_A], ActualSum.A as [SumActual_A],
(case BudgetSum.A when 0 then 0 else (ActualSum.A/BudgetSum.A)end) as [A_Ratio],
--B
Budgets.B as [Budget_B], BudgetSum.B as [SumBudget_B],
Actuals.B as [Actual_B], ActualSum.B as [SumActual_B],
(case BudgetSum.B when 0 then 0 else (ActualSum.B/BudgetSum.B)end) as [B_Ratio]
FROM Budgets
inner join Actuals on (Actuals.RowNum = Budgets.RowNum and Actuals.ID = Budgets.ID)
inner join BudgetSum on (Actuals.RowNum = BudgetSum.RowNum and Actuals.ID = BudgetSum.ID)
inner join ActualSum on (Actuals.RowNum = ActualSum.RowNum and Actuals.ID = ActualSum.ID)
order by Budgets.ID, Budgets.RowNum
SQL Server 2008的執行計划:
有6個表掃描占據了最昂貴查詢的18%。 這些表掃描都是針對您的表變量@DailyBudget
和@DailyActual
。 遺憾的是,您無法在表變量上創建索引,除非它們是創建唯一索引的副作用,但我懷疑這不會對您有所幫助。
您可以在臨時表上創建索引,我建議您嘗試將代碼轉換為使用臨時表,創建缺少的索引並查看是否有幫助。 創建適當的索引也可能有助於您的排序成本占據yoru最昂貴查詢的63%。
我建議,如果您被允許這樣做,您可以設置這些表的一些較小版本,並嘗試添加其他索引。 每個表可能有10,000條記錄,ID和D_DATE的值不同,因此您可以獲得一些有代表性的數據。 也許你可以自由創建一個單獨的,較小的數據庫。
我懷疑你需要一些額外的索引。 例如,以下代碼按D_DATE
排序(這來自您的預算CTE):
SELECT ID, D_Date, A, B,
ROW_NUMBER() OVER(PARTITION BY ID ORDER BY D_DATE ASC) as 'RowNum'
from @DailyBudget
where not (A = 0 and B = 0)
and D_Date > CONVERT(datetime, '2013-01-01 00:00:00.000', 102)
嘗試使用相同的列創建第二個非主索引,但順序為D_DATE
和ID
。
另一件可能花費很多的事情是你生成RowNum
然后RowNum
進行分組,這要求查詢引擎以RowNum
順序對所有這些記錄進行排序。 我會嘗試這樣的事情:
WITH Budgets AS
(SELECT ID, D_Date, A, B
from @DailyBudget
where not (A = 0 and B = 0)
and D_Date > CONVERT(datetime, '2013-01-01 00:00:00.000', 102)
)
, BudgetSum AS
(select t1.ID, T1.d_date, SUM(t2.A) as [A], SUM(t2.B) as [B]
from Budgets as t1
inner join Budgets as t2 on t1.D_DATE >= t2.D_DATE and t1.ID = t2.ID
group by t1.ID, T1.D_DATE
)
它幾乎相同,但它利用了您已有的索引(主鍵),不需要計算,然后按RowNum
排序。
最后,你用來獲取截止日期的YTD數據的技術是完全有效的,但由於你的表有數百萬條記錄,你可能正在談論數十億條加入的記錄要處理。 這需要很長時間,這並不奇怪! 考慮使用一些臨時表來保存數據的子集,而不是一次性處理進入最終數字的每個記錄。 或者對查詢進行分區(按日期或按ID范圍),以便您可以多次運行更快的查詢並在Excel中組合所需的數字,或者在一組較小的數據庫表中,您可以使用其他數據作為表進行更新增長。
希望有些幫助。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.