Изненадан съм, че и двете са бързи. Бих предложил да ги замените с 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);
И за второто:
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)
)
И за двете ви трябва два индекса:ips_fatura(ips_usuario_id)
и ips_fatura(ips_usuario_id_titular)
. Можете да проверите обяснението, за да сте сигурни, че EXISTS
използва индекса. Ако не, по-новите версии на MySQL използват индекси за 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);
И в двата случая (EXISTS
или IN
) целта е да се направи "полусъединяване". Тоест да глобявате само първия ред със съвпадение, а не всички съвпадения. Това е важна ефективност, тъй като позволява на заявката да избегне премахването на дублиране.
Бих предположил, че проблемът е в оптимизацията на or
-- обикновено това води до неефективно JOIN
алгоритми. Въпреки това, може би MySQL е умен в първия ви случай. Но добавянето на IS NULL
към външната маса го изхвърля.