J'utilisais CROSS APPLY pour rejoindre les utilisateurs et les tables GeoPhone et tout fonctionnait rapidement, mais maintenant j'ai des utilisateurs avec des valeurs NULL dans la colonne Téléphone. L'application croisée ignore ces lignes dans la sortie finale. Je suis donc passé à OUTER APPLY. Mais cela fonctionne beaucoup plus lentement (plus de 15 fois plus lentement lorsque le nombre total de lignes en sortie n'a augmenté que de 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
Contre:
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
J'essaie de comprendre pourquoi. Comme je le vois, le plan d'exécution est différent. Mais théoriquement, je ne vois aucun calcul pouvant provoquer un tel ralentissement.
Des idées?
MA SOLUTION FINALE:
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
Cela affecte le pays réel pour les téléphones non nuls et le pays de la première plage pour les téléphones nuls (qui est déjà "INCONNU" pour mon cas). Pour certaines raisons WHERE dbo.Users.Phone <= dbo.GeoPhone.[End] OR dbo.Users.Phone IS NULL
donne les mêmes résultats mais beaucoup plus lentement.
N'hésitez pas à commenter cela.
CROSS APPLY est spécifique à MSSQL ... Microsoft on APPLY
APPLY fait exécuter la requête de droite une fois par résultat dans la requête de gauche. CROSS considère uniquement les lignes correspondantes comme INNER JOIN. L'utilisation d'OUTER considère toutes les lignes de la requête de gauche. Les rangs supplémentaires font mal.
Je vous recommande de reformuler votre requête de droite pour accepter explicitement les valeurs NULL au lieu d'utiliser OUTER APPLY.
Vous pouvez essayer ceci:
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
Assurez-vous d'avoir un index sur dbo.Users.Phone