Bonsoir,
Envoyé par
Artemus24
6) quand tu as trois tables en jointure, il y a un ordre à respecter.
En général, on commence par la table charnière (je réutilise ton vocabulaire).
Et ensuite, on fait le jointure sur les autres tables.
Pourquoi respecter un tel ordre ? Et s’il y a 10 tables « charnières » à joindre, par quel bout commence-t-on ? Au passage, je fais observer que la jointure naturelle est une opération commutative et associative, faisant que l’ordre ne joue pas.
Envoyé par
Artemus24
Inversement, si tu veux optimiser tes accès, commence par les tables les plus petites.
S’il s’agit là encore d’un ordre à respecter, autant dire qu’un optimiseur s’en tamponne le coquillard ! Il sait ce qu’il a à faire et comment le faire.
Envoyé par
Gugelhupf
Envoyé par
Artemus24
Pourquoi faire un "where M.id = 40" ?
Car en faisant cela, tu récupères tout, puis ensuite, tu sélectionnes ce dont tu as besoin.
7. Pourquoi faire un "where M.id = 40" ? : parce que id = 40 n'est pas une condition de jointure, mais un élément variable. Je n'ai pas testé la différence entre les performances entre
ON et
WHERE, mais je suis sur que le SGBD optimise cela à la lecture de la requête.
Vous avez parfaitement raison, Gugelhupf, c’est bien le SGBD qui optimise.
En fait, "where M.id = 40" correspond à l’opération relationnelle de
restriction. Il est évident qu’un optimiseur quel qu’il soit va commencer par effectuer cette opération qui est la plus rentable de toutes quant aux performances (sous réserve bien sûr que l’on ait défini l’index ad-hoc).
Ainsi, que l’on code « Belle Marquise, vos beaux yeux me font mourir d’amour » :
SELECT
P.*,
M.nom AS nom_medecin,
M.prenom AS prenom_medecin
FROM t_medecin M
JOIN t_charniere_medecin_patient MP
ON M.id = MP.id_medecin
JOIN t_patient P
ON P.id = MP.id_patient
WHERE M.id = 40
;
Ou bien « D’amour mourir me font, belle Marquise, vos beaux yeux » :
SELECT
P.*,
M.nom AS nom_medecin,
M.prenom AS prenom_medecin
FROM t_medecin M, t_charniere_medecin_patient MP, t_patient P
WHERE M.id = MP.id_medecin
AND P.id = MP.id_patient
AND M.id = 40
;
ou encore « Vos yeux beaux d’amour me font, belle Marquise, mourir » :
SELECT
P.*,
M.nom AS nom_medecin,
M.prenom AS prenom_medecin
FROM t_charniere_medecin_patient MP
INNER JOIN t_medecin M
ON M.id = MP.id_medecin
AND M.id = 40
INNER JOIN t_patient P
ON P.id = MP.id_patient
WHERE M.id = 40;
Eh bien, un optimiseur n’en a cure car, comme aurait dit Monsieur de La Palice, sa mission c’est ... d’optimiser ! Dans tous les cas, il applique donc d’abord la restriction très juteuse « where M.id = 40 », ce que montre bien un EXPLAIN, même avec MySQL :
1re requête :
2e requête :
3e requête :
Envoyé par
Artemus24
une foreign key, c'est déjà un index
Les auteurs de MySQL en ont certes décidé ainsi, mais c’est un diktat insupportable, une erreur de leur part, ils confondent les niveaux, relationnel d’une part, physique d’autre part. Une clé étrangère (
foreign key) d’une table T1 n’est pas un index, mais une référence à une clé candidate (voire une surclé) d’une table T2 (non nécessairement distincte de T1). On est en l’occurrence au niveau relationnel. Sorti de MySQL, que le DBA décide au niveau physique de mettre en œuvre pour T1 un index dont les colonnes sont celles de la clé étrangère, pourquoi pas, mais seulement en cas de nécessité, il est le seul juge.
Par exemple, avec PostgreSQL, sans index sur la colonne id_medecin, la requête ci-dessous va provoquer un balayage complet de la table t_charniere_medecin_patient :
select * from t_charniere_medecin_patient where id_medecin = 40 ;
=>
"Seq Scan on t_charniere_medecin_patient "
Avec un tel verdict de la part de l’optimiseur, on créera un index, mais là encore, c’est une décision du DBA (après tout, pour une table de quelques lignes, genre titres de civilité, le jeu n’en vaut sans doute pas la chandelle). Dans le cas présent, avec PostgreSQL, on codera par exemple :
create index t_charniere_medecin_patient_x1 on t_charniere_medecin_patient (id_medecin) ;
Et notre DBA peaufinera dans la soute, jusqu’à ce qu’il obtienne la performance recherchée. En passant, avant de s’occuper de la performance, afin d’éviter que cette table ne se transforme en «
sac à tuples » (présence de doublons, donc mise en danger de l’algèbre relationnelle qui ne sait opérer correctement que sur des ensembles), il la dotera d’une clé primaire {id_medecin, id_patient} (avec pour conséquence la mise en œuvre implicite ou non de l’index de type UNIQUE correspondant...)
Envoyé par
5) tu fais une jointure, d'accord, mais j'aimerai que tu précises quel type de jointure.
Un "inner join", un "left outer join", autre chose ... Je n'aime pas les déclaratives par défaut.
Les sentiments ne sont pas de mise ! SQL est un langage pour lequel il existe une norme, et il y est écrit (cf. par exemple
WG3:HBA-003 = H2-2003-305 = 5WD-02-Foundation-2003-09, WD 9075-2 (SQL/Foundation), September, 2003, aux pages 312-313) :
7.7 <joined table> Function Specify a table derived from a Cartesian product, inner join, or outer join.
Format <joined table> ::=
<cross join>
| <qualified join>
| <natural join>
<cross join> ::=
<table reference> CROSS JOIN <table factor>
<qualified join> ::=
<table reference> [ ] JOIN <table reference> <join specification>
<natural join> ::=
<table reference> NATURAL [ ] JOIN <table factor>
<join specification> ::=
<join condition>
| <named columns join>
<join condition> ::= ON <search condition>
<named columns join> ::= USING <left paren> <join column list> <right paren>
<join type> ::=
INNER
| <outer join type> [ OUTER ]
<outer join type> ::=
LEFT
| RIGHT
| FULL
<join column list> ::=
<column name list>
Syntax Rules [...]
3) If a <qualified join> or <natural join> is specified and a <join type> is not specified, then INNER is implicit.
[...]
La norme ayant décrété (dès SQL:1992, il y a donc belle lurette !) qu’INNER était implicite, chacun est libre d’en faire usage ou non. Maintenant, si les règles en vigueur dans l’entreprise imposent INNER (ou NATURAL ou USING, etc.), chacun devra évidemment se conformer à ces règles.
10 |
0 |