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í.