2012-01-05 12 views
6

Devo restituire tutti i valori da colA che non sono in colB da mytable. Sto usando:Modo efficiente per selezionare tutti i valori da una colonna non in un'altra colonna

SELECT DISTINCT(colA) FROM mytable WHERE colA NOT IN (SELECT colB FROM mytable) 

Sta funzionando, tuttavia la query impiega troppo tempo per essere completata.

Esiste un modo più efficiente per farlo?

+0

'NOT IN' rallenta quando aumenta la dimensione impostata e spesso c'è un limite al numero di righe nella clausola' NOT IN'. Al di fuori dei piccoli set di risultati, ho trovato preferibile utilizzare altri mezzi per ottenere la differenza tra due set di risultati. – Paul

+0

Quando si parla di prestazioni, è necessario assegnare un nome all'RDBMS o ottenere risposte non ottimali. –

risposta

10

In SQL standard ci sono senza parentesi in DISTINCT colA. DISTINCT non è una funzione.

SELECT DISTINCT colA 
FROM mytable 
WHERE colA NOT IN (SELECT DISTINCT colB FROM mytable); 

Aggiunto DISTINCT anche alla sotto-selezione. Se hai molti duplicati potrebbe velocizzare la query.

Un CTE potrebbe essere più veloce, a seconda del DBMS. Ho inoltre dimostrare LEFT JOIN in alternativa per escludere i valori in valB, e un modo alternativo per ottenere valori distinti con GROUP BY:

WITH x AS (SELECT colB FROM mytable GROUP BY colB) 
SELECT m.colA 
FROM mytable m 
LEFT JOIN x ON x.colB = m.colA 
WHERE x.colB IS NULL 
GROUP BY m.colA; 

Oppure, semplificato ulteriormente, e con una sottoquery pianura (probabilmente più veloce):

SELECT DISTINCT m.colA 
FROM mytable m 
LEFT JOIN mytable x ON x.colB = m.colA 
WHERE x.colB IS NULL; 

Esistono fondamentalmente 4 tecniche per escludere le righe con chiavi presenti in un altro (o lo stesso) tabella:

Il fattore decisivo per la velocità sarà indici. È necessario disporre di indici su colA e colB affinché questa query sia veloce.

+0

Grazie, ho provato: 'SELEZIONA DISTINCT m1.colA FROM mytable m1 SINISTRA UNISCITA mytable m2 ON (m1.colA = m2.colB) DOVE m2.colA È NULL ORDINE DI m1.colA ASC' ed è di diversi ordini di grandezza più veloce e sembra funzionare - è equivalente al codice che ho postato nella domanda? È molto più veloce di essere sospettoso di aver perso qualcosa. – Flash

+0

@Andrew: Spiacente, hai un errore nella tua query. Deve essere 'WHERE m2.colB IS NULL'. La query (corretta) potrebbe essere più veloce con 'LEFT JOIN (SELECT DISTINCT colB FROM mytable) m2 ON m2.colB = m1.colA' ** se ** ci sono molti valori duplicati per' colB'. –

+0

@Andrew: 'm2.colA' è sempre' NULL' se 'm2.colB' è NULL qui, ma' m2.colA' può essere NULL anche se 'm2.colB' non lo è. Quindi il modulo corretto (e più veloce!) Qui è: 'WHERE m2.colB IS NULL'. ** Se ** 'colA' è definito NOT NULL, la tua domanda precedente è corretta. –

6

È possibile utilizzare exists:

select distinct 
    colA 
from 
    mytable m1 
where 
    not exists (select 1 from mytable m2 where m2.colB = m1.colA) 

exists fa un semi-join per soddisfare rapidamente i valori. not in completa l'intero set di risultati e quindi fa un or su di esso. exists è in genere più veloce per i valori nelle tabelle.

+0

Puoi spiegare come funziona questa query? – Flash

+0

@Andrew - Sicuro! Dice, prendi il distinto 'colA's dove non ci sono righe da' mytable' che 'colB' è uguale a' colA'. – Eric

0

È possibile utilizzare l'operatore EXCEPT che differisce in modo efficace due query SELECT. EXCEPT DISTINCT restituirà solo valori univoci. L'operatore Oracle MINUS equivale a EXCEPT DISTINCT.

Problemi correlati