Like ‘[A-Z]QLServer’ vs. like ‘_QLServer’
ostatnio na forum wss.pl pojawił się wątek o przeszukiwaniu ciągów znakowych, punktem wyjścia dla niniejszego researchu był post Pawła Potasińskiego (aka brejk):
————————————————————————————-
Akodo_Shado:
select name from slowa
where name LIKE ‘kote[a-z]%’.
Efekt był piorunujący! 140 wyników w mig.
brejk:
I nic dziwnego. Przecież w tych 3,5 mln słów ile mogło się zaczynać od “kote” :-) Naturalne, że przy tak dobrej selektywności serwer może użyć indeksu na polu name (jakiegokolwiek indeksu, warto dodać).
Akodo_Shado:
Konsekwencja tego problemu jest też taka, że
o ile ‘kote[a-z]%’ robi się błyskawicznie o tyle
‘[a-z]%otek’ już nie koniecznie.
brejk:
Co w tym dziwnego? W drugim przypadku serwer musi przecież przeszukać praktycznie całą tabelę (od a do z).
————————————————————————————-
Paweł miał rację, to jasne … ale ale … od czego jest kombinacja CTRL + L :)
research rozpoczął się od zrobienia tabeli:
create table test2 ( id int, ciag char(36),ciag_rev char(36)); go declare @i int set @i = 0 while (@i < 1000000) begin insert into test2 (id, ciag) values (@i,convert(char(36), newid())) set @i = @i + 1 end
Pierwszy pomysł jaki mi wpadł do głowy był taki żeby zrobić drugą kolumnę z:
update test2 set ciag_rev = reverse(ciag) go
mamy tabele bez indeksów, robię z niej dwa zapytania jak poniżej:
(mam w kolumnie ciag wartosc: ‘00006BB4-215F-424E-8B99-9A69A5C94A97′)
select ciag,id from test2 where ciag like '[0-9]0006BB4-215F-424E-8B99-9A69A5C94A97' select ciag_rev,id from test2 where ciag_rev like '79A49C5A96A9-99B8-E424-F512-4BB6000[0-9]'
wybieram CTRL+L i widze:

następnie robię 1x klastrowany + 2x nieklastrowany:
create clustered index idx_id on test2 (id) create nonclustered index idx_ciag on test2 (ciag) create nonclustered index idx_ciag_rev on test2 (ciag_rev)
wykonuje te same 2 zapytania:

zmienia się plan wykonania (nie mamy już table scan, mamy index seek … ale tak czy siak nie ma znaczenia czy nieznany znak znajduje się jako pierwszy czy jako ostatni! Sprawdzam dalej podmieniając aż do: ‘[0-9][0-9][0-9][0-9][0-9]BB4-215F-424E-8B99-9A69A5C94A97′ i dalej nic …. nie ma znaczenia czy nieznane znaki są na końcu czy na początku…
dopiero kiedy wykonam:
select ciag,id from test2 where ciag like '%0006BB4-215F-424E-8B99-9A69A5C94A97'
select ciag_rev,id from test2 where ciag_rev like '79A49C5A96A9-99B8-E424-F512-4BB6000%'
sprawa się wyjaśnia …

Wniosek:
wskazywać SQL Serverowi czego może sie spodziewać a wówczas nawet jeśli nie będziemy znali pierwszych znaków to można próbować się ograniczać dzięki czemu:
- seek bedzie jeśli użyjemy:
[0-9]CiagZnakow
[a-zA-Z0-9]CiagZnakow
- scan będzie jeśli:
_CiagZnakow
%CiagZnakow
Jeśli mimo wszystko ktoś musi specyfikować ciągi znaków przy pomocy _ lub % to wówczas można spróbować dołożyć kolumnę z odwróconą kolejnością liter ?