Geo*_*e K 4 performance join sql-server query-performance
这个查询在我的系统上运行了大约 15 秒。查询计划在这里。我相信主要问题就在这里,优化器选择嵌套循环并误认为基数:
表 _Reference65215 和 _InfoRg100966 分别有 454 和 3332 行。如果我在这里强制 SQL Server 使用哈希匹配,则执行时间会下降到 2 秒。
我不能在这里使用任何类型的提示,因为代码来自平台。该平台使用自己的语言,然后将其解释为 T-SQL。我可以更改查询。统计数据是最新的。Maxdop 1 是平台供应商的一般建议
选择嵌套循环的原因可能是什么以及如何解决它?也许还有其他值得关注的地方?
EXEC sp_executesql
N'SELECT TOP 45 T1._IDRRef,
T1._Marked,
T1._Number,
T1._Date_Time,
T1._Posted,
T1._Fld74271RRef,
CASE
WHEN T1._Fld74272RRef=@P1
THEN T1._Fld74307RRef
ELSE T1._Fld74272RRef
END,
T1._Fld74273,
T1._Fld74274RRef,
T1._Fld74281,
CASE
WHEN T1._Fld74272RRef=@P2
THEN 0x000100DD
WHEN T1._Fld74272RRef=@P3
OR T1._Fld74272RRef=@P4
OR T1._Fld74272RRef=@P5
THEN 0x0000FF7E
ELSE 0x0000FF3E
END,
CASE
WHEN T1._Fld74272RRef=@P6
THEN T1._Fld74284RRef
WHEN T1._Fld74272RRef=@P7
OR T1._Fld74272RRef=@P8
OR T1._Fld74272RRef=@P9
THEN T1._Fld74285RRef
ELSE T1._Fld74282RRef
END,
T1._Fld74289RRef,
T1._Fld74303,
CASE
WHEN T1._Fld74333RRef IN( SELECT TOP 1 T12._IDRRef
AS Q_001_F_000RRef
FROM dbo._Reference65527 T12
WHERE T12._Fld67386=@P10
ORDER BY T12._Fld124008 )
THEN @P11
WHEN T1._Fld74333RRef IN( SELECT TOP 1 T13._IDRRef
AS Q_002_F_000RRef
FROM dbo._Reference65527 T13
WHERE T13._Fld67386=@P12
ORDER BY T13._Fld124008 DESC )
THEN @P13
ELSE @P14
END,
CASE
WHEN ISNULL( CAST( T2.Fld109931Balance_ AS NUMERIC(27, 2) ), @P15 )<=@P16
AND T1._Posted=0x01
AND T1._Fld74271RRef<>@P17
THEN 0x01
ELSE 0x00
END,
CASE
WHEN T11._Fld101929 IS NULL
THEN @P18
WHEN T11._Fld101929=0x01
THEN @P19
ELSE @P20
END
FROM dbo._Document65911 T1
LEFT OUTER JOIN
(
SELECT T3._Fld109927_TYPE
AS Fld109927_TYPE,
T3._Fld109927_RTRef
AS Fld109927_RTRef,
T3._Fld109927_RRRef
AS Fld109927_RRRef,
CAST( SUM( T3._Fld109931 ) AS NUMERIC(27, 2) )
AS Fld109931Balance_
FROM dbo._AccumRgT109935 T3
WHERE T3._Fld67386=@P21
AND EXISTS
(
SELECT 0x01
AS Q_001_F_000_
FROM dbo._Reference65291 T4
INNER JOIN
dbo._Reference65215 T5
ON T4._Fld118298=@P22
AND EXISTS
(
SELECT 0x01
AS Q_004_F_000_
FROM dbo._InfoRg107349 T6
WHERE T6._Fld67386=@P23
AND T6._Fld107350RRef=T4._IDRRef
AND T6._Fld107351RRef=T5._IDRRef
)
AND T5._IDRRef IN
(
SELECT T7._Reference65215_IDRRef
AS Q_005_F_000RRef
FROM dbo._Reference65215_VT116326 T7
INNER JOIN
dbo._InfoRg106545 T8
ON T8._Fld106547_TYPE=0x08
AND T8._Fld106547_RTRef=0x0000FFD5
AND T8._Fld106547_RRRef=@P24
AND T8._Fld106546_TYPE=T7._Fld116328_TYPE
AND T8._Fld106546_RTRef=T7._Fld116328_RTRef
AND T8._Fld106546_RRRef=T7._Fld116328_RRRef
WHERE T7._Fld67386=@P25
AND T8._Fld67386=@P26
)
WHERE T5._Fld67386=@P27
AND 0x08<>0x01
AND CASE
WHEN EXISTS
(
SELECT 0x01
AS Q_002_F_000_
FROM dbo._InfoRg100966 T9
WHERE T9._Fld67386=@P28
AND T9._Fld100967RRef=T5._IDRRef
AND T9._Fld100968_TYPE=0x08
AND T9._Fld100968_RTRef=0x0000FF7E
AND T9._Fld100968_RRRef=T3._Fld109930RRef
)
THEN 0x01
ELSE 0x00
END=CASE
WHEN EXISTS
(
SELECT 0x01
AS Q_003_F_000_
FROM dbo._InfoRg100973 T10
WHERE T10._Fld67386=@P29
AND T10._Fld100974RRef=T5._IDRRef
AND T10._Fld100975_TYPE=0x08
AND T10._Fld100975_RTRef=0x0000FF7E
AND T10._Fld100976=0x00
)
THEN 0x01
ELSE 0x00
END
)
AND T3._Period=@P30
AND T3._Fld109931<>@P31
AND T3._Fld109931<>@P32
GROUP BY T3._Fld109927_TYPE,
T3._Fld109927_RTRef,
T3._Fld109927_RRRef
HAVING CAST( SUM( T3._Fld109931 ) AS NUMERIC(27, 2) )<>0.0
) T2
ON T2.Fld109927_TYPE=0x08
AND T2.Fld109927_RTRef=0x00010177
AND T2.Fld109927_RRRef=T1._IDRRef
LEFT OUTER JOIN
dbo._InfoRg101927 T11
ON(0x08=T11._Fld101928_TYPE
AND 0x00010177=T11._Fld101928_RTRef
AND T1._IDRRef=T11._Fld101928_RRRef)
AND T11._Fld67386=@P33
WHERE T1._Fld67386=@P34
AND EXISTS
(
SELECT 1
FROM
(
SELECT 1
AS SDBL_DUMMY
) SDBL_DUAL
LEFT OUTER JOIN
dbo._Document65911_VT74348 T14
ON T1._IDRRef=T14._Document65911_IDRRef
AND T14._Fld67386=T1._Fld67386
LEFT OUTER JOIN
dbo._Reference65239 T15
ON T1._Fld74344_TYPE=0x08
AND T1._Fld74344_RTRef=0x0000FED7
AND T1._Fld74344_RRRef=T15._IDRRef
AND T15._Fld67386=@P35
LEFT OUTER JOIN
dbo._Reference65757 T16
ON T1._Fld74284RRef=T16._IDRRef
AND T16._Fld67386=@P36
WHERE EXISTS
(
SELECT 0x01
AS Q_001_F_000_
FROM dbo._Reference65291 T17
INNER JOIN
dbo._Reference65215 T18
ON T17._Fld118298=@P37
AND EXISTS
(
SELECT 0x01
AS Q_015_F_000_
FROM dbo._InfoRg107349 T19
WHERE T19._Fld67386=@P38
AND T19._Fld107350RRef=T17._IDRRef
AND T19._Fld107351RRef=T18._IDRRef
)
AND T18._IDRRef IN
(
SELECT T20._Reference65215_IDRRef
AS Q_016_F_000RRef
FROM dbo._Reference65215_VT116326 T20
INNER JOIN
dbo._InfoRg106545 T21
ON T21._Fld106547_TYPE=0x08
AND T21._Fld106547_RTRef=0x0000FFD5
AND T21._Fld106547_RRRef=@P39
AND T21._Fld106546_TYPE=T20._Fld116328_TYPE
AND T21._Fld106546_RTRef=T20._Fld116328_RTRef
AND T21._Fld106546_RRRef=T20._Fld116328_RRRef
WHERE T20._Fld67386=@P40
AND T21._Fld67386=@P41
)
LEFT OUTER JOIN
dbo._Reference65493 T22
ON @P42=T22._IDRRef
AND T22._Fld67386=@P43
WHERE T18._Fld67386=@P44
AND 0x08<>0x01
AND CASE
WHEN EXISTS
(
SELECT 0x01
AS Q_002_F_000_
FROM dbo._InfoRg100966 T23
WHERE T23._Fld67386=@P45
AND T23._Fld100967RRef=T18._IDRRef
AND T23._Fld100968_TYPE=0x08
AND T23._Fld100968_RTRef=0x0000FF7E
AND T23._Fld100968_RRRef=T1._Fld74270RRef
)
THEN 0x01
ELSE 0x00
END=CASE
WHEN EXISTS
(
SELECT 0x01
AS Q_003_F_000_
FROM dbo._InfoRg100973 T24
WHERE T24._Fld67386=@P46
AND T24._Fld100974RRef=T18._IDRRef
AND T24._Fld100975_TYPE=0x08
AND T24._Fld100975_RTRef=0x0000FF7E
AND T24._Fld100976=0x00
)
THEN 0x01
ELSE 0x00
END
AND 0x08<>0x01
AND NOT(NOT EXISTS
(
SELECT 0x01
AS Q_004_F_000_
FROM dbo._InfoRg99652 T25
WHERE T25._Fld67386=@P47
AND T25._Fld99653_TYPE=0x08
AND T25._Fld99653_RTRef=0x0000FFD5
AND T25._Fld99653_RRRef=T1._Fld74289RRef
AND T25._Fld99654_TYPE=0x08
AND T25._Fld99654_RTRef=0x0000FFD5
AND T25._Fld99654_RRRef=@P48
)
AND NOT CASE
WHEN EXISTS
(
SELECT top 356165165156165165 0x01
AS Q_005_F_000_
FROM dbo._InfoRg100966 T26
INNER JOIN ---------------------------------------------------------------------------
dbo._InfoRg99652 T27
ON T26._Fld100967RRef=T18._IDRRef
AND T26._Fld100968_TYPE=T27._Fld99654_TYPE
AND T26._Fld100968_RTRef=T27._Fld99654_RTRef
AND T26._Fld100968_RRRef=T27._Fld99654_RRRef
AND T27._Fld99653_TYPE=0x08
AND T27._Fld99653_RTRef=0x0000FFD5
AND T27._Fld99653_RRRef=T1._Fld74289RRef
WHERE T26._Fld67386=@P49
AND T27._Fld67386=@P50
)
THEN 0x01
ELSE 0x00
END=CASE
WHEN EXISTS
(
SELECT 0x01
AS Q_006_F_000_
FROM dbo._InfoRg100973 T28
WHERE T28._Fld67386=@P51
AND T28._Fld100974RRef=T18._IDRRef
AND T28._Fld100975_TYPE=0x08
AND T28._Fld100975_RTRef=0x0000FFD5
AND T28._Fld100976=0x00
)
THEN 0x01
ELSE 0x00
END)
AND 0x08<>0x01
AND CASE
WHEN EXISTS
(
SELECT 0x01
AS Q_007_F_000_
FROM dbo._InfoRg100966 T29
WHERE T29._Fld67386=@P52
AND T29._Fld100967RRef=T18._IDRRef
AND T29._Fld100968_TYPE=0x08
AND T29._Fld100968_RTRef=0x000106FA
AND T29._Fld100968_RRRef=T1._Fld74272RRef
)
THEN 0x01
ELSE 0x00
END=CASE
WHEN EXISTS
(
SELECT 0x01
AS Q_008_F_000_
FROM dbo._InfoRg100973 T30
WHERE T30._Fld67386=@P53
AND T30._Fld100974RRef=T18._IDRRef
AND T30._Fld100975_TYPE=0x08
AND T30._Fld100975_RTRef=0x000106FA
AND T30._Fld100976=0x00
)
THEN 0x01
ELSE 0x00
END
AND CASE
WHEN T1._Fld74272RRef=@P54
OR T1._Fld74272RRef=@P55
THEN CASE
WHEN CASE
WHEN T14._Fld74350RRef IS NULL
THEN 0x01
ELSE CASE
WHEN T14._Fld74350RRef IS NOT NULL
THEN 0x08
END
END<>0x01
THEN 0x01
ELSE 0x00
END
WHEN T1._Fld74272RRef=@P56
THEN CASE
WHEN 0x08<>0x01
THEN 0x01
ELSE 0x00
END
ELSE 0x01
END=0x01
AND CASE
WHEN T1._Fld74272RRef=@P57
OR T1._Fld74272RRef=@P58
THEN CASE
WHEN 0x08<>0x01
AND CASE
WHEN EXISTS
(
SELECT 0x01
AS Q_011_F_000_
FROM dbo._InfoRg100966 T31
WHERE T31._Fld67386=@P59
AND T31._Fld100967RRef=T18._IDRRef
AND T31._Fld100968_TYPE=0x08
AND T31._Fld100968_RTRef=0x0001007C
AND T31._Fld100968_RRRef=ISNULL( T15._Fld116737RRef, @P60 )
)
THEN 0x01
ELSE 0x00
END=CASE
WHEN EXISTS
(
SELECT 0x01
AS Q_012_F_000_
FROM dbo._InfoRg100973 T32
WHERE T32._Fld67386=@P61
AND T32._Fld100974RRef=T18._IDRRef
AND T32._Fld100975_TYPE=0x08
AND T32._Fld100975_RTRef=0x0001007C
AND T32._Fld100976=0x00
)
THEN 0x01
ELSE 0x00
END
AND 0x08<>0x01
AND CASE
WHEN EXISTS
(
SELECT 0x01
AS Q_013_F_000_
FROM dbo._InfoRg100966 T33
WHERE T33._Fld67386=@P62
AND T33._Fld100967RRef=T18._IDRRef
AND T33._Fld100968_TYPE=0x08
AND T33._Fld100968_RTRef=0x00010103
AND T33._Fld100968_RRRef=ISNULL( T15._Fld116803RRef, @P63 )
)
THEN 0x01
ELSE 0x00
END=CASE
WHEN EXISTS
(
SELECT 0x01
AS Q_014_F_000_
FROM dbo._InfoRg100973 T34
WHERE T34._Fld67386=@P64
AND T34._Fld100974RRef=T18._IDRRef
AND T34._Fld100975_TYPE=0x08
AND T34._Fld100975_RTRef=0x00010103
AND T34._Fld100976=0x00
)
THEN 0x01
ELSE 0x00
END
THEN 0x01
ELSE 0x00
END
ELSE CASE
WHEN 0x08<>0x01
AND CASE
WHEN EXISTS
(
SELECT 0x01
AS Q_009_F_000_
FROM dbo._InfoRg100966 T35
WHERE T35._Fld67386=@P65
AND T35._Fld100967RRef=T18._IDRRef
AND T35._Fld100968_TYPE=0x08
AND T35._Fld100968_RTRef=0x0001007C
AND T35._Fld100968_RRRef=T1._Fld74288RRef
)
THEN 0x01
ELSE 0x00
END=CASE
WHEN EXISTS
(
SELECT 0x01
AS Q_010_F_000_
FROM dbo._InfoRg100973 T36
WHERE T36._Fld67386=@P66
AND T36._Fld100974RRef=T18._IDRRef
AND T36._Fld100975_TYPE=0x08
AND T36._Fld100975_RTRef=0x0001007C
AND T36._Fld100976=0x00
)
THEN 0x01
ELSE 0x00
END
THEN 0x01
ELSE 0x00
END
END=0x01
AND (0x08<>0x01
OR T1._Fld74284RRef=T22._Fld123105RRef)
)
)
ORDER BY T1._Date_Time DESC,
T1._IDRRef DESC',
N'@P1 varbinary(16),@P2 varbinary(16),@P3 varbinary(16),@P4 varbinary(16),@P5 varbinary(16),@P6 varbinary(16),@P7 varbinary(16),@P8 varbinary(16),@P9 varbinary(16),@P10 numeric(10),@P11 numeric(10),@P12 numeric(10),@P13 numeric(10),@P14 numeric(10),@P15 numeric(10),@P16 numeric(10),@P17 varbinary(16),@P18 numeric(10),@P19 numeric(10),@P20 numeric(10),@P21 numeric(10),@P22 nvarchar(4000),@P23 numeric(10),@P24 varbinary(16),@P25 numeric(10),@P26 numeric(10),@P27 numeric(10),@P28 numeric(10),@P29 numeric(10),@P30 datetime2(3),@P31 numeric(10),@P32 numeric(10),@P33 numeric(10),@P34 numeric(10),@P35 numeric(10),@P36 numeric(10),@P37 nvarchar(4000),@P38 numeric(10),@P39 varbinary(16),@P40 numeric(10),@P41 numeric(10),@P42 varbinary(16),@P43 numeric(10),@P44 numeric(10),@P45 numeric(10),@P46 numeric(10),@P47 numeric(10),@P48 varbinary(16),@P49 numeric(10),@P50 numeric(10),@P51 numeric(10),@P52 numeric(10),@P
我会添加OPTION(USE HINT 'DISABLE_OPTIMIZER_ROWGOAL')到查询以禁用行目标。
发现行目标使用的最简单方法是使用TOP()运算符,用于在您的情况下尽快返回 45 行。
循环连接的使用在这里更常见,因为它估计较小的结果集并使用非阻塞运算符。
在大多数情况下,行目标会有所帮助,但是对于复杂的大型查询,我看到它们过去很麻烦。
通过禁用这些行目标,您应该为整个查询获得更优化的计划。
您还可以通过添加OPTION(QUERYTRACEON 4138)到查询的末尾来禁用它。
我试图删除 TOP 45 部分 - 现在它的工作时间不到 1 秒。我在哪里可以更深入地了解行目标?
TOP(45)在这种情况下,删除已删除的行目标并提高性能。
Paul White 有一些关于行目标的很棒的博客文章。第 1 部分和第 2 部分可以在此处和此处找到。优化器内部也有:深度行目标。
如果您无法更改查询,则可以为特定查询添加计划指南以禁用行目标。
另一种在不添加提示的情况下删除行目标的方法
根据声明:
要记住的第二个一般点是,仅当目标低于常规估计值时才设置行目标
再次来自:在执行计划中设置和识别行目标
您可以TOP()使用如此高的数字指定一个无意义的数字,以至于不会设置行目标,然后将您的实际内容包裹TOP()起来。
例如:
SELECT TOP(5) *
FROM(
SELECT TOP(99999999999) *
FROM dbo.table
ORDER BY column ASC
) AS A;
Run Code Online (Sandbox Code Playgroud)
更多例子:
简而言之,TOP(5)rowgoal 被top(99999999999)内部查询中更高的值覆盖,导致在我的示例中只剩下 2 个实际的行目标,一个在TOP(99999999)运算符上:
SELECT TOP(5) *
FROM(
SELECT TOP(99999999999) *
FROM dbo.table
ORDER BY column ASC
) AS A;
Run Code Online (Sandbox Code Playgroud)
嵌套循环运算符上的一个紧跟在第二个TOP()完全匹配EstimateRows
PhysicalOp="Top" LogicalOp="Top" EstimateRows="5" EstimateRowsWithoutRowGoal="9.4199"
Run Code Online (Sandbox Code Playgroud)
对于像您这样的行目标问题的真实示例,由于行目标,我能够使用非阻塞运算符(例如 NL 连接)更改计划形状TOP(5):
屏幕截图中未显示实际性能问题
使用TOP(999999999)方法散列匹配运算符。
在应用行目标禁用提示时,此计划形状与查询匹配。
我仍然希望添加查询提示而不是编写两个TOP()s。但是,如果您不被允许或不能,这可能会有所帮助。