inserimento di righe da un tavolo all'altro, che SQL è più efficiente (join esterno vs scansione sequenziale)
-
12-09-2019 - |
Domanda
Ho bisogno di copiare le righe dalla tabella B per tabella A. Il requisito è quello di inserire solo le righe che non sono già in A.
La mia domanda è, che è di due seguenti è più efficiente:
A)
INSERT INTO A (x, y, z)
SELECT x, y, z
FROM B b
WHERE b.id NOT IN (SELECT id FROM A);
B)
INSERT INTO A (x, y, z)
SELECT b.x, b.y, b.z
FROM B b LEFT OUTER JOIN A a
ON b.id = a.id
WHERE a.id is NULL;
Io parto dal presupposto la risposta dipende dalle dimensioni delle tabelle. Ma volevo sapere se c'è qualcosa di lampante sull'utilizzo di un approccio rispetto all'altro.
Per ridurre l'imprecisione, diciamo Tabella B avrà meno di 50K righe e Tabella A sarà sempre uguale o maggiore di dimensioni alla Tabella B per un fattore di 1-5.
Se qualcuno ha altri modi più efficaci per fare questo, fai dire.
Soluzione
Credo che l'opzione B è meglio, soprattutto se la tabella A è più grande di tabella B di un fattore> 1.
Se si dispone di indici su a.id e b.id poi unendo sarà più veloce, secondo me, rispetto all'utilizzo in cui per ogni riga ...
Altri suggerimenti
Per aggiungere un'altra opzione:
INSERT INTO A (x, y, z)
SELECT B.x, B.y, B.z
FROM B
WHERE NOT EXISTS(SELECT * FROM A WHERE A.id = B.id)
Di solito vado con il LEFT JOIN approccio. Ma, se si vuole conoscere veramente ciò che è più efficiente, eseguire alcuni test sul proprio ambiente. Vedere che cosa i piani di esecuzione per ciascun approccio sono (si potrebbe scoprire che in realtà molteplici approcci risultano nello stesso piano di esecuzione).
Non dovrebbe importa - un buon ottimizzatore tratterà questi in modo identico. In pratica, ho visto per i piani di esecuzione stravaganti esattamente in questo caso, ma io sono noti per utilizzare entrambi gli stili in modo intercambiabile, a seconda dell'umore, la leggibilità e la complessità della query.
In SQL Server, l'opzione A non è disponibile quando è necessario iscriversi in una tupla di più Thana una singola colonna senza utilizzare un qualche tipo di concatenazione di soluzione (che non consiglio), che ci porta al gatto-scuoiatura opzione C (che io uso anche, soprattutto con le giunture sono davvero squirrely), che si estende a tuple direttamente:
INSERT INTO A (x, y, z)
SELECT x, y, z
FROM B b
WHERE NOT EXISTS (SELECT * FROM A WHERE id = b.id);
INSERT INTO A (x, y, z)
SELECT x, y, z
FROM B b
WHERE NOT EXISTS (SELECT * FROM A WHERE id1 = b.id1 AND id2 = b.id2);
A seconda del numero di righe e l'attività sul database, sarebbe di grande aiuto per eliminare tutti gli indici della tabella prima l'inserto e ricrearli in seguito.