SQL Server CASE表达式不短路吗?

时间:2018-10-17 04:04:40

标签: sql-server case query-optimization

是否有人可以帮助我们优化以下查询是合适的

根据执行平面,似乎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;

2 个答案:

答案 0 :(得分:1)

不要认为这是短路或短路。那是过程代码的心态,而不是基于集合的心态。

在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_2ID_VERPACKUNG_3CHARGE_NUMMER字段建立索引可能会有所帮助。您也许还可以使用CTE,临时表或表变量来帮助Sql Server更好地将这些数据缓存一次。

答案 1 :(得分:0)

如果不满足where的条件,则else将变为活动状态。如果总是这样,那么您将期望以下内容不返回任何行:

select *
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
WHERE lp.ID_VERPACKUNG_2 IS NULL 
AND lp.ID_VERPACKUNG_3 IS NULL