Mau*_*cio 1 performance sql-server sql-server-2016 query-performance
我有一个返回 127K 行的 SQL Server 2016 查询。您可以在此处找到查询和查询计划。如果您还需要表结构,请告诉我。
我需要加入一个只有 20 行的表,作为其中一个产品的替代品。换句话说,我从主表中查询产品,但在某些条件下,其中一些可以被其他产品替换。
问题是,对于那个简单的表,我有 254K 的逻辑读取。我试过LEFT JOIN
和OUTER APPLY
。
关于如何替换它以避免大量逻辑读取的任何建议?只是提一下,只有 1 个产品有替代品。
仔细查看执行计划 XML,请注意这些有问题的统计信息:
<Wait WaitType="ASYNC_NETWORK_IO" WaitTimeMs="1328" WaitCount="403"/>
<QueryTimeStats CpuTime="353" ElapsedTime="1853"/>
Run Code Online (Sandbox Code Playgroud)
查询花费了 1.3 秒等待应用程序使用的结果。查询总共只运行了 1.8 秒。所以这里的主要问题是应用程序正在逐行使用这些 127k 结果。查询本身运行得相当快。
Forrest McDaniel 有一篇很好的博客文章展示了这个问题:两个简单的 ASYNC_NETWORK_IO 演示
答案的其余部分解决了问题的“逻辑读取”部分。
OUTER APPLY
'd 表 ( DBVAREKT
)上所有这些逻辑读取的原因在这里:
“索引查找”对连接的上输入上的每一行执行一次NESTED LOOPS
。因此,该索引 ( ID1
) 中有 127,329 次搜索,即使最后只返回了 302 个匹配行。
优化器通常不会选择在索引中进行那么多搜索,但它只认为上面的输入会有 82 行。做82次搜索肯定更合理。
解决此问题的一般方法是避免NESTED LOOPS
在该特定表上进行连接,因为这是问题的根源。为此,您可以使用连接提示,但我很难说应该在哪里应用提示。
Randi提到可能重写查询,将一些数据放入临时表,本质上将查询分解为更小的块,SQL Server 优化器可以更好地处理这些块。您可以OUTER APPLY
按如下方式分解:
SELECT
1756,
L.MADTYPE,
DBM.VNR1
INTO #results
FROM dbo.STDORDRE S
INNER JOIN dbo.STDORD STO ON sto.DATO = s.DATO
AND sto.KUNDE = s.KUNDE
LEFT JOIN dbo.STDORDML L ON L.ONR = s.ONR
CROSS APPLY (SELECT dbo.MCS_ClarionDateToSQL(D.DATO) SQL_DATO,
DATEPART(dw, dbo.MCS_ClarionDateToSQL(D.DATO)) DP, D.VNR1, D.DATO, D.LINE, D.KATALOGNR, D.VFAKTOR, D.MADTYPE FROM dbo.DBMENU D WHERE D.SNR = s.VARENR AND D.LINE = L.MENULINE) DBM
INNER JOIN dbo.DBKUNDE kun ON kun.NR = s.KUNDE
INNER JOIN dbo.DBKUNGRP dbk ON dbk.NR = kun.GRP
INNER JOIN dbo.DBVARE varm ON varm.NR = s.VARENR
INNER JOIN dbo.DBVARE var ON var.NR = DBM.VNR1
LEFT OUTER JOIN dbo.MENORDRE MEN ON MEN.KUNDE = s.KUNDE
AND MEN.DATO = DBM.DATO
AND MEN.LINIE = DBM.LINE
AND MEN.NR = s.MNR
WHERE 1 = 1
AND ( kun.UDSKREVET = 0
OR ( kun.UDSKREVET = 1
AND kun.UDSDATO >= 79627 ))
AND varm.TYPE = 9
AND varm.KPFIX = 0
AND s.ML = 1
AND DBM.DATO BETWEEN 79627 AND 79777
AND sto.TYPE = 1;
SELECT
1756,
L.MADTYPE,
DBM.VNR1
FROM #results RES
OUTER APPLY (SELECT MTY.PREC MTY_PREC,
MTY.NR MTY_NR ,
VAR1.PREC VAR1_PREC,
var1.VAR_PKG_ID VAR1_VAR_PKG_ID,
VAR1.NR VAR1_NR ,
VAR1.TYPE VAR1_TYPE,
VAR1.GRP VAR1_GRP
FROM dbo.DBVAREKT VKT
LEFT JOIN dbo.DBVARE VAR1 ON VAR1.PREC = VKT.TO_VARE_PREC
AND (ISNULL(VKT.MADTYPE,0) <> 0 )
LEFT JOIN dbo.DBMTYPE MTY ON MTY.PREC = VKT.TO_MADTYPE_PREC
WHERE 1 = 1
AND VKT.MADTYPE = RES.MADTYPE
AND VKT.VARENR = RES.VNR1
) OA;
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
932 次 |
最近记录: |