Interni tipovi join-ovanja

Objavljeno: 05-01-2014 | Autor: Milen Blagojević | Kategorija: Optimizacija

0

Prilikom logičkih join-ovanja tabela u SQL serveru, SQL Server Query Optimizer koristi jedan od 3 tipa internih join-ova:

Merge join

U većini slučajeva ovo je najefikasniji metod join-ovanja tabela. SQL Server koristi ovaj tip kada se join-uju tabele sa približnim brojem redova po kolonama koje imaju isto sortirane indekse.

SET STATISTICS TIME ON;
SET STATISTICS IO ON;
SELECT cf.CrtacID, ce.Naziv
FROM dbo.CrtaniFilmovi cf
INNER JOIN dbo.CrtaneEpizode ce on cf.CrtacID = ce.CrtacID;

Statistike i exec plan:
(999982 row(s) affected)
Table ‘CrtaneEpizode’. Scan count 1, logical reads 4501, physical reads 2, read-ahead reads 1749, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table ‘CrtaniFilmovi’. Scan count 1, logical reads 1206, physical reads 5, read-ahead reads 1189, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.


Merge join se takođe koristi i prilikom join-ovanja dve tabele bez odgovarajućih indeksa ukoliko optimizer proceni da je jeftinija operacija sortirati obe tabele i onda uraditi merge nego raditi hash join:

Loop join

Ovaj tip join-a SQL Server koristi kada je jedna od tabela koje se join-uju dosta manja od druge. Kao što samo ime kaže, u njemu se za svaki red manje tabele uradi seek veće tabele.

SET STATISTICS TIME ON;
SET STATISTICS IO ON;
SELECT cra.AutorID, cf.CrtacID
FROM dbo.CrtaniFilmovi cf
INNER JOIN dbo.CrtaniFilmovi_Rel_Autori cra on cf.CrtacID = cra.CrtacID;

Statistike i exec plan:
(9 row(s) affected)
Table ‘CrtaniFilmovi’. Scan count 0, logical reads 27, physical reads 2, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table ‘CrtaniFilmovi_Rel_Autori’. Scan count 1, logical reads 2, physical reads 1, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

Loop join će se takođe koristiti ako u prvom primeru dodamo WHERE:

SET STATISTICS TIME ON;
SET STATISTICS IO ON;
SELECT cf.CrtacID, ce.Naziv
FROM dbo.CrtaniFilmovi cf
INNER JOIN dbo.CrtaneEpizode ce on cf.CrtacID = ce.CrtacID
WHERE cf.CrtacID = 1;


Hash join

Heš join je najmanje efikasan i koristi se kod velikih tabela kada se join ne radi po indeksima ili se radi po indeksima koji nisu sortirani po istom redosledu. Ovaj tip join-a se radi tako što se na atribut po kome se radi join (iz manje tabele) primeni heš funkcija čime se dobija heš tabela, nakon toga se za svaki red veće tabele kreira heš ključ i radi se join-ovanje ukoliko ključ postoji u heš tabeli. U okviru ovog tipa postoje 3 posebna tipa heš join-a:
In-memory hash join – Kada se cela heš tabela može smestiti u memoriju
Grace Hash Join – Kada se cela heš tabela ne može smestiti u memoriju, tada se radi particionisanje heš tabele
Recursive Hash Join – Kada je heš tabela ogromna i mora se koristiti više nivoa particionisanja heš tabele

U ovom primeru smo pobrisali indekse sa tabela:

SET STATISTICS TIME ON;
SET STATISTICS IO ON;
SELECT cf.CrtacID, ce.Naziv
FROM dbo.CrtaniFilmovi cf 
INNER JOIN dbo.CrtaneEpizode ce on cf.CrtacID = ce.CrtacID;

Statistike i exec plan:
(999982 row(s) affected)
Table ‘Worktable’. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table ‘CrtaneEpizode’. Scan count 1, logical reads 5348, physical reads 2, read-ahead reads 5355, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table ‘CrtaniFilmovi’. Scan count 1, logical reads 1200, physical reads 21, read-ahead reads 1207, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.


SQL Server Query Optimizer će znati kada koji od ovih joina treba da koristi tako da ne preporučujemo korišćenje query hintova kojima se biraju tipovi join-ovanja:

SELECT CF.CrtacID,CF.Naziv,CE.EpizodaID,CE.Naziv
FROM dbo.CrtaneEpizode CE
INNER MERGE JOIN dbo.CrtaniFilmovi CF ON CE.CrtacID = CF.CrtacID;

SELECT CF.CrtacID,CF.Naziv,CE.EpizodaID,CE.Naziv
FROM dbo.CrtaneEpizode CE
INNER LOOP JOIN dbo.CrtaniFilmovi CF ON CE.CrtacID = CF.CrtacID;

SELECT CF.CrtacID,CF.Naziv,CE.EpizodaID,CE.Naziv
FROM dbo.CrtaneEpizode CE
INNER HASH JOIN dbo.CrtaniFilmovi CF ON CE.CrtacID = CF.CrtacID;