2012-02-10 17 views
10

Tengo una tabla (correo electrónico) de direcciones de correo electrónico:¿Cómo puedo realizar una consulta SQL 'NO EN' más rápido?

EmailAddress 
------------ 
[email protected] 
[email protected] 
[email protected] 
[email protected] 

y una mesa (lista negra) de direcciones de correo electrónico de la lista negra:

EmailAddress 
------------ 
[email protected] 
[email protected] 

y quiero seleccionar aquellas direcciones de correo electrónico que se encuentran en el Tabla EMAIL pero NO en la tabla BLACKLIST. Estoy haciendo:

SELECT EmailAddress 
FROM EMAIL 
WHERE EmailAddress NOT IN 
    (
     SELECT EmailAddress 
     FROM BLACKLIST 
    ) 

pero cuando el recuento de filas es muy alto, el rendimiento es terrible.

¿Cómo puedo hacer esto mejor? (Suponga SQL genérica si es posible. Si no es así, asumir T-SQL.)

+2

Agregue índice en la columna BLACKLIST..EmailAddress para mejorar el rendimiento de la consulta finalmente elegida. – Tomek

+0

@Tomek - Debería haber indicado, los problemas de rendimiento están con el índice incluido. – Howiecamp

Respuesta

21

Se puede utilizar una combinación externa izquierda, o una cláusula not exists.

externa izquierda:

select E.EmailAddress 
    from EMAIL E left outer join BLACKLIST B on (E.EmailAddress = B.EmailAddress) 
where B.EmailAddress is null; 

No existe:

select E.EmailAddress 
    from EMAIL E where not exists 
     (select EmailAddress from BLACKLIST B where B.EmailAddress = E.EmailAddress) 

Tanto son soluciones SQL bastante genéricos (no dependen de un motor específico DB). Diría que este último es un poco más eficiente (aunque no mucho). Pero definitivamente más eficiente que el not in.

Como lo comentaron los comentadores, también puede intentar crear un índice en BLACKLIST(EmailAddress), que debería ayudar a acelerar la ejecución de su consulta.

+0

@dasblinkenlight: ¡gracias! agregado eso. –

+0

El 'no existe' puede ser más rápido en algunos motores de DB pero AFAIK, SQL Server lo optimiza automáticamente y convierte' IN' en 'NOT Exists' – Icarus

+0

Si no me equivoco, creo que' left join' ser más lento y 'no existe' generará el mismo plan de consulta que la consulta del OP. –

3

NOT IN difiere de NOT EXISTS si la lista negra permite valores nulos como EmailAddress. Si hay un único valor nulo, el resultado de la consulta siempre devolverá cero filas porque NOT IN (nulo) es desconocido/falso para cada valor. Por lo tanto, los planes de consulta difieren levemente, pero no creo que haya ningún impacto serio en el rendimiento.

Una sugerencia es crear una nueva tabla llamada VALIDEMAIL, agregar un desencadenador a BLACKLIST que elimine direcciones de VALIDEMAIL cuando se inserten filas y agregar a VALIDEMAIL cuando se elimine de BLACKLIST. Luego reemplace EMAIL con una vista que sea una unión de VALIDEMAIL y BLACKLIST.

Cuestiones relacionadas