J'utilise Microsoft SQL Server 2008 (SP1, x64). J'ai deux requêtes qui font la même chose, du moins je le pense, mais elles ont des plans de requête et des performances complètement différents.
Question 1 :
SELECT c_pk
FROM table_c
WHERE c_b_id IN (SELECT b_id FROM table_b WHERE b_z = 1)
OR c_a_id IN (SELECT a_id FROM table_a WHERE a_z = 1)
Question 2 :
SELECT c_pk
FROM table_c
LEFT JOIN (SELECT b_id FROM table_b WHERE b_z = 1) AS b ON c_b_id = b_id
LEFT JOIN (SELECT a_id FROM table_a WHERE a_z = 1) AS a ON c_a_id = a_id
WHERE b_id IS NOT NULL
OR a_id IS NOT NULL
La requête 1 est rapide comme je m'y attendais, tandis que la requête 2 est très lente. Le site plans de requêtes sont très différents.
Je voudrais que la requête 2 soit aussi rapide que la requête 1. J'ai un logiciel qui utilise la requête 2, et je ne peux pas le changer en requête 1. Je peux modifier la base de données.
Quelques questions :
- pourquoi les plans de requêtes sont-ils différents ?
- Puis-je "apprendre" au serveur SQL que la requête 2 est égale à la requête 1 ?
Toutes les tables ont des clés primaires (en grappe) et des index appropriés sur toutes les colonnes :
CREATE TABLE table_a (
a_pk int NOT NULL PRIMARY KEY,
a_id int NOT NULL UNIQUE,
a_z int
)
GO
CREATE INDEX IX_table_a_z ON table_a (a_z)
GO
CREATE TABLE table_b (
b_pk int NOT NULL PRIMARY KEY,
b_id int NOT NULL UNIQUE,
b_z int
)
GO
CREATE INDEX IX_table_b_z ON table_b (b_z)
GO
CREATE TABLE table_c (
c_pk int NOT NULL PRIMARY KEY,
c_a_id int,
c_b_id int
)
GO
CREATE INDEX IX_table_c_a_id ON table_c (c_a_id)
GO
CREATE INDEX IX_table_c_b_id ON table_c (c_b_id)
GO
Les tables ne sont pas modifiées après le remplissage initial. Je suis le seul à les interroger. Elles contiennent des millions d'enregistrements (table_a : 5M, table_b : 4M, table_c : 12M), mais utiliser seulement 1% donne des résultats similaires.
Edit : J'ai essayé d'ajouter des FOREIGN KEYs pour c_a_id
y c_b_id
mais cela n'a rendu la requête 1 plus lente...
J'espère que quelqu'un pourra jeter un coup d'œil à la plans de requêtes et expliquer la différence.