SQL: левое соединение против подзапроса CASE - что более эффективно

Какой из них вы, ребята, считаете более эффективным (с меньшей нагрузкой)?

SELECT t1.a, 
(CASE
WHEN t1.p=1 THEN t2.g 
WHEN t1.p=2 THEN t3.g
END) as v

FROM t1
LEFT JOIN t2 ON t1.x=t2.x
LEFT JOIN t3 ON t1.y=t3.y

ИЛИ ЖЕ

SELECT 
t1.a, t2.v 

FROM t1    
outer apply (
SELECT v= CASE
WHEN t1.p=1 THEN (SELECT v FROM t2 WHERE t1.x=t2.x)
WHEN t1.p=2 THEN (SELECT v FROM t3 WHERE t1.y=t3.y)
END
) t2

Просто хочу выяснить, как работает sql engine..

[Что я пытаюсь изучить в этом вопросе] В первом запросе таблицы t2 а такжеt3 будет вызываться всегда, но во 2-м запросе они будут вызываться только в том случае, если регистр совпадает (и, следовательно, будет меньше load = проверено только 2 таблицы вместо 3 в строке)?

2 ответа

Поместите дополнительный предикат t1.p= в каждом левом соединении, чтобы они стали взаимоисключающими по мере необходимости для результата. Это позволило бы использовать coalesce вместо выражения case (но с выражением case все в порядке, это просто опция).

В вашем примере нет веской причины использовать оператор apply, и хотя они оптимизируют лучше, чем коррелированные подзапросы, помещенные в предложение select, они остаются коррелированными подзапросами. На мой взгляд, если нет веской причины для "более экзотического" варианта, не используйте его. Так что, не используйте здесь оператор apply, используйте более стандартное левое соединение.

SELECT
    t1.a
  , COALESCE(t2.g,t3.g) AS v
FROM t1
LEFT JOIN t2 ON t1.x = t2.x AND t1.p = 1
LEFT JOIN t3 ON t1.y = t3.y AND t1.p = 2
;

Однако, если у вас была функциональная потребность в одной (или предписанном количестве) строк из этих взаимосвязанных подзапросов, у вас была бы веская причина использовать заявку, например

SELECT
    t1.a
  , t2.v
FROM t1
OUTER APPLY (
        SELECT
            CASE
                WHEN t1.p = 1 THEN (
                        SELECT TOP(1) t2.g FROM t2  -- top 
                        WHERE t1.x = t2.x
                        ORDER BY t2.z               -- order
                    )
                WHEN t1.p = 2 THEN (
                        SELECT TOP(1) t3.g FROM t3  -- top
                        WHERE t1.y = t3.y
                        ORDER BY t3.z               -- order
                    )
            END AS v
    ) t2

Независимо от мнения, использование планов выполнения - лучший способ сравнить параметры запроса.

Я бы пошел с left join, но напишите это как:

SELECT t1.a, COALESCE(t2.g, t3.g) as v
FROM t1 LEFT JOIN
     t2
     ON t1.x = t2.x AND t1.p = 1 LEFT JOIN
     LEFT JOIN t3
     ON t1.y = t3.y AND t1.p = 2;

Эта логика не обязательно в точности эквивалентна вашей логике, но я подозреваю, что этот запрос выполняет то, что вы намерены. (Например, если t2.g когда-либо NULL а также t1.p = 1тогда результаты не совпадают.)

Что касается производительности, LEFT JOIN дает оптимизатору больше возможностей для запроса, чем CASE выражение делает, так что, скорее всего, будет быстрее. Однако при правильной индексации все три запроса, вероятно, имеют хорошую производительность.

Другие вопросы по тегам