ceturtdiena, 2011. gada 21. jūlijs

SARG optimizācija II, meklēšana char un nchar kolonnās

Šoreiz vēl viens raksts par par vaicājumu parametriem (speciālgadījums rakstā SARG optimizācija minētajam). Konteksts šim ir datu tipu char un nchar atšķirības, netiešā veidā arī kolācijas, par ko nākotnē tiek domāts uzrakstīt vairāk (pirmais netiešais tēmas ievadraksts bija Kārtošana un kolācijas).

Par kolācijām un datu tipiem
Datu tipi char un nchar (tāpat kā varchar un nvarchar), īsi sakot, atšķiras ar to, ka char glabā katru simbolu vienā baitā, kamēr nchar glabā katru simbolu divos baitos. Tas arī nozīmē, ka char var saglabāt mazāk dažādu simbolu kā nchar. Un galu galā- char laukā simboli tiek kodēti izmantojot norādīto kolāciju, kamēr nchar laukā- izmantojot Unicode kodējumu (par to plašāk citreiz).
Apskatīsim šādu vaicājumu:
Select 'Jānis' LatvianCol, N'Jānis' UnicodeCol
Tātad- tiek atgrieztas divas kolonnas- 'LatvianCol' un 'UnicodeCol'. Šajā situācijā redzama atšķirība vaicājumu rezultātos nav. Bet atšķirība ir. Atkal, daudz neiegrimstot detaļās- pirmā kolonnā dati tiek kodēti izmantojot vienu baitu, otrajā kolonnā divus baitus. Un atšķirība ir tādēļ, ka vienā gadījumā teksta lauks ir atzīmēts ar pēdiņām, bet otrā gadījumā, pēdiņām priekšā ir N burts (N'Jānis').
Pārtulkoju vārdu "Karsts" uz arābu valodu (jo ārā patiešām ir ļoti karsts), un ieguvu ilustratīvāku piemēru:
Tātad- viens simbols ir par maz, lai kodētu arābu burtus, tādēļ tiek aizstāti ar '???' simboliem. Šeit būtu daudz ko piebilst un papildināt, bet kā jau minēju- šoreiz galvenā uzmanība uz to, ka ir atšķirība, vai tekstu ieliekam pēdiņās ('Jānis'), vai ieliekam pēdiņās un pieliekam priekšā N burtu (N'Jānis')

Vaicājumu parametri
Lai neatkārtotos, vislabāk būtu, ja būtu vismaz pārskriets pāri rakstam SARG optimizācija.
Kad tas izdarīts, saliekam visu kopā, un apskatām šādu piemēru (Piemēra nolūkos veidojam tabulu):
Create Table dbo.TestTable
(
   TestTableID int Identity primary key,
   Skaitlis VarChar(50),
   NSkaitlis NVarChar(50)
)
Go
Set NoCount ON
Declare @i int
Set @i = 0
While @i < 10000
Begin
   Insert Into dbo.TestTable(Skaitlis, NSkaitlis)
      Values(Cast(Rand()*10000000 as VarChar(50)),
        Cast(Rand()*10000000 as NVarChar(50)) );
   Set @i = @i + 1;
End
Go
Create Index IX_Skaitlis On dbo.TestTable
(
    Skaitlis
)
Go
Create Index IX_MainigsGarums On dbo.TestTable
(
    NSkaitlis
)
Tātad- ir divas kolonas- "Skaitlis" un "NSkaitlis". Abās tiek glabātas nejaušas skaitliskas vērtības pārvērstas tekstuālā formātā. Vienā gadījumā VarChar kolonnā, otrā gadījumā NVarChar kolonnā. Abām kolonnām ir izveidots indeks.
Un tagad 4 vaicājumi:

Select * From dbo.TestTable Where NSkaitlis = '111' --OK
Select * From dbo.TestTable Where NSkaitlis = N'111' --OK
Select * From dbo.TestTable Where Skaitlis = '111' --OK
Select * From dbo.TestTable Where Skaitlis = N'111' --Slikti
Visos 'OK' gadījumos vaicājuma izpildes plāns būs labs- rezultāts tiks meklēts indeksā, kamēr sliktajā gadījumā, indeks tiks pārlasīts, visas tekstuālās vērtības konvertētas un tikai tad salīdzinātas ar meklējamo tekstu.

Pirmajā gadījumā var "zem pārsega" pārkodēt meklējamo '111' uz N'111' (kodēt tos pašus redzamos simbolus izmantojot citu kodu tabulu).
Otrajā un trešajā gadījumā mēs salīdzinām vienādus datu tipus, līdz ar to nekāda datu tipu konvertācija nav vajadzīga.
Pēdējā, sliktajā, gadījumā SQL Server nevar automātiski pārkonvertēt divos baitos kodētu vērtību uz vienā baitā glabātu vērtību, tādēļ nekas cits neatliek, kā konvertēt kolonnas datus uz diviem baitiem. Tas beidzas ar to, ka ir jānolasa pilnīgi visas attiecīgās kolonnas vērtības, katra no tām jākonvertē un jāsalīdzina ar parametru vērtību.

Kopsavilkums
pirmais, ko rakstā gribēju pateikt:
- NChar kolonnu salīdzināt ar NChar parametru ir ļoti labi
- NChar kolonnu salīdzināt ar Char parametru ir labi
- Char kolonnu salīdzināt ar Char parametru ir ļoti labi
- Char kolonnu salīdzināt ar NChar parametru ir slikti
otrais:
Select * From Tabula Where colX = 'vērtība' 
nav tas pats, kas
Select * From Tabula Where colX = N'vērtība'

1 komentārs:

  1. SQL 2012 situācija ir labāka- "Slikti" vairs nebūs tik slikti- būs brīdinājums (Warning), bet netiks pārlasītas visas vērtības.

    AtbildētDzēst