如何加速此SQL查询
首先,感谢您提前提供的任何提示或建议。我不是一个程序员,但我也没有任何其他方式来访问我的数据进行分析,所以我一直在学习(大部分是通过搜索StackOverflow和Google) 因此,下面的查询按预期工作,但速度很慢。我想我有地方可以优化代码,但我已经在拍自己的背,让它工作,所以我的想法。有没有办法加快速度 其基本思想是将预算数据和实际数据作为ID,零表示每个ID的时间(因此这是一个与时间无关的比较),并计算预算与实际累积绩效的比率 编辑:使用SQL Server Management Studio 2008 R2,添加了执行计划 注意:表变量仅用于测试代码。满标度代码中使用的永久表如何加速此SQL查询,sql,sql-server,sql-server-2008,query-optimization,Sql,Sql Server,Sql Server 2008,Query Optimization,首先,感谢您提前提供的任何提示或建议。我不是一个程序员,但我也没有任何其他方式来访问我的数据进行分析,所以我一直在学习(大部分是通过搜索StackOverflow和Google) 因此,下面的查询按预期工作,但速度很慢。我想我有地方可以优化代码,但我已经在拍自己的背,让它工作,所以我的想法。有没有办法加快速度 其基本思想是将预算数据和实际数据作为ID,零表示每个ID的时间(因此这是一个与时间无关的比较),并计算预算与实际累积绩效的比率 编辑:使用SQL Server Management Stu
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%。这些表扫描都是针对您的表变量
@dailybecast
和@DailyActual
。不幸的是,您不能在表变量上创建索引,除非它们是创建唯一索引的副作用,但我怀疑这对您没有帮助
您可以在临时表上创建索引,我建议您尝试将代码转换为使用临时表,创建缺少的索引,看看是否有帮助。创建适当的索引也可能有助于降低排序成本,因为排序成本占YRU最昂贵查询的63%。如果允许,我建议您设置这些表的一些较小版本,并尝试添加其他索引。每个表可能有10000条记录,ID和D_DATE的值不同,因此可以得到一些有代表性的数据。也许可以创建一个单独的、较小的数据库,让您自由支配 我想你需要一些额外的索引。例如,以下代码按
D_DATE
进行排序(这来自您的预算CTE):
尝试使用相同的列创建第二个非主索引,但顺序为D_DATE
和ID
另一件可能花费很大的事情是生成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或一组较小的数据库表中汇编所需的数字,这些表可以随着表的增长使用其他数据进行更新
希望这能有所帮助 编辑您的问题,并粘贴执行计划。如果您包括RDBMS和至少主要版本(例如:SQL Server 2012、Oracle 11i等),也会有所帮助。谢谢。我不知道如何粘贴执行计划,所以我只是链接了它的一张图片(因为我也不能发布图片):
float
如果你想表示金额,它很少是正确的数据类型。如果可以的话,我会改为使用十进制。关于浮点的观点仍然有效:它不应该在大多数业务情况下使用,因为它不精确。如果不切换到十进制,将无法得到想要的结果。Float适用于刻度比精度更重要的情况,或者需要表示非常非常小的数字,不能用十进制来表示。对不起,我应该提到表变量“@DailyBudget”和“@DailyActuals”只是为了测试而使用非机密数据运行查询。这些是实时代码中的永久SQL表。您是在D_日期而不是ID上排序的。我很确定,如果您创建一些额外的索引,您将看到性能改进。嗯,不确定您的确切意思。你的意思不仅仅是表中的属性吗?这两个表都是用以下主键创建的:CONSTRAINT[dailybecudent\u primary\u KEY]主键集群([ID]ASC[D\u DATE]ASC)和[primary]上的(PAD\u INDEX=OFF、STATISTICS\u norecocompute=OFF、IGNORE\u DUP\u KEY=OFF、ALLOW\u ROW\u LOCKS=ON、ALLOW\u PAGE\u LOCKS=ON)和[primary])您需要一个非聚集索引,其中包含您正在排序/筛选的其他列。谢谢!好建议。我有一种感觉,这种缓慢与我正在做的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
)