CROSS APPLY vs OUTER APPLY разность скоростей
Я использовал CROSS APPLY для подключения к таблицам пользователей и GeoPhone, и все работало быстро, но теперь у меня есть пользователи с значениями NULL в столбце "Телефон". Cross apply пропускает эти строки в конечном выпуске. Поэтому я переключился на OUTER APPLY. Но он работает значительно медленнее (более чем в 15 раз медленнее, когда общее количество строк на выходе увеличилось всего на 1000).
SELECT TOP (10000) dbo.Users.Login, dbo.Users.Phone, GeoPhone.Country
FROM dbo.Users CROSS APPLY
(SELECT TOP 1 Country
FROM dbo.GeoPhone
WHERE dbo.Users.Phone <= dbo.GeoPhone.[End]) GeoPhone
Versus:
SELECT TOP (10000) dbo.Users.Login, dbo.Users.Phone, GeoPhone.Country
FROM dbo.Users OUTER APPLY
(SELECT TOP 1 Country
FROM dbo.GeoPhone
WHERE dbo.Users.Phone <= dbo.GeoPhone.[End]) GeoPhone
Я пытаюсь понять, почему. Как я вижу, план выполнения отличается. Но теоретически я не вижу никаких вычислений, которые могут вызвать такое замедление.
Любые идеи?
МОЙ ЗАКЛЮЧИТЕЛЬНЫЙ РЕШЕНИЕ:
SELECT TOP (10000) dbo.Users.Login, dbo.Users.Phone, GeoPhone.Country
FROM dbo.Users CROSS APPLY
(SELECT TOP 1 Country
FROM dbo.GeoPhone
WHERE ISNULL(dbo.Users.Phone, 0) <= dbo.GeoPhone.[End]) GeoPhone
Это присваивает фактическую страну для не нулевых телефонов и страны из первого диапазона для нулевых телефонов (что уже "НЕИЗВЕСТНО" для моего случая). По какой-то причине WHERE dbo.Users.Phone <= dbo.GeoPhone.[End] OR dbo.Users.Phone IS NULL
выполняет те же результаты, но значительно медленнее.
Пожалуйста, не стесняйтесь прокомментировать это.
Ответы
Ответ 1
CROSS APPLY является специфичным для MSSQL... Microsoft on APPLY
APPLY заставляет запрос правой стороны выполнять один раз за результат в левом вопросе. CROSS рассматривает только соответствующие строки, такие как INNER JOIN. Использование OUTER рассматривает все строки в левом вопросе. Дополнительные ряды пострадали.
Я рекомендую вам переформулировать ваш правый запрос, чтобы явно принимать NULL вместо использования OUTER APPLY.
Ответ 2
Вы можете попробовать следующее:
SELECT TOP (10000) dbo.Users.Login, dbo.Users.Phone, GeoPhone.Country
FROM dbo.Users CROSS APPLY
(SELECT TOP 1 Country
FROM dbo.GeoPhone
WHERE dbo.Users.Phone <= dbo.GeoPhone.[End]) GeoPhone
UNION ALL
SELECT TOP (10000) dbo.Users.Login, dbo.Users.Phone, NULL AS Country
FROM dbo.Users
WHERE dbo.Users.Phone IS NULL
Удостоверьтесь, что у вас есть индекс на dbo.Users.Phone