Mysql
 sql >> Database >  >> RDS >> Mysql

Perché questa query MySQL (con controllo nullo) è così più lenta di quest'altra?

Sono sorpreso che uno dei due sia veloce. Suggerirei di sostituirli con 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);

E per il secondo:

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)
      )

Per entrambi, vuoi due indici:ips_fatura(ips_usuario_id) e ips_fatura(ips_usuario_id_titular) . Puoi controllare la spiegazione per essere sicuro che EXISTS sta usando l'indice. In caso contrario, le versioni più recenti di MySQL utilizzano gli indici per 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);

In entrambi i casi (EXISTS o IN ) l'obiettivo è fare un "semi join". Cioè, per multare solo la prima riga con una corrispondenza piuttosto che tutte le partite. Questa è un'efficienza importante, perché consente alla query di evitare la rimozione della duplicazione.

Suppongo che il problema sia l'ottimizzazione del or -- di solito questo si traduce in un JOIN inefficiente algoritmi. Tuttavia, forse MySQL è intelligente nel tuo primo caso. Ma l'aggiunta di IS NULL al tavolo esterno lo getta via.