ceturtdiena, 2011. gada 24. februāris

SARG optimizācija

SARG (no angļu val. Search Arguments) ir tā vaicājuma daļa, ar kuras palīdzību tiek filtrēti vaicājuma atgrieztie rezultāti- gan tie, kas ir tabulu sasiešanas On daļā, gan tie, kas ir where daļā. Bieži vien šī vaicājuma daļa arī nosaka, kādi indeksi tiks izmantoti vaicājuma optimizēšanai.

Šajā rakstā daži likumi, kas neļauj SQL vaicājumu optimizātoram "izdomāt", ka var izmantot indeksus. Lai ilustrētu ar piemēru, izmantošu dbo.TestTable tabulu ar indeksu uz kolonnas "skaitlis" (jau sastapta vairākos rakstos iepriekš):
Create Table dbo.TestTable
(
   TestTableID int Identity primary key,
   Skaitlis int,
   TrisBurti char(3),
   MainigsGarums NVarChar(20),
   GarsTeksts NVarChar(100)
)
Go
Set NoCount ON
Declare @i int
Set @i = 0
While @i < 10000
Begin
   Insert Into dbo.TestTable(Skaitlis, TrisBurti, MainigsGarums, GarsTeksts)
      Values(Cast(Rand()*1000 as int), 'abc', Replicate('x', Cast(Rand()*20 as int)), Replicate('x',100));
   Set @i = @i + 1;
End
Go
Create Index IX_Skaitlis On dbo.TestTable
(
    Skaitlis
)
Lai varētu analizēt vaicājumu rezultātus, uzstādīsim, lai tiek parādīta IO Statistika:
set statistics io on
Efektīvs vaicājums uz šo tabulu un attiecīgo indeksu izskatītos šādi:
select TestTableID from dbo.TestTable
where skaitlis = 11
Tiek veiktas 2 loģiskās lasīšanas operācijas, tas nozīmē, ka indeksā tika atrasta vajadzīgā vērtība un attiecīgās indeksa beigu virsotnes (kurā glabājas TestTableID. Ja nav skaidrs kāpēc tāds apgalvojums, tad šeit var palasīt: Indeksi (non-clustered indexes)).

Sliktie un labie piemēri

1. Neizmantot matemātiskas darbības uz indeksa kolonnas jo tādā gadījumā indeksā vērtība tiks meklēta to pārlasot, nevis meklējot konkrēto vērtību! Šādi tiek veiktas 20 loģiskās lasīšanas operācijas:
select TestTableID from dbo.TestTable
where (skaitlis - 1) = 11
tā vietā pavisam mierīgi matemātisko operāciju var pārnest uz otru pusi un atkal iegūt 2 loģiskās lasīšanas operācijas (lieki piebilst- rezultāti būs identiski):
select TestTableID from dbo.TestTable
where skaitlis = 11 + 1
2. Neizmantot tipa konversāciju uz indeksa kolonnas kad vien iespējams. Notiek tas pats kas iepriekš, 20 loģiskās lasīšanas operācijas (starp citu, šis varētu būt tipisks gadījums uz datuma kolonnas, kad meklē konkrēta datuma rindas lai atbrīvotos no laika daļas- cast uz datuma pataisot par nvarchar un salīdzina ar tekstu. Tādā gadījumā varētu apsvērt Between izmantošanu, lai izvairītos no cast):
select TestTableID from dbo.TestTable
where cast(skaitlis as nvarchar) = '12'
Šādi būs 2 loģiskās lasīšanas operācijas:

select TestTableID from dbo.TestTable
where skaitlis = cast('12' as int)
 3. Neizmantot funkcijas uz indeksa kolonnas. Atkal 20 loģiskās lasīšans operācijas:
select TestTableID from dbo.TestTable
where Power(skaitlis,2) = 144
 Tā vietā var panākt to pašu rezultātu, bet jau tikai 2 loģiskās lasīšanas operācijas:
select TestTableID from dbo.TestTable
where skaitlis = SQRT(144)
Kopsavilkums
Tātad tāds pamata likums varētu būt- kad vien iespējams, visas darbības veikt ar mainīgo, nevis ar indeksa kolonnu.
Lai arī aprakstītie likumi ir samērā vienkārši, bieži vien par tiem aizmirst vai nemaz neiedomājas.

Ak jā, un lai pēc sevis satīrītu:
drop table dbo.TestTable

Nav komentāru:

Komentāra publicēšana