sql-server - SQL Server CASE 表达式不会短路吗?
问题描述
如果有人可以帮助我们优化以下查询,则合适
根据执行平面,无论条件如何,else 部分子查询似乎总是在执行。
不会CASE
短路吗?为什么它正在执行,即使它不是必需的?
IF OBJECT_ID('#Calculation') IS NOT NULL
DROP TABLE #Calculation;
SELECT
Result.IdDeckungsbeitrag,
Result.wert AS Wert,
REPLACE(@Formula, '<#PackagingCosts> ', Result.wert) AS Kalkulation
INTO
#Calculation
FROM
(SELECT
deck.IdDeckungsbeitrag,
CASE
WHEN lp.ID_VERPACKUNG_2 IS NULL
AND lp.ID_VERPACKUNG_3 IS NULL
THEN vg.VERPACKUNGSKOSTEN_PRO_EINHEIT * deck.Menge
ELSE
(
SELECT SUM(temp.me) * vg.VERPACKUNGSKOSTEN_PRO_EINHEIT
FROM
(
SELECT SUM(gv.MENGE) AS me
FROM dbo.KUNDENRECHNUNG_POSITION krp
LEFT JOIN dbo.LIEFERSCHEIN_POSITION lp
ON lp.ID_LIEFERSCHEIN_POSITION = krp.ID_LIEFERSCHEIN_POSITION
LEFT JOIN dbo.GEBINDE_VERLADEN gv
ON gv.ID_LIEFERSCHEIN_POSITION = lp.ID_LIEFERSCHEIN_POSITION
LEFT JOIN dbo.MATERIAL_BESTAND mb
ON mb.ID_MATERIAL_BESTAND = gv.ID_MATERIAL_BESTAND
LEFT JOIN dbo.MATERIAL_GEBINDE mg
ON mg.ID_MATERIAL_BESTAND = mg.ID_MATERIAL_BESTAND
WHERE mg.CHARGE_NUMMER = deck.Charge
GROUP BY mg.ID_VERPACKUNG
) temp
)
END AS wert
FROM @DeckungsbeitragCalculationPositions_TVP deck
LEFT JOIN dbo.KUNDENRECHNUNG_POSITION krp
ON krp.ID_KUNDENRECHNUNG_POSITION = deck.IdDeckungsbeitrag
LEFT JOIN dbo.LIEFERSCHEIN_POSITION lp
ON lp.ID_LIEFERSCHEIN_POSITION = krp.ID_LIEFERSCHEIN_POSITION
LEFT JOIN dbo.VERPACKUNG vg
ON vg.ID_VERPACKUNG = lp.ID_VERPACKUNG_1
WHERE deck.IdMandant = @Id_Mandant
) Result;
解决方案
不要认为它是否短路。这是一种程序代码思维方式,而不是基于集合的思维方式。
在 SQL 中,实际的“执行”发生在表或索引扫描和查找、哈希匹配、排序等领域。将不同表中的数据拉入工作集中,最终将产生所需的关系结果。
没有看到任何实际的或预计的执行计划,在这种情况下(没有双关语),我怀疑查询优化器认为首先在内存中生成这个结果集是最有效的:
SELECT mg.ID_VERPACKUNG, mg.CHARGE_NUMMER, SUM(gv.MENGE) AS me
FROM dbo.KUNDENRECHNUNG_POSITION krp
LEFT JOIN dbo.LIEFERSCHEIN_POSITION lp
ON lp.ID_LIEFERSCHEIN_POSITION = krp.ID_LIEFERSCHEIN_POSITION
LEFT JOIN dbo.GEBINDE_VERLADEN gv
ON gv.ID_LIEFERSCHEIN_POSITION = lp.ID_LIEFERSCHEIN_POSITION
LEFT JOIN dbo.MATERIAL_BESTAND mb
ON mb.ID_MATERIAL_BESTAND = gv.ID_MATERIAL_BESTAND
LEFT JOIN dbo.MATERIAL_GEBINDE mg
ON mg.ID_MATERIAL_BESTAND = mg.ID_MATERIAL_BESTAND
GROUP BY mg.ID_VERPACKUNG, mg.CHARGE_NUMMER
这是子句的子查询ELSE
,减去WHERE
子句条件,并添加了附加信息SELECT
以使匹配更有效。如果查询优化器不能确信在WHEN
高比例的时间内满足子句,它可能认为生成这个更大的ELSE
集合一次以根据需要进行匹配更有效。换句话说,如果它认为无论如何都必须运行该子查询,它可能会尝试为所有可能的数据预加载它。
我们对您的数据库知之甚少,无法提出真正的解决方案,但围绕 、 和 字段建立索引ID_VERPACKUNG_2
可能ID_VERPACKUNG_3
会CHARGE_NUMMER
有所帮助。您还可以使用 CTE、临时表或表变量来帮助 Sql Server 更好地缓存这些数据一次。
推荐阅读
- java - 从 Spring Boot 1 升级到 Spring Boot 2 后,对每个 HTTP 请求进行不必要的日志记录
- php - PHP 7.2.23 MongoDB\Driver\Manager 数组集群返回空
- sql - 替换oracle数据库值范围内的字符
- c++ - 是否可以限制 C++ 17 并行“for_each”的线程数?
- python - H2O 以不同的方式解析文件类型
- c - 将字符串数组传递给在所有级别下施加 const-ness 的函数的最佳方法
- python - 如何针对烧瓶中的 jsonschema 验证 json?
- c# - 使用 Jodit WYSIWYG 和 .NET 上传图像
- javascript - 使用 Radio 值设置类背景颜色?
- android - 怎么可能收到收取 0 美元的订单?谷歌开发者控制台