Perché i loop nidificati si uniscono supportano solo i join di sinistra?


11

Nel blog di Craig Freedman, Nested Loops Join , spiega perché i join di loop nidificati non possono supportare un join esterno destro:

Il problema è che eseguiamo la scansione della tabella interna più volte, una volta per ogni riga del join esterno. Potremmo incontrare le stesse file interne più volte durante queste scansioni multiple. A che punto possiamo concludere che una determinata fila interna non ha o non si unirà?

Qualcuno può spiegare questo in un modo davvero semplice ed educativo?

Significa che il ciclo inizia con la tabella esterna ( R1) e esegue la scansione di inner ( R2)?

Capisco che per un R1valore che non si unisce a R2, dovrebbe essere sostituito con un NULLcosì il set di risultati diventa ( NULL, R2). Per me sembra impossibile restituire un R2valore quando R1non si unisce, per il motivo che non può sapere quale R2valore restituire. Ma non è così che viene spiegato. O è?

SQL Server infatti ottimizza (e spesso sostituisce) RIGHT JOINcon LEFT JOIN, ma la domanda è spiegare perché è tecnicamente impossibile per una logica di NESTED LOOPS JOINsupporto / utilizzo RIGHT JOIN.

Risposte:


12

Il problema principale qui è l'implementazione di un join esterno, usando loop nidificati, in un modo tecnico che è opposto al modo logico , in cui si accede alla tabella interna attraverso il loop esterno e alla tabella esterna si accede attraverso il loop interno .

Date le tabelle A e B, implementiamo A LEFT JOIN B.

A
--
1
2

B
_
1
3

Innanzitutto, facciamolo in modo " naturale ".

Esaminiamo attraverso A. Accediamo al
record 1.
Esaminiamo attraverso B.
Troviamo il record 1 in B e produciamo 1-1 .

Continuiamo a scorrere attraverso A. Accediamo al
record 2.
Passiamo a B.
Non troviamo alcuna corrispondenza in B.
Abbiamo prodotto 2-null .

Ora facciamolo nel modo " opposto ".

Esaminiamo attraverso B. Accediamo al
record 1.
Esaminiamo attraverso A.
Troviamo il record 1 in A e produciamo 1-1 .

Continuiamo a scorrere per B. Accediamo al
record 3.
Passiamo per A.
Non troviamo alcuna corrispondenza in A.

Ora ricorda che lo era A LEFT JOIN B, il che significa che oltre all'1-1 dovremmo produrre 2-null .
Il problema è che a quel punto non abbiamo idea per quali record ID A abbiamo già una corrispondenza (1) e per quali record non abbiamo (2).


Questo può effettivamente essere risolto in vari modi, ad esempio tenendo un array di bit per la tabella A.
Quando viene trovato un record A come una corrispondenza, lo contrassegniamo nell'array di bit.
Alla fine dei loop nidificati stiamo attraversando l'array di bit, producendo e producendo tutti i record non contrassegnati.
Questo è ovviamente più complicato del loop nidificato "naturale".


13

Quello che non mi piace nell'articolo collegato è l'affermazione che "l'algoritmo di join loop nidificato non supporta l'operatore di join logico di join destro" .

Mentre c'è una limitazione, la formulazione a questo punto è un po 'confusa. Spero che quanto segue spieghi meglio le cose:

L'algoritmo nop join nid coinvolge due tabelle (se le tabelle di base o i set di risultati di operazioni precedenti sono irrilevanti) che sono denominate tabella esterna e interna e sono trattate in modo diverso dall'algoritmo (la tabella "esterna" è attraversata all'esterno loop e la tabella "interna" nei loop interni).

Quindi, supponiamo che abbiamo un join:

A (some_type) JOIN B

L'algoritmo può essere eseguito come:

outer-loop-A  nested-loop  inner-loop-B

o:

outer-loop-B  nested-loop  inner-loop-A

Ora, se ( some_type) è INNERo CROSSunisci, allora non ci sono limiti, il pianificatore può scegliere tra uno dei due modi (con caratteristiche di prestazione diverse, a seconda della dimensione degli insiemi, distribuzione dei valori delle colonne unite, indici, ecc. Solitamente la tabella più piccola verrà scelta come tabella "esterna" nell'algoritmo).

Ma quando some_typeè LEFTjoin, può usare solo:

outer-loop-A  nested-loop  inner-loop-B

e non

outer-loop-B  nested-loop  inner-loop-A

E poiché a RIGHTpuò sempre essere riscritto come LEFTjoin, ha la stessa limitazione, al contrario. Per A RIGHT JOIN B(che può essere riscritto a B LEFT JOIN A) può usare solo:

outer-loop-B  nested-loop  inner-loop-A

e non viceversa * .

La stessa limitazione si applica a sinistra-semijoin, sinistra-anti-semijoin, destra-semijoin e destra-anti-semijoin.

Il FULLjoin d'altra parte non può essere gestito direttamente con un algoritmo di join loop nidificato. L'articolo spiega molto bene (è quasi alla fine) come è possibile riscrivere un join completo (ed è tramite l'ottimizzatore) in un'unione di un join sinistro e un antisemein sinistro che potrebbe quindi essere pianificato come due loop nidificati (e un unione).

* Come spiega Dudu Markovitz nella sua risposta, il modo inverso sarebbe in grado di essere utilizzato, ma solo se modificassimo l'algoritmo di join ad anello nidificato per avere una struttura aggiuntiva e un ulteriore passaggio alla fine.


Bene, questo ha chiarito molto. La tua risposta combinata con Dudu M: s lo spiega molto bene!
GordonLiddy,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.