Si la requête implique de grandes parties de b
et/ou c
il est plus efficace d'agréger d'abord et de se joindre plus tard.
Je pense que ces deux variantes seront considérablement plus rapides :
SELECT a.id,
,COALESCE(b.ct, 0) + COALESCE(c.ct, 0) AS bc_ct
FROM a
LEFT JOIN (SELECT a_id, count(*) AS ct FROM b GROUP BY 1) b USING (a_id)
LEFT JOIN (SELECT a_id, count(*) AS ct FROM c GROUP BY 1) c USING (a_id);
Vous devez tenir compte de la possibilité que certains a_id
ne sont pas présents du tout dans a
et/ou b
. count()
ne renvoie jamais NULL
, mais c'est un peu réconfortant face à LEFT JOIN
, ce qui vous laisse avec NULL
valeurs pour les lignes manquantes néanmoins. Vous devez préparez-vous pour NULL
. Utilisez COALESCE()
.
Ou UNION TOUS a_id
à partir des deux tables, agrégées, puis REJOINDRE :
SELECT a.id
,COALESCE(ct.bc_ct, 0) AS bc_ct
FROM a
LEFT JOIN (
SELECT a_id, count(*) AS bc_ct
FROM (
SELECT a_id FROM b
UNION ALL
SELECT a_id FROM c
) bc
GROUP BY 1
) ct USING (a_id);
Probablement plus lent. Mais toujours plus rapide que les solutions présentées jusqu'à présent. Et vous pourriez vous passer de COALESCE()
et toujours pas perdre de rangées. Vous pouvez obtenir occasionnellement NULL
valeurs pour bc_ct
, dans ce cas.