CROSS APPLYを使用してUsersテーブルとGeoPhoneテーブルを結合していましたが、すべて高速で動作していましたが、Phone列にNULL値を持つユーザーがいます。クロスアプライは、最終出力でこれらの行をスキップします。そこで、外部適用に切り替えました。ただし、動作が大幅に遅くなります(出力の行の総数が1000だけ増加した場合、15倍以上遅くなります)。
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
対:
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
これにより、Null以外の電話には実際の国が、Null電話には最初の範囲の国が割り当てられます(私の場合は既に「不明」です)。何らかの理由で WHERE dbo.Users.Phone <= dbo.GeoPhone.[End] OR dbo.Users.Phone IS NULL
は同じ結果を出しますが、非常に遅くなります。
これをコメントアウトしてお気軽に。
CROSS APPLYはMSSQL固有です... Microsoft on APPLY
APPLYにより、左側のクエリの結果ごとに右側のクエリが1回実行されます。 CROSSは、INNER JOINのような一致する行のみを考慮します。 OUTERを使用すると、左側のクエリのすべての行が考慮されます。余分な行が痛い。
OUTER APPLYを使用する代わりに、NULLを明示的に受け入れるように右側のクエリを再構築することをお勧めします。
これを試すことができます:
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にインデックスがあることを確認してください