我有一个查询连接2表ReconCollaterlExternal
(1194994行)和ReconCollateralInternal
(888060行)。
所以这些不是大表,这里是查询:
DECLARE @asofdate DATE = '2018-08-29';
DECLARE @threshold INT = 25
SELECT A.* FROM (
SELECT ri.AsOfDate, ri.Portfoliocode, SUM( ABS(ri.netamount)) SumAbsEmcMtm, SUM( ABS(re.netamount)) SumAbsBrokerMtm,
100*(SUM( ABS(ri.netamount))- SUM( ABS(re.netamount)))/SUM( ABS(ri.netamount)) PctMtmBreak
FROM ReconCollateralExternal ri
INNER JOIN ReconCollateralInternal re ON re.portfoliocode = ri.portfoliocode AND re.AsOfDate = ri.AsOfDate
WHERE ri.asofdate = @asofdate GROUP BY ri.portfoliocode , ri.AsOfDate HAVING SUM( ABS(ri.netamount)) != 0
) A
WHERE ABS(A.PctMtmBreak) >= @threshold ORDER BY ABS(A.PctMtmBreak) DESC;
两张桌子上都有AsOfDate
,PortfolioCode
的索引。查询需要7秒才能运行,我觉得这太长了。
我感谢任何帮助如何加快查询速度。
试试这个吧。由于每个表中都有适当的索引,我们可以单独过滤它们,然后聚合而不是sorg + join,然后加入聚合值。
DECLARE @asofdate DATE = '2018-08-29';
DECLARE @threshold INT = 25
SELECT
@asofdate AsOfDate,
A.Portfoliocode,
A.SumAbsEmcMtm,
A.SumAbsBrokerMtm,
A.PctMtmBreak
FROM
(
SELECT
ri.Portfoliocode, ri.SumAbsEmcMtm, re.SumAbsBrokerMtm,
100*(ri.SumAbsEmcMtm- re.SumAbsBrokerMtm)/ri.SumAbsEmcMtm PctMtmBreak
FROM
(
SELECT
ri.portfoliocode,
SUM(ABS(ri.netamount)) SumAbsEmcMtm
FROM ReconCollateralExternal ri
WHERE ri.asofdate = @asofdate
GROUP BY ri.portfoliocode
HAVING SUM( ABS(ri.netamount)) != 0
) ri
INNER JOIN
(
SELECT
re.portfoliocode,
SUM(ABS(re.netamount)) SumAbsBrokerMtm
FROM ReconCollateralInternal re
WHERE re.asofdate = @asofdate
GROUP BY re.portfoliocode
) re ON re.portfoliocode = ri.portfoliocode
) A
WHERE ABS(A.PctMtmBreak) >= @threshold
ORDER BY ABS(A.PctMtmBreak) DESC;
试试看。
这是您的查询(重新格式化了一下):
SELECT ri.AsOfDate, ri.Portfoliocode, SUM( ABS(ri.netamount)) as SumAbsEmcMtm, SUM( ABS(re.netamount)) as SumAbsBrokerMtm,
100*(SUM( ABS(ri.netamount))- SUM( ABS(re.netamount)))/SUM( ABS(ri.netamount)) as PctMtmBreak
FROM ReconCollateralExternal ri INNER JOIN
ReconCollateralInternal re
ON re.portfoliocode = ri.portfoliocode AND re.AsOfDate = ri.AsOfDate
WHERE ri.asofdate = @asofdate
GROUP BY ri.portfoliocode, ri.AsOfDate
HAVING SUM( ABS(ri.netamount)) <> 0 AND
100*(SUM( ABS(ri.netamount))- SUM( ABS(re.netamount)))/SUM( ABS(ri.netamount)) >= @threshold
ORDER BY PctMtmBreak DESC;
(子查询不会影响性能。我只是删除了它,因为我更容易想象处理。在外部HAVING
中使用别名会使子查询合理。)
从JOIN
s和WHERE
条件的索引开始。我建议:
ReconCollateralExternal(asofdate, portfoliocode, netamount)
ReconCollateralInternal(portfoliocode, asofdate)
我将netamount
放在第一个索引中,因此索引覆盖了查询(即没有数据页面查找)。
这可能会或可能不会带来很大的性能提升。这取决于GROUP BY
处理的数据量。
HAVING SUM( ABS(ri.netamount)) != 0
是否足够早在这里踢,我猜它确实是由于计算标量和过滤器操作在查询计划中的顺序...但是,我宁愿更明确地说明它。GROUP BY
列上没有必要使用AsOfDate
,因为它是一个常数。EG
CREATE INDEX idx_test ON ReconCollateralExternal (AsOfDate, PortofolioCode) INCLUDE (NetAmount)
CREATE INDEX idx_test ON ReconCollateralInternal (AsOfDate, PortofolioCode) INCLUDE (NetAmount)
请记住,没有免费午餐这样的东西:索引可能会使查询运行得更快(?)但是它会对表上的插入/更新/删除操作产生(小)性能影响别处!
查询将是这样的:
DECLARE @asofdate DATE = '2018-08-29';
DECLARE @threshold INT = 25
SELECT Portfoliocode,
AsOfDate = @asofdate,
SumAbsEmcMtm,
SumAbsBrokerMtm,
100 * (SumAbsEmcMtm - SumAbsBrokerMtm) / SumAbsEmcMtm PctMtmBreak
FROM (SELECT ri.Portfoliocode,
SUM( ABS(ri.NetAmount)) SumAbsEmcMtm,
SUM( ABS(re.NetAmount)) SumAbsBrokerMtm
-- 100 * (SUM (ABS(ri.NetAmount)) - SUM( ABS(re.netamount))) / SUM( ABS(ri.netamount)) PctMtmBreak
FROM ReconCollateralExternal ri
JOIN ReconCollateralInternal re
ON re.PortfolioCode = ri.PortfolioCode
AND re.AsOfDate = @asofdate -- ri.AsOfDate
WHERE ri.asofdate = @asofdate
GROUP BY ri.PortfolioCode
HAVING SUM( ABS(ri.NetAmount)) != 0
) A
WHERE ABS(100 * (SumAbsEmcMtm - SumAbsBrokerMtm) / SumAbsEmcMtm ) >= @threshold
ORDER BY ABS(100 * (SumAbsEmcMtm - SumAbsBrokerMtm) / SumAbsEmcMtm ) DESC;
PS:请记住,当您在区分大小写的服务器上部署此代码时,它将无法编译,例如Portofolio Code!= portofolio代码