sql >> Base de Datos >  >> RDS >> Mysql

¿Por qué esta consulta mysql (con verificación nula) es tan lenta que esta otra?

Me sorprende que cualquiera sea rápido. Sugeriría reemplazarlos 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);

Y para el segundo:

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

Para ambos, desea dos índices:ips_fatura(ips_usuario_id) y ips_fatura(ips_usuario_id_titular) . Puede consultar la explicación para asegurarse de que EXISTS está usando el índice. Si no, las versiones más recientes de MySQL usan índices para 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);

En cualquier caso (EXISTS o IN ) el objetivo es hacer una "semi-unión". Es decir, multar solo la primera fila con una coincidencia en lugar de todas las coincidencias. Esta es una eficiencia importante, porque permite que la consulta evite la eliminación de la duplicación.

Yo especularía que el problema es la optimización de or -- por lo general esto resulta en JOIN ineficiente algoritmos Sin embargo, quizás MySQL sea inteligente en su primer caso. Pero la adición de IS NULL a la mesa exterior lo tira.