You are on page 1of 41

itanje grafikog plana izvravanja za

osnovne upite
Lekcija

Interpretirati osnovne grafike planove izvravanja

Planovi izvravanja za jednostavne SELECT, UPDATE, INSERT ili


DELETE upite sa samo par spajanja

Svaka ikona predstavlja odreeni operator unutar plana


izvravanja

ikona=operator
Lista operatora
Select (Result) RID Lookup
Clustered Index Scan Filter
NonClustered Index Scan Lazy Spool
Clustered Index Seek Spool
NonClustered Index Seek
Eager Spool
Hash Match
Nested Loops Stream Aggregate
Merge Join Distribute Streams
Sort Repartition Streams
Key Lookup Gather Streams
Compute Scalar Bitmap
Constant Scan Split
Table Scan
Clustered Index Scan

Operacija se deava kada pretraga klasterovanog indeksa ili nekog


drugog indeksa ne zadovoljava potrebe upita.
U tom sluaju SQL server mora da skenira ceo skup podataka

Primer:
SELECT ct.*
FROM Person.ContactType AS ct;

Ako kliknemno na Tool Tip (predjemo miem preko ikone), dobiemo


vie informacija
U Object vidimo koji se objekat referencira. U ovom sluaju to je
klasterovan indeks PK_ContactType_ContactTypeID
Clustered Index Scan

Index Scan se deava kada indeks postoji, ali optimizer odlui da ima
suvie redova da vrati, da je bre da skenira sve vrednosti indeksa
nego da koristi kljueve tog indeksa

Drugi razlog je da indeks nije dovoljno selektivan da bi optimizator bio


siguran da e nai podatke a da ne skanira veliki procenat indeksa

Ako vidite Index Scan u svom planu, treba se zapitati da li se vraa vie
redova nego to je potrebno tj. da li treba podesiti WHERE klauzulu

Vraanje vie redova nego to je potrebno troi SQL Server resurse i


ugroava performanse u celini
Clustered Index Seek

Ova operacija se deava kada upit koristi indeks za pristup samo


jednog reda ili nekoliko susednih redova
Ovo je jedan od brih naina za dohvatanje podataka iz sistema

Primer:
SELECT ct.*
FROM Person.ContactType AS ct
WHERE ct.ContactTypeID = 7

Kada se indeks koristi u Seek operaciji, vrednosti kljua se koriste za pretragu i


pronalaenje reda ili redova podataka

Benefit klasterovanog traenja indeksa, pored jeftinije pretrage jeste to to se


podaci nalaze u indeksu na nivou lista pa nam nije potreban nikakav dodatni
korak za pronalaenje podataka
Clustered Index Seek

Obratiti panju na Seek Predicates u Tool Tipu

Seek Predicates su filteri po kojima se vrednosti dohvataju

Stoji vrednost @1 umesto broja 7

Ovo je iz razloga to se ovaj upit kvalifikuje za jednostavnu


parametrizaciju ime se potpomae reuse optimizacionog plana
kada se on poziva sa razliitom vrednou

Primetiti da je Order property sada true


NonClustered Index Seek

Ova operacija je pretraga preko neklasterovanog indeksa

Primer:
SELECT ct.ContactTypeId
FROM Person.ContactType AS ct
WHERE Name LIKE 'Own%'
Neklasterovan indeks smeta samo kljueve, ali ne i podatke
U ovom sluaju imamo pokrivajui indeks zato to se dve kolone koje se
koriste u upitu nalaze u samom indeksu: name kao klju i Id kao
vrednost tog kljua
Jo dodatnih informacija u odnosu na Tool Tip se moe dobiti desnim
klikom na Index Seek I selekcijom Properties iz drop-down menija
Key Lookup

Key Lookup operator (RID i KEY) je potreban da bi se dohvatili


podaci iz heap-a ili klasterovanog indeksa
Primer:
SELECT p.BusinessEntityID, p.LastName, p.FirstName,
p.NameStyle
FROM Person.Person AS p
WHERE p.LastName LIKE 'Jaf%';
Key Lookup znai da optimizator ne moe da dohvati red u
jednoj operaciji ve mora da koristi, u ovom sluaju klasterovani
klju, ili row id iz heap tabele da bi vratio odgovarajue redove
iz klasterovanog indeksa (ili iz same tabele)
Heap or Clustered

Select top 1 Case


when index_id=0 then 'Heap'
Else 'Clustered'
End as TableType
FROM sys.indexes
WHERE Object_id = object_id(Purchasing.Shipmethod')
order BY index_id

SELECT object_name(sys.tables.object_id)
FROM sys.indexes
INNER JOIN sys.tables
ON sys.indexes.object_ID=sys.tables.OBJECT_ID
WHERE sys.indexes.type=0
Key Lookup

Prostatic Output List i Seek Predicates iz Tool Tipa za Index Seek i za Key
Lookup
U Output List se vide kolone vracene iz indeksa
Primetiti da je optimizator modifikovao sam upit!
U Output Listi za operator Key Lookup moemo videti I kolonu
Person.NameStyle koja je falila jo
Nested Loops spajanje je potrebno da bi se kombinovali podaci iz Index Seek
i Key Lookup
Ukoliko Key Lookup nije potreban, onda se ne pojavljuje ni Nested Loops
Ukoliko tabela nema klasterovan index, operator RID Lookup bi se koristio
umesto Key Lookup
RID je identifikator reda
Table Scan

Table scan se deava kada tabela nema klasterovan indeks, u


suprotnom se koristi Clustered Index Scan
Table scan se koristi i kada nam trebaju svi redovi iz tabele
Primer:
SELECT *
FROM dbo.DatabaseLog;

Table scan nije problem kada je broj redova relativno mali


RID Lookup

RID Lookup je heap ekvivalent od Key Lookup operacije


Ne-klasterovani indeksi ne moraju uvek da sadre sve podatke
da bi se zadovoljio upit I zato je potrebna dodatna operacija
Kada postoji klasterovani indeks na tabeli, koristi se key lookup
kao to je prethodno opisano
Ukoliko nema klasterovanog indeksa, moraju se potraiti podaci
koristei interni identifikator, Row ID ili RID
Primer:
SELECT *
FROM [dbo].[DatabaseLog]
WHERE DatabaseLogID = 1
RID Lookup

Obratiti panju na Output List u Tool Tipu gde se pojavljuje


dodatno ime kolone Bmk1000 (RID)
Ta kolona e se koristit u Nested Loops operatoru za spajanje
podataka iz RID Lookup operacije
U Tool Tipu za RID Lookup Bmk100 je opet korien, ali ovaj put
u Seek Predicates sekciji
Ako RID Lookup vraa mnogo redova, treba razmisliti kako upit
prepisati da bude bolji da bi koristio manje I/O operacija
Table Joins

Primer:

SELECT e.JobTitle, a.City,


p.LastName + ', ' + p.FirstName AS EmployeeName
FROM HumanResources.Employee AS e
JOIN Person.BusinessEntityAddress AS bea
ON e.BusinessEntityID = bea.BusinessEntityID
JOIN Person.Address a
ON bea.AddressID = a.AddressID
JOIN Person.Person AS p
ON e.BusinessEntityID = p.BusinessEntityID ;
Table Joins
Table Joins

Moemo da identifikujemo 3 najskuplje operacije u planu:


Index Scan 31%
Hash Match join izmedju tabele Person.Person i izlaza prvog
HashMatch 21%
Hash Match join izmeu Person.Addres tabele i outputa iz Nested
Loop operatora 20%

Pogledati Tool Tip za Index Scan operator i trokove kotanja


Table Joins
Optimizer je izraunao, na osnovu statistike
indeksa i kolona da je najbolji nain da se
doe do podatka da se skenira ceo indeks
red po red
Prolo se kroz 19614 redova
Hash Match Join
Javlja se u planu kada SQL Server smesti dva skupa podataka u
privremene tabele (hash tabele) i koristi ove strukture za poreenje
podataka i kreiranja rezultujueg skupa
U prethodnom primeru je ovo drugi najskuplji operator u planu
izvravanja
SQL server prvo hashuje redove iz manje tabele koje ubacuje u hash
tabele
Zatim obrauje veu tabelu, red po red i poredi sa hash tabelom
traei par
Ukoliko su obe tabele velike, ovo spajanje moe da bude neefikasno

Svi podaci iz hash tabele se smetaju u tempdb pa previe korienja


Hash Joinova moe da utie na optereenje tabele tempdb
Kada vidite Hash Match join, treba pogledati da li moe da se podesi
upit, doda index ili where klauzula da bi join bio efikasniji
Hash Match Join

Optimizer izraunava hash vrednost za sve


redove iz manje tabele i smeta u tempdb
(hash tabela sa bucketima), pa se druga
tabela spaja sa redovima iz temdb
Sve dok je temdb relativno mala,
poreenje je brzo
U ovom sluaju se podaci iz Employee
spajaju sa Person tabelom
Moda moe da se izvri spajanje
efikasnijim
Kreiranje drugog indeksa
Korienje WHERE klauzule
Nested Loops join

Nested Loops Join uzima skup podataka (outer set) i poredi ga,
red po red, sa drugim skupom podataka (inner set)
Koristi se kada je inner set mali, a outer set je indeksovan
svejedno da li je mali ili veliki
U tom sluaju je ovo spajanje izuzetno efikasno
Pogledajmo property od operacije Clustered Index Seek nad
Business Entity tabelom (kota 9%)
Nested Loops
Nested Loops
Tabela Employees se skenira a tabela
BusinessEntityAddress se pretrauje
(seek)
Broj redova je bio mali, tako da je
operacija vrlo efikasna
Compute Scalar
Nije vrsta spajanja, ali se nalazi u planu izvravanja za prethodni
primer
Odnosi se na p.LastName + ', ' + p.FirstName u upitu
Pogledati u Properties ovog operatora gde se nalazi opis
izraunavanja
Operacija daje skalarnu vrednost koja je obino rezultat nekog
izraunavanja
Compute Scalar
Troak je trivijalan
Pogledati na elipsu
Merge Join

Radi nad sortiranim podacima i koristi tu injenicu u svom radu

Primer:
SELECT c.CustomerID
FROM Sales.SalesOrderDetail od
JOIN Sales.SalesOrderHeader oh
ON od.SalesOrderID = oh.SalesOrderID
JOIN Sales.Customer c
ON oh.CustomerID = c.CustomerID
Merge Join

Prvo se izvrava Clustered Index Scan nad Customer tabelom i


NonClustered Index Scan nad SalesOrderHeader tabelom
Svi redovi se spajaju koristei Merge Join
Trea tabela se spaja koristei Hash Match spajanje
Merge Join

Merge Join je koriten zato to su kolone spajanja, SalesOrderID


i CustomerID sortirane

Ukoliko kolone spajanja nisu sortirane, optimizator ima opcije


da:
Sortira kolone spajanja prvo pa uradi Merge Join
Koristi manje efikasno Hash Match spajanje

Optimizator razmatra opcije i bira plan izvravanja koji koristi


najmanje resursa na osnovu statistike
Filterovanje podataka

Primer:
SELECT e.[Title], a.[City],
c.[LastName] + ',' + c.[FirstName] AS EmployeeName
FROM [HumanResources].[Employee] e
JOIN [HumanResources].[EmployeeAddress] ed
ON e.[EmployeeID] = ed.[EmployeeID]
JOIN [Person].[Address] a
ON [ed].[AddressID] = [a].[AddressID]
JOIN [Person].[Contact] c
ON e.[ContactID] = c.[ContactID]
WHERE e.[Title] = 'Production Technician - WC20' ;

Optimizator je koristio kriterijum iz WHERE klauzule za Clustered


Index Scan koristei primarni klju
Zahvaljujui manjem skupu podataka i dobrom indeksu nad
tabelom Person, optimizator je koristio efikasnije spajanje,
Nested Loops
Filterovanje podataka

Prvo se izvrava Clustered Index Scan koristei PK


Nested Loops se izvrava zbog manjeg skupa podataka I dobrog
indeksa nad Person.Person tabelom
Sort

Primer:
SELECT Shelf
FROM Production.ProductInventory
ORDER BY Shelf

Troak sortiranja je veliki, zato to nema indeksa nad kolonom


Ako sortiranje zauzima vie od 25% ukupnog vremena
izvravanja upita, potrebno je da se upit optimizira
Da li su potrebni svi redovi? Razmotriti korienje WHERE
klauzule
Sort

Prvo se izvrava Clustered Index Scan


Sort kota 76% zato to nema indeksa nad ovom kolonom
Ako napravimo klasterovan indeks, podaci e doi presortirani
To nije uvek mogue
Ako imate sortiranje po vie kolona, videti da li su sva sortiranja
neophodna
Sort

Primer:
SELECT *
FROM Production.ProductInventory
ORDER BY ProductID
Ako pogledamo execution plan, videemo da nema Sort
operatora
Hash Match (aggregate)

Hash Match operator za spajanja moe da se pojavi kada se radi


agregacija unutar upita
Primer:
SELECT [City],COUNT([City]) AS CityCount
FROM [Person].[Address]
GROUP BY [City]

SQL server e kreirati privremenu hash tabelu u memoriji da bi


izbrojao redove
Agregacije unutar upita mogu da budu skupe
Razmotriti korienje WHERE klauzule
Hash Match (aggregate)

Izvravanje poinje sa Index Scan poto nema where klauzule


Hash Match (aggregate) kreira privremenu hash tabelu u
memoriji da bi prebrojao broj redova koji odgovaraju group by
koloni
Agregacije mogu da budu skupe operacije
Filter
Primer:
SELECT [City],
COUNT([City]) AS CityCount
FROM [Person].[Address]
GROUP BY [City]
HAVING COUNT([City]) > 1

Having se izvrava tek posle agregacije

Razmatrati korienje WHERE klauzule!


Filter

Filter operator se pojavljuje tek sa having u group by


Ograniava broj vrednosti u koloni City
Operator Having se ne primenjuje pre agregacije svih podataka
Broje redova u Hash Match operatoru je 575, a u Filteru 348
Having ne poboljava performanse zato to se izvrava posle
grupisanja, za razliku od where klauzule
INSERT
INSERT INTO Person.Address (AddressLine1,
AddressLine2, City, StateProvinceID, PostalCode, rowguid,
ModifiedDate)
VALUES (
N'1313 Mockingbird Lane', -- AddressLine1 - nvarchar(60)
N'Basement', -- AddressLine2 - nvarchar(60)
N'Springfield', -- City - nvarchar(30)
79, -- StateProvinceID - int
N'02134', -- PostalCode - nvarchar(15)
NEWID(), -- rowguid - uniqueidentifier
GETDATE() -- ModifiedDate - datetime
)

Moe da izgleda da se INSERT izvrava jednostavno


Fizika struktura tabele moe da utie na plan izvravanja
IDENTITY kolona, FOREIGN KEY ogranienje
INSERT

Constant Scan kreira red da bi sledei operatori imali gde da smeste podatke
Compute Scalar poziva funkciju getidentity (prva operacija u insertu)
Sledea Scalar operacija kreira serije prostora za sledee podatke (pogledati Property)
Sve to se prosleuje Clustered Index Insert operatoru, gde se najvei deo plana
realizira
Izlaz iz njega je ID koji se prosleuje Nested Loop joinu koji dobija podatke od
Clustered Index Seek operatora nad StateProvince tabele zbog provere
referencijalnog integriteta nad stranim kljue, StateProvinceId
Assert operator proverava da li je zadovoljen referencijalni integritet
Donja grana predstavlja podatke koji se dodaju u kolonu tipa spatial data (ne radimo)
UPDATE
UPDATE [Person].[Address]
SET [City] = 'Munro', [ModifiedDate] = GETDATE()
WHERE [City] = 'Monroe' ;

Non clastered Index Scan dohvata sve potrebne redove iz indeksa da bi pronaao sve
redove koji zadovoljavaju where klauzulu
Moda trebaju dodatni indeksi?
Top operator (nije korien)
Eager Spool olakava rollback operaciju (smeta objekte koji se auriraju u temp
objekat)
Compute Scalar procenjuje izraze i generie izraunate skalarne vrednosti (npr.
Getdate())
ClusteredIndex Update identifikuje redove i aurira ih (vrednosti su deo
klasterovanog indeksa)
Obratiti panju zbog performanse kako se redovi koji se auriraju dohvataju
(Clustered ili Non-Clustered Index Seek bolje neko Non-Clustered Index Scan)
DELETE

BEGIN TRAN
DELETE FROM Person.EmailAddress
WHERE BusinessEntityID = 42
ROLLBACK TRAN

Direktan pristup klasterovanom indeksu se koristi da se pronadje red koji se


brie
Referencijalni integritet?

You might also like