Я обнаружил проблему с обработкой MS SQL Server CROSS APPLY
.
База данных, с которой я работаю, имеет систему ценообразования со следующей схемой:
Сервис -> Модель цены <- Компонент цены (<i> '->' обозначаетВнешний ключ, указывающий на таблицу )
Некоторые ценовые модели имеют "пошаговое ценообразование", что означает, что когда параметр количества достигает различных порогов, цена будет увеличиваться (1-3 единицы - это цена А, 4-8 единиц - цена B и т. Д.).
Проблема, с которой я столкнулся, заключается в том, что INNER JOIN
между [Service] и [Price Component] в [Price Model ID] создает дублирующиеся строки, поскольку я на самом деле не использую цены в PriceКомпонент, просто еще одно поле в таблице, одинаковое для каждой из строк [Компонент цены].
SELECT *
FROM [Service] s
INNER JOIN [Price Component] pc
ON s.[Price Model Id] = pc.[Price Model Id]
Логическим решением этой проблемы является замена INNER JOIN
на CROSS APPLY
, который делает это:
SELECT *
FROM [Service] s
CROSS APPLY (SELECT TOP 1 *
FROM [Price Component] pc
WHERE s.[Price Model Id] = pc.[Price Model Id]
) AS pc
Проблема заключается в том, что эффективность полностью разрушается внекоторые другие соединения, казалось бы, не связаны с этим изменением.Если посмотреть на план выполнения, объединение, которое раньше занимало 2,3 цикла, теперь занимает 4,8 миллиона циклов.
Я попытался добавить DISTINCT
к исходному запросу (поскольку он не использует уникальные данные из таблицы [Компонент цены], и это функциональное решение, за исключением того, что он в четыре раза увеличивает время выполнения. IЯ также пытался вернуть только необходимое мне значение из таблицы [Price Component], но, похоже, это не очень помогает:
SELECT *
FROM [Service] s
CROSS APPLY (SELECT DISTINCT pc.moneyUnitId
FROM [Price Component] pc
WHERE s.[Price Model Id] = pc.[Price Model Id]
) AS pc
Странно, но изменение CROSS APPLY
на OUTER APPLY
исправляетпроблемы с другими объединениями, но не позволяют использовать CROSS APPLY (как я понимаю, в основном это разница между INNER JOIN
и OUTER JOIN
).
Есть ли у кого-нибудь мысли илипонимание того, что может вызвать безумное увеличение сложности с CROSS APPLY
?
ОБНОВЛЕНИЕ
Итак, после прочтения еще немного о том, как интерпретировать план выполнения, яВы узнали следующее:
Оригинальный запрос (с использованием INNER JOIN
s) - это длинная серия вложенных циклов, которая начинается с любых данных фильтра, которые вы ей предоставляете.Пока фильтр работает с индексированными полями.
Модифицированный запрос (с использованием CROSS APPLY
) представляет собой более длинный ряд хэш-соответствий и объединяет все предоставленные вами таблицы, кроме таблиц с фильтрами, затемприменяет фильтры в последнюю очередь.Всегда медленнее смерти.
Рабочий модифицированный запрос (с OUTER APPLY
), делает то же самое, что и оригинал, но не исключает результаты, которые не совпадают с WHEREпункт.Так же быстро, как и оригинал.
Итак, проблема в том, почему CROSS APPLY
меняет план, чтобы объединить все таблицы перед запрошенным фильтром?