Badając coś innego, szukałem czegoś innego. Wygenerowałem tabele testowe z pewnymi danymi i uruchomiłem różne zapytania, aby dowiedzieć się, w jaki sposób różne sposoby pisania zapytań wpływają na plan wykonania. Oto skrypt, którego użyłem do wygenerowania losowych danych testowych:
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID('t') AND type in (N'U'))
DROP TABLE t
GO
CREATE TABLE t
(
c1 int IDENTITY(1,1) NOT NULL
,c2 int NULL
)
GO
insert into t
select top 1000000 a from
(select t1.number*2048 + t2.number a, newid() b
from [master]..spt_values t1
cross join [master]..spt_values t2
where t1.[type] = 'P' and t2.[type] = 'P') a
order by b
GO
update t set c2 = null
where c2 < 2048 * 2048 / 10
GO
CREATE CLUSTERED INDEX pk ON [t] (c1)
GO
CREATE NONCLUSTERED INDEX i ON t (c2)
GO
Biorąc pod uwagę te dane, wywołałem następujące zapytanie:
select *
from t
where
c2 < 1048576
or c2 is null
;
Ku mojemu wielkiemu zaskoczeniu, plan wykonania, który został wygenerowany dla tego zapytania, był następujący . (Przepraszamy za link zewnętrzny, jest za duży, aby zmieścić się tutaj).
Czy ktoś może mi wyjaśnić, co słychać w tych „ stałych skanach ” i „ skalarach obliczeniowych ”? Co się dzieje?
|--Nested Loops(Inner Join, OUTER REFERENCES:([Expr1010], [Expr1011], [Expr1012]))
|--Merge Interval
| |--Sort(TOP 2, ORDER BY:([Expr1013] DESC, [Expr1014] ASC, [Expr1010] ASC, [Expr1015] DESC))
| |--Compute Scalar(DEFINE:([Expr1013]=((4)&[Expr1012]) = (4) AND NULL = [Expr1010], [Expr1014]=(4)&[Expr1012], [Expr1015]=(16)&[Expr1012]))
| |--Concatenation
| |--Compute Scalar(DEFINE:([Expr1005]=NULL, [Expr1006]=NULL, [Expr1004]=(60)))
| | |--Constant Scan
| |--Compute Scalar(DEFINE:([Expr1008]=NULL, [Expr1009]=(1048576), [Expr1007]=(10)))
| |--Constant Scan
|--Index Seek(OBJECT:([t].[i]), SEEK:([t].[c2] > [Expr1010] AND [t].[c2] < [Expr1011]) ORDERED FORWARD)
źródło
62
służy do porównania równości. Myślę, że60
musi to oznaczać, że zamiast> AND <
jak pokazano w planie, w rzeczywistości dostajesz,>= AND <=
chyba że jest to wyraźnaIS NULL
flaga, może (?), A może bit2
wskazuje na coś innego niezwiązanego i60
nadal jest równy, jak wtedy, gdy to robięset ansi_nulls off
i zmieniam nac2 = null
to, pozostaje na60
Ciągłe skanowanie to sposób, w jaki SQL Server tworzy wiadro, w którym umieści coś później w planie wykonania. Tutaj zamieściłem dokładniejsze wyjaśnienie . Aby zrozumieć, do czego służy ciągłe skanowanie, musisz dokładniej przyjrzeć się planowi. W tym przypadku do wypełnienia przestrzeni utworzonej przez ciągłe skanowanie używane są operatory obliczania skalarnego.
Operatory obliczeń skalarnych są ładowane z wartością NULL i wartością 1045876, więc z pewnością będą one używane z łączeniem pętli w celu filtrowania danych.
Naprawdę fajne jest to, że ten plan jest Trywialny. Oznacza to, że przeszedł minimalny proces optymalizacji. Wszystkie operacje prowadzą do interwału scalania. Służy to do utworzenia minimalnego zestawu operatorów porównania dla wyszukiwania indeksu ( szczegóły na ten temat tutaj ).
Chodzi o to, aby pozbyć się nakładających się wartości, aby móc następnie wyciągać dane przy minimalnej liczbie przejść. Mimo że nadal używa operacji pętli, zauważysz, że pętla wykonuje się dokładnie raz, co oznacza, że jest to skutecznie skanowanie.
DODATEK: Ostatnie zdanie jest wyłączone. Były dwie próby. Źle odczytałem plan. Reszta pojęć jest taka sama, a cel, minimalne podanie, jest taki sam.
źródło