我有一个查询,该查询将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秒钟才能运行,我认为这太长了。
我非常感谢您如何加快查询速度。
答案 0 :(得分:1)
尝试这个。由于每个表中都有适当的索引,因此我们可以分别过滤它们,然后聚合而不是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;
尝试一下。
答案 1 :(得分:0)
这是您的查询(经过重新格式化):
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
和WHERE
条件的索引开始。我建议:
ReconCollateralExternal(asofdate, portfoliocode, netamount)
ReconCollateralInternal(portfoliocode, asofdate)
我将netamount
放在第一个索引中,以便索引覆盖查询(即没有数据页查找)。
这可能会或可能不会大大提高性能。这取决于为GROUP BY
处理多少数据。
答案 2 :(得分:0)
HAVING SUM( ABS(ri.netamount)) != 0
是否在这里足够早地启动,我猜想是由于查询计划中的Compute Scalar和Filter操作的顺序而导致的……我仍然希望对此更加明确。GROUP BY
列上不需要AsOfDate
,因为它是一个常数。例如
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:请记住,当您将此代码部署在区分大小写的服务器上时,由于例如PortofolioCode!= portofoliocode