我有一个视图,其中有一个未编入索引的列在另一个查询中连接。我们无法在视图中创建索引,因为它使用外连接。
外部查询基本上是:
select * from SomeTable AS T INNER JOIN
v_SomeView AS V ON T.Column = V.Column
查询非常缓慢,通过一些实验,我们发现将查询更改为:
select * from SomeTable AS T INNER JOIN
(select TOP 10000000 * from v_SomeView) AS V ON T.Column = V.Column
加快了查询速度(10分钟到5秒左右)。
视图中只有大约1000行。
有人可以解释这里发生的事情会对性能产生如此巨大的影响吗?
执行计划:
以下是实际视图 v_SecurityClassificationResult :
SELECT rc.SecurityId, rc.Status, rc.ExpiryDate, rc.StartDate, rc.ClassificationValue AS RiskClass, sg.ClassificationValue AS SecurityGroup,
br.ClassificationValue AS BondRating, cur.ClassificationValue AS Currency, cod.ClassificationValue AS Country, reg.ClassificationValue AS Region
FROM dbo.SecurityClassificationResult AS rc LEFT OUTER JOIN
dbo.SecurityClassificationResult AS sg ON rc.SecurityId = sg.SecurityId AND rc.ExpiryDate = sg.ExpiryDate AND sg.SecurityClassificationFieldId =
(SELECT SecurityClassificationFieldId
FROM dbo.SecurityClassificationField
WHERE (ClassificationField = 'SecurityGroup')) LEFT OUTER JOIN
dbo.SecurityClassificationResult AS br ON rc.SecurityId = br.SecurityId AND sg.ExpiryDate = br.ExpiryDate AND br.SecurityClassificationFieldId =
(SELECT SecurityClassificationFieldId
FROM dbo.SecurityClassificationField
WHERE (ClassificationField = 'BondRating')) LEFT OUTER JOIN
dbo.SecurityClassificationResult AS cur ON rc.SecurityId = cur.SecurityId AND br.ExpiryDate = cur.ExpiryDate AND cur.SecurityClassificationFieldId =
(SELECT SecurityClassificationFieldId
FROM dbo.SecurityClassificationField
WHERE (ClassificationField = 'Currency')) LEFT OUTER JOIN
dbo.SecurityClassificationResult AS cod ON rc.SecurityId = cod.SecurityId AND cur.ExpiryDate = cod.ExpiryDate AND cod.SecurityClassificationFieldId =
(SELECT SecurityClassificationFieldId
FROM dbo.SecurityClassificationField
WHERE (ClassificationField = 'CountryOfDomicile')) LEFT OUTER JOIN
dbo.SecurityClassificationResult AS reg ON rc.SecurityId = reg.SecurityId AND cod.ExpiryDate = reg.ExpiryDate AND reg.SecurityClassificationFieldId =
(SELECT SecurityClassificationFieldId
FROM dbo.SecurityClassificationField
WHERE (ClassificationField = 'Region'))
WHERE (rc.SecurityClassificationFieldId =
(SELECT SecurityClassificationFieldId
FROM dbo.SecurityClassificationField
WHERE (ClassificationField = 'RiskClass')))
以及从中选择的另一个查询:
SELECT count(*)
FROM dbo.Fund_RelevantSecurity AS FRS INNER JOIN
dbo.SourceSystemImportLog AS SSIL ON FRS.SourceSystemImporLogtId = SSIL.SourceSystemImporLogtId INNER JOIN
dbo.FundInstanceHolding AS FIH ON FRS.FundInstanceHoldingId = FIH.FundInstanceHoldingId INNER JOIN
dbo.FundInstance AS FI ON FIH.FundInstanceId = FI.FundInstanceId INNER JOIN
dbo.SourceSystemImportLog AS SSILOrig ON SSILOrig.SourceSystemImporLogtId = FI.SourceSystemImportLogId INNER JOIN
dbo.Security ON FRS.SecurityId = dbo.Security.SecurityId INNER JOIN
dbo.Fund ON FRS.FundId = dbo.Fund.FundId INNER JOIN
dbo.BusinessUnitFund ON dbo.Fund.FundId = dbo.BusinessUnitFund.FundId INNER JOIN
dbo.BusinessUnit ON dbo.BusinessUnit.BusinessUnitId = dbo.BusinessUnitFund.BusinessUnitId RIGHT OUTER JOIN
(select top 2147483647 * from dbo.v_SecurityClassificationResult) AS classificationResult ON FRS.SecurityId = classificationResult.SecurityId AND GETDATE()
<= classificationResult.ExpiryDate AND GETDATE() >= classificationResult.StartDate
WHERE (SSIL.ImportStatusId <> 5)
答案 0 :(得分:0)
我建议您重建索引并刷新统计信息。通过做TOP N你的优化器采取另一个计划,似乎这个更好。尝试检查预期和实际的记录数量,以找出计划错误的位置。 另一件事是,如果重写视图,可能会获得更好的性能。您可以执行类似的操作(无法检查语法和逻辑,因为没有提供结构和数据):
SELECT
rc.SecurityId ,
rc.Status ,
rc.ExpiryDate ,
rc.StartDate ,
s.ClassificationValue AS RiskClass ,
MIN(CASE WHEN s.ClassificationValue = 'SecurityGroup' THEN s.ClassificationValue END) AS SecurityGroup ,
MIN(CASE WHEN s.ClassificationValue = 'BondRating' THEN s.ClassificationValue END) AS BondRating ,
MIN(CASE WHEN s.ClassificationValue = 'Currency' THEN s.ClassificationValue END) AS Currency ,
MIN(CASE WHEN s.ClassificationValue = 'CountryOfDomicile' THEN s.ClassificationValue END) AS Country ,
MIN(CASE WHEN s.ClassificationValue = 'Region' THEN s.ClassificationValue END) AS Region
FROM
dbo.SecurityClassificationResult AS rc
LEFT OUTER JOIN
(
SELECT s.ClassificationValue,
sf.ClassificationField
FROM dbo.SecurityClassificationResult AS s
JOIN dbo.SecurityClassificationField AS sf
ON sf.SecurityClassificationFieldId = s.SecurityClassificationFieldId
WHERE sf.ClassificationField IN ( 'SecurityGroup', 'BondRating', 'Currency', 'CountryOfDomicile' 'Region')
) s
ON s.SecurityId = rc.SecurityId
WHERE
( rc.SecurityClassificationFieldId = (
SELECT
SecurityClassificationFieldId
FROM
dbo.SecurityClassificationField
WHERE
( ClassificationField = 'RiskClass' )
) )
GROUP BY rc.SecurityId ,
rc.Status ,
rc.ExpiryDate ,
rc.StartDate ,
s.ClassificationValue