Mysql
 sql >> Datenbank >  >> RDS >> Mysql

Warum ist diese MySQL-Abfrage (mit Nullprüfung) so langsamer als diese andere?

Ich bin überrascht, dass beide schnell sind. Ich würde vorschlagen, sie durch exists zu ersetzen :

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

Und zum zweiten:

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

Für beide benötigen Sie zwei Indizes:ips_fatura(ips_usuario_id) und ips_fatura(ips_usuario_id_titular) . Sie können die Erklärung überprüfen, um sicherzustellen, dass EXISTS verwendet den Index. Wenn nicht, verwenden die neueren Versionen von MySQL Indizes für 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 beiden Fällen (EXISTS oder IN ) ist das Ziel, einen "Semi-Join" durchzuführen. Das heißt, nur die erste Reihe mit einer Übereinstimmung zu bestrafen, anstatt alle Übereinstimmungen. Dies ist eine wichtige Effizienz, da die Abfrage das Entfernen von Duplikaten vermeiden kann.

Ich würde spekulieren, dass das Problem die Optimierung des or ist -- normalerweise führt dies zu ineffizientem JOIN Algorithmen. Aber vielleicht ist MySQL in Ihrem ersten Fall schlau. Aber die Hinzufügung von IS NULL zum äußeren Tisch wirft es ab.