Překvapuje mě, že obojí je rychlé. Navrhoval bych je nahradit výrazem exists
:
SELECT COUNT(*)
FROM ips_usuario u
WHERE EXISTS (SELECT 1 FROM ips_fatura f WHERE u.id = f.ips_usuario_id) OR
EXISTS (SELECT 1 FROM ips_fatura f WHERE u.ips_usuario_id_titular = f.ips_usuario_id);
A za druhé:
SELECT COUNT(*)
FROM ips_usuario u
WHERE EXISTS (SELECT 1 FROM ips_fatura f WHERE u.id = f.ips_usuario_id) OR
(u.ips_usuario_id_titular IS NOT NULL AND
EXISTS (SELECT 1 FROM ips_fatura f WHERE u.ips_usuario_id_titular = f.ips_usuario_id)
)
Pro oba tyto indexy chcete dva indexy:ips_fatura(ips_usuario_id)
a ips_fatura(ips_usuario_id_titular)
. Můžete zkontrolovat vysvětlení a ujistit se, že EXISTS
používá index. Pokud ne, novější verze MySQL používají indexy pro IN
:
SELECT COUNT(*)
FROM ips_usuario u
WHERE u.id IN (SELECT f.ips_usuario_id FROM ips_fatura f) OR
u.ips_usuario_id_titular IN (SELECT f.ips_usuario_id FROM ips_fatura f);
V obou případech (EXISTS
nebo IN
) cílem je udělat „semi-join“. To znamená pokutovat pouze první řadu zápalkou, nikoli všechny zápasy. To je důležitá efektivita, protože to umožňuje dotazu vyhnout se odstranění duplicit.
Spekuloval bych, že problém je v optimalizaci or
-- obvykle to má za následek neefektivní JOIN
algoritmy. Možná je však MySQL ve vašem prvním případě chytrá. Ale přidání IS NULL
k vnějšímu stolu to odhodí.