为什么连接两个 table 变量会显着增加 SQL Server 2012 中的执行时间
Why joining two table variables significantly increases execution time in SQL Server 2012
我正在将数据提取到两个 table 变量 @PremiumData
和 @LossData
中。加入列是 ControlNo
.
如果我 运行 它们分开,填充 @PremiumData
的执行时间是 3 秒,填充 @LossData
的执行时间是 0 秒。
但是当我通过 left join
将它们连接在一起时,执行时间增加到 01:07!分钟。
可以在这里找到查询计划:https://www.brentozar.com/pastetheplan/?id=Syd564Tnf
DECLARE
@EffectiveDateFrom DATETIME = '2012-04-01',
@EffectiveDateTo DATETIME = '2018-04-30'
DECLARE @PremiumData TABLE (
ControlNo int,
PolicyNumber varchar(50),
EffectiveDate datetime,
ExpirationDate datetime,
ProducerName varchar(300),
Premium money
)
DECLARE @LossData TABLE (
ControlNo int,
Losses money
)
INSERT INTO @PremiumData
SELECT
INV.QuoteControlNum,
tblQuotes.PolicyNumber,
tblQuotes.EffectiveDate,
(SELECT TOP 1 Q.ExpirationDate
FROM tblQuotes Q
WHERE Q.ControlNo = tblQuotes.ControlNo
ORDER BY Q.QuoteID DESC) as ExpirationDate,
tblProducers.ProducerName,
(SELECT ISNULL(SUM(tblFin_InvoiceDetails.AmtBilled), 0)
FROM tblFin_InvoiceDetails
WHERE (tblFin_InvoiceDetails.ChargeType = 'P')
AND (tblFin_InvoiceDetails.InvoiceNum = INV.InvoiceNum)) AS Premium
FROM
tblFin_Invoices INV
INNER JOIN
tblQuotes ON INV.QuoteID = tblQuotes.QuoteID
INNER JOIN
tblProducerLocations ON INV.ProducerLocationGUID = tblProducerLocations.ProducerLocationGUID
LEFT OUTER JOIN
tblProducers WITH (NOLOCK) ON tblProducerLocations.ProducerGUID = dbo.tblProducers.ProducerGUID
WHERE
(INV.Failed = 0)
AND (DATEDIFF(dd, tblQuotes.EffectiveDate, ISNULL(@EffectiveDateTo, tblQuotes.EffectiveDate)) >= 0)
AND (DATEDIFF(dd, ISNULL(@EffectiveDateFrom, tblQuotes.EffectiveDate), tblQuotes.EffectiveDate) >= 0)
AND dbo.tblQuotes.CompanyLocationGUID IN ('32828BB4-E1FA-489F-9764-75D8AF7A78F1',--"Plaza Insurance Company"
'54A8FCCD-C7FE-4642-9C22-3A25207CDAEE' -- Watford
)
INSERT INTO @LossData
SELECT
CPI.ControlNumber,
SUM(CRP.ResPayAmount) as [Losses]
FROM
tblClaims_Claim C
INNER JOIN
tblClaims_PolicyInformation CPI ON CPI.ClaimId = C.ClaimId
INNER JOIN
tblClaims_ReservePayments CRP ON CRP.ClaimId = C.ClaimId
GROUP BY
CPI.ControlNumber--,
/* Joining @PremiumData and @LossData*/
SELECT
p.PolicyNumber,
CONVERT(VARCHAR(11),p.EffectiveDate,101) as EffectiveDate,
YEAR(EffectiveDate) as EffectiveYear,
MONTH(EffectiveDate) as EffectiveMonth,
SUBSTRING('JAN FEB MAR APR MAY JUN JUL AUG SEP OCT NOV DEC ', (MONTH(EffectiveDate) * 4) - 3, 3) as MonthShort,
'Q' + CONVERT(CHAR(1),DATEPART(QUARTER, p.EffectiveDate)) as Quarter,
p.ProducerName,
SUM(p.Premium) as Premium,
ISNULL(ROUND(dbo.fn_EarnedPremiumCalcExtendedPolicies(SUM(Premium), EffectiveDate, ExpirationDate, 0, GETDATE()), 2), SUM(Premium)) AS EarnedPremium,
ISNULL(l.Losses,0) as Losses,
ISNULL(SUM(l.Losses), 0) / NULLIF(ISNULL(ROUND(dbo.fn_EarnedPremiumCalcExtendedPolicies(SUM(Premium), EffectiveDate, ExpirationDate, 0, GETDATE()), 2), SUM(Premium)),0) as LossRatio
FROM
@PremiumData p
LEFT JOIN
@LossData l ON p.ControlNo = l.ControlNo
GROUP BY --p.ControlNo
p.PolicyNumber,
p.EffectiveDate,
p.ExpirationDate,
p.ProducerName,
l.Losses
这也是我关心的执行计划部分:
查看您链接的执行计划中 table 变量的估计行数。估计是 1 行,但实际行数要高得多。
问题是基数估计有偏差。我想查询会导致溢出到临时数据库中,因为初始内存授予太低了。还有一些helpful answers here
尝试使用温度 tables 而不是 table 变量。
您也可以尝试在 insert
语句(table 变量或临时 table)的末尾添加 option(recompile)
,这应该会改进您的基数估计。
根据您的编辑进行编辑:这种类型的基数估计也很差。之所以存在排序,是因为您正在对连接两个 table 变量的查询进行分组。
我正在将数据提取到两个 table 变量 @PremiumData
和 @LossData
中。加入列是 ControlNo
.
如果我 运行 它们分开,填充 @PremiumData
的执行时间是 3 秒,填充 @LossData
的执行时间是 0 秒。
但是当我通过 left join
将它们连接在一起时,执行时间增加到 01:07!分钟。
可以在这里找到查询计划:https://www.brentozar.com/pastetheplan/?id=Syd564Tnf
DECLARE
@EffectiveDateFrom DATETIME = '2012-04-01',
@EffectiveDateTo DATETIME = '2018-04-30'
DECLARE @PremiumData TABLE (
ControlNo int,
PolicyNumber varchar(50),
EffectiveDate datetime,
ExpirationDate datetime,
ProducerName varchar(300),
Premium money
)
DECLARE @LossData TABLE (
ControlNo int,
Losses money
)
INSERT INTO @PremiumData
SELECT
INV.QuoteControlNum,
tblQuotes.PolicyNumber,
tblQuotes.EffectiveDate,
(SELECT TOP 1 Q.ExpirationDate
FROM tblQuotes Q
WHERE Q.ControlNo = tblQuotes.ControlNo
ORDER BY Q.QuoteID DESC) as ExpirationDate,
tblProducers.ProducerName,
(SELECT ISNULL(SUM(tblFin_InvoiceDetails.AmtBilled), 0)
FROM tblFin_InvoiceDetails
WHERE (tblFin_InvoiceDetails.ChargeType = 'P')
AND (tblFin_InvoiceDetails.InvoiceNum = INV.InvoiceNum)) AS Premium
FROM
tblFin_Invoices INV
INNER JOIN
tblQuotes ON INV.QuoteID = tblQuotes.QuoteID
INNER JOIN
tblProducerLocations ON INV.ProducerLocationGUID = tblProducerLocations.ProducerLocationGUID
LEFT OUTER JOIN
tblProducers WITH (NOLOCK) ON tblProducerLocations.ProducerGUID = dbo.tblProducers.ProducerGUID
WHERE
(INV.Failed = 0)
AND (DATEDIFF(dd, tblQuotes.EffectiveDate, ISNULL(@EffectiveDateTo, tblQuotes.EffectiveDate)) >= 0)
AND (DATEDIFF(dd, ISNULL(@EffectiveDateFrom, tblQuotes.EffectiveDate), tblQuotes.EffectiveDate) >= 0)
AND dbo.tblQuotes.CompanyLocationGUID IN ('32828BB4-E1FA-489F-9764-75D8AF7A78F1',--"Plaza Insurance Company"
'54A8FCCD-C7FE-4642-9C22-3A25207CDAEE' -- Watford
)
INSERT INTO @LossData
SELECT
CPI.ControlNumber,
SUM(CRP.ResPayAmount) as [Losses]
FROM
tblClaims_Claim C
INNER JOIN
tblClaims_PolicyInformation CPI ON CPI.ClaimId = C.ClaimId
INNER JOIN
tblClaims_ReservePayments CRP ON CRP.ClaimId = C.ClaimId
GROUP BY
CPI.ControlNumber--,
/* Joining @PremiumData and @LossData*/
SELECT
p.PolicyNumber,
CONVERT(VARCHAR(11),p.EffectiveDate,101) as EffectiveDate,
YEAR(EffectiveDate) as EffectiveYear,
MONTH(EffectiveDate) as EffectiveMonth,
SUBSTRING('JAN FEB MAR APR MAY JUN JUL AUG SEP OCT NOV DEC ', (MONTH(EffectiveDate) * 4) - 3, 3) as MonthShort,
'Q' + CONVERT(CHAR(1),DATEPART(QUARTER, p.EffectiveDate)) as Quarter,
p.ProducerName,
SUM(p.Premium) as Premium,
ISNULL(ROUND(dbo.fn_EarnedPremiumCalcExtendedPolicies(SUM(Premium), EffectiveDate, ExpirationDate, 0, GETDATE()), 2), SUM(Premium)) AS EarnedPremium,
ISNULL(l.Losses,0) as Losses,
ISNULL(SUM(l.Losses), 0) / NULLIF(ISNULL(ROUND(dbo.fn_EarnedPremiumCalcExtendedPolicies(SUM(Premium), EffectiveDate, ExpirationDate, 0, GETDATE()), 2), SUM(Premium)),0) as LossRatio
FROM
@PremiumData p
LEFT JOIN
@LossData l ON p.ControlNo = l.ControlNo
GROUP BY --p.ControlNo
p.PolicyNumber,
p.EffectiveDate,
p.ExpirationDate,
p.ProducerName,
l.Losses
这也是我关心的执行计划部分:
查看您链接的执行计划中 table 变量的估计行数。估计是 1 行,但实际行数要高得多。
问题是基数估计有偏差。我想查询会导致溢出到临时数据库中,因为初始内存授予太低了。还有一些helpful answers here
尝试使用温度 tables 而不是 table 变量。
您也可以尝试在 insert
语句(table 变量或临时 table)的末尾添加 option(recompile)
,这应该会改进您的基数估计。
根据您的编辑进行编辑:这种类型的基数估计也很差。之所以存在排序,是因为您正在对连接两个 table 变量的查询进行分组。