簡體   English   中英

如何加快這個SQL查詢

[英]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的執行計划:

http://s11.postimg.org/ierhjgvv7/6_18_2013_10_17_26_AM.jpg

有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_DATEID

另一件可能花費很多的事情是你生成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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM