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