Pour ceux qui rencontreraient ce bug, je poste ici sa description et sa solution :
me donne un résultat erroné (vide dans mon cas)
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13 SELECT DISTINCT C.NUMORDRE FROM A LEFT OUTER JOIN C ON (C.NUMORDRE = A.NUMORDRE) WHERE (A.CARTE is null) AND (A.NUMORDRE not in ( select B.NUMORDRE from B inner join D ON (D.REF = B.REF) AND (D.TAG = 1) where (B.REF like 'A%') AND (B.NUMORDRE = A.NUMORDRE) ) )
alors que
donne le bon résultat (une ligne dans mon cas)
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14 SELECT DISTINCT C.NUMORDRE FROM A LEFT OUTER JOIN C ON (C.NUMORDRE = A.NUMORDRE) WHERE (A.CARTE is null) AND (A.NUMORDRE not in ( select B.NUMORDRE from B inner join D ON (D.REF = B.REF) AND (D.TAG = 1) where (B.NUMORDRE > 0) AND (B.REF like 'A%') AND (B.NUMORDRE = A.NUMORDRE) ) )
La différence entre les deux ? l'ajout de (B.NUMORDRE > 0) AND dans la clause where de la sous-requête.
Cette condition toujours vraie a pour but de forcer le l'optimiseur de requête à produire un plan corect du join.
En effet, dans le premier cas, le plan de la sous-requête était
alors que dans le second, il est
Code : Sélectionner tout - Visualiser dans une fenêtre à part PLAN JOIN (ECRITURES_1 INDEX (RDB$FOREIGN106,RDB$FOREIGN111),EXERCICES_1 INDEX (RDB$18))
Le truc vient de Ann Harrison, sur une page à entête Firebird.
Code : Sélectionner tout - Visualiser dans une fenêtre à part PLAN JOIN (EXERCICES_1 NATURAL,ECRITURES_1 INDEX (KYECRITURESREFEXERCICE,RDB$FOREIGN106,RDB$FOREIGN111))
Mais ce qu'elle indique marche avec Interbase, mais pas avec Firebird (1.5).
J'ajouterai qu'il s'agit bien d'un problème de plan, car, en mettant un bon plan explicite,
on obtient aussi le résultat correct, et cette fois-ci aussi bien avec Interbase que Firebird.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14 SELECT DISTINCT C.NUMORDRE FROM A LEFT OUTER JOIN C ON (C.NUMORDRE = A.NUMORDRE) WHERE (A.CARTE is null) AND (A.NUMORDRE not in ( select B.NUMORDRE from B inner join D ON (D.REF = B.REF) AND (D.TAG = 1) where (B.REF like 'A%') AND (B.NUMORDRE = A.NUMORDRE) PLAN JOIN (B INDEX (RDB$FOREIGN111),D INDEX (RDB$18)) ) )
A noter que le problème vient de ce que B.REF est indexé, et que FB 1.5/IB 6, à tort, veut introduire cet index (RDB$FOREIGN106) dans la plan du join
Partager