W SQL Server 2008 dodano typ danych daty .
Rzutowanie datetime
kolumny na sargabledate
jest możliwe i można użyć indeksu na datetime
kolumnie.
select *
from T
where cast(DateTimeCol as date) = '20130101';
Inną opcją jest użycie zakresu.
select *
from T
where DateTimeCol >= '20130101' and
DateTimeCol < '20130102'
Czy te zapytania są równie dobre, czy jedno powinno być preferowane nad drugim?
sql-server
Mikael Eriksson
źródło
źródło
where cast(date_column as date) = 'value'
gdy jest prezentowany w języku C # podobnym dowhere obj.date_column.Date == date_variable
.Odpowiedzi:
Mechanizm leżący u podstaw możliwości rzutowania nazywa się dynamicznym wyszukiwaniem .
SQL Server wywołuje funkcję wewnętrzną,
GetRangeThroughConvert
aby uzyskać początek i koniec zakresu.Nieoczekiwanie nie jest to ten sam zakres, co twoje dosłowne wartości.
Tworzenie tabeli z wierszem na stronę i 1440 wierszami dziennie
Potem biegnie
Pierwsze zapytanie zawiera
1443
odczyty, a drugie2883
odczytuje cały dodatkowy dzień, a następnie odrzuca je względem pozostałego predykatu.Plan pokazuje, że predykatem wyszukiwania jest
Zamiast
>= '20130101' ... < '20130102'
tego czyta,> '20121231' ... < '20130102'
a następnie odrzuca wszystkie2012-12-31
wiersze.Kolejną wadą polegającą na tym jest to, że szacunki liczności mogą nie być tak dokładne, jak w przypadku tradycyjnego zapytania o zakres. Można to zobaczyć w poprawionej wersji SQL Fiddle .
Wszystkie 100 wierszy w tabeli jest teraz zgodnych z predykatem (z odstępami czasu 1 minuta wszystkie w tym samym dniu).
Drugie zapytanie (zakres) poprawnie szacuje, że 100 będzie pasowało i używa skanowania indeksu klastrowego.
CAST( AS DATE)
Zapytania nieprawidłowo szacuje, że tylko jeden wiersz będzie pasował i tworzy plan z najważniejszych wyszukiwań.Statystyki nie są całkowicie ignorowane. Jeśli wszystkie wiersze w tabeli mają to samo
datetime
i pasuje do predykatu (np.20130101 00:00:00
Lub20130101 01:00:00
), wówczas plan pokazuje skanowanie indeksu klastrowego z szacowanymi 31,6228 wierszami.Więc w takim przypadku wydaje się, że szacunek pochodzi z formuły tutaj .
Jeśli wszystkie wiersze w tabeli mają to samo
datetime
i nie pasuje do predykatu (np.20130102 01:00:00
), Wówczas wraca do szacowanej liczby wierszy 1 i planu z przeglądami.W przypadkach, w których tabela ma więcej niż jedną
DISTINCT
wartość, szacunkowe wiersze wydają się być takie same, jakby zapytanie szukało dokładnie20130101 00:00:00
.Jeśli histogram statystyczny zawiera krok,
2013-01-01 00:00:00.000
wówczas szacunek będzie oparty naEQ_ROWS
(tzn. Nie będzie uwzględniał innych czasów w tym dniu). W przeciwnym razie, jeśli nie ma kroku, wygląda na to, że wykorzystujeAVG_RANGE_ROWS
kroki z otaczających kroków.Ponieważ
datetime
dokładność wynosi około 3 ms w wielu systemach, będzie bardzo niewiele rzeczywistych zduplikowanych wartości, a liczba ta będzie wynosić 1.źródło
TL;DR
część z kilkoma punktorami w różnych przypadkach, dodając, czy w takim przypadku obsada do tej pory jest dobrym pomysłem, czy nie?Wiem, że ma to od dawna Great Answer® od Martina, ale chciałem dodać tutaj pewne zmiany w zachowaniu w nowszych wersjach SQL Server. Wydaje się, że zostało to przetestowane tylko do 2008R2.
Dzięki nowym WSKAZÓWKOM UŻYTKOWANIA, które umożliwiają wykonanie podróży w czasie oszacowania liczności, możemy zobaczyć, kiedy coś się zmieniło.
Przy użyciu tej samej konfiguracji, co w SQL Fiddle.
Możemy przetestować różne poziomy:
Plany wszystkich z nich są dostępne tutaj . Oba poziomy kompatowania 100 i 110 dają kluczowy plan wyszukiwania, ale zaczynając od poziomu zgodności 120, zaczynamy uzyskiwać ten sam plan skanowania z szacunkami 100 wierszy. Dotyczy to poziomu zgodności 140.
Oszacowanie liczności dla
>= '20130101', < '20130102'
planów pozostaje na poziomie 100, czego oczekiwano.źródło