Pamiętam, jak kiedyś przeczytałem, że indeksowanie pola o niskiej liczności (mała liczba odrębnych wartości) nie jest naprawdę warte wykonywania. Przyznaję, że nie wiem wystarczająco dużo o działaniu indeksów, aby zrozumieć, dlaczego tak jest.
A co, jeśli mam tabelę ze 100 milionami wierszy i wybieram rekordy, w których pole bitowe ma wartość 1? Powiedzmy, że w dowolnym momencie istnieje tylko kilka rekordów, w których pole bitowe ma wartość 1 (w przeciwieństwie do 0). Czy warto indeksować to pole bitowe, czy nie? Czemu?
Oczywiście mogę to po prostu przetestować i sprawdzić plan wykonania i zrobię to, ale jestem też ciekawa teorii, która za tym stoi. Kiedy liczność ma znaczenie, a kiedy nie?
sql-server
indexing
jeremcc
źródło
źródło
Odpowiedzi:
Zastanów się, czym jest indeks w SQL - a indeks jest tak naprawdę kawałkiem pamięci wskazującym na inne fragmenty pamięci (tj. Wskaźniki do wierszy). Indeks jest podzielony na strony, dzięki czemu części indeksu mogą być ładowane i usuwane z pamięci w zależności od użycia.
Kiedy pytasz o zestaw wierszy, SQL używa indeksu, aby znaleźć wiersze szybciej niż skanowanie tabeli (przeglądanie każdego wiersza).
SQL ma indeksy klastrowe i nieklastrowe. Rozumiem, że indeksy klastrowe grupują podobne wartości indeksów na tej samej stronie. W ten sposób, gdy pytasz o wszystkie wiersze pasujące do wartości indeksu, SQL może zwrócić te wiersze ze zgrupowanej strony pamięci. Dlatego próba grupowania indeksowania kolumny GUID jest złym pomysłem - nie próbujesz grupować losowych wartości.
Podczas indeksowania kolumny zawierającej liczby całkowite indeks SQL zawiera zestaw wierszy dla każdej wartości indeksu. Jeśli masz zakres od 1 do 10, masz 10 wskaźników indeksu. W zależności od liczby wierszy może to być stronicowane inaczej. Jeśli zapytanie szuka indeksu pasującego do „1”, a następnie tam, gdzie nazwa zawiera „Fred” (zakładając, że kolumna Nazwa nie jest indeksowana), SQL bardzo szybko pobiera zestaw wierszy pasujących do „1”, a następnie tabela przeszukuje tabelę w celu znalezienia reszty.
Więc to, co naprawdę robi SQL, to próba zmniejszenia zestawu roboczego (liczby wierszy), przez który musi iterować.
Indeksując pole bitowe (lub jakiś wąski zakres), redukujesz zestaw roboczy tylko o liczbę wierszy pasujących do tej wartości. Jeśli masz małą liczbę pasujących wierszy, znacznie zmniejszyłoby to zestaw roboczy. W przypadku dużej liczby wierszy z rozkładem 50/50 może to przynieść niewielki wzrost wydajności w porównaniu z utrzymaniem aktualności indeksu.
Powodem, dla którego wszyscy mówią, aby testować, jest to, że SQL zawiera bardzo sprytny i złożony optymalizator, który może zignorować indeks, jeśli zdecyduje, że skanowanie tabeli jest szybsze, może użyć sortowania, lub może organizować strony pamięci, jak cholernie lubi.
źródło
Właśnie natknąłem się na to pytanie z innej strony. Zakładając, że twoje stwierdzenie, że tylko kilka rekordów przyjmuje wartość 1 (i są to te, które Cię interesują), filtrowany indeks może być dobrym wyborem. Coś jak:
Spowoduje to utworzenie znacznie mniejszego indeksu, którego optymalizator jest wystarczająco inteligentny, aby użyć go, gdy jest to predykat w zapytaniu.
źródło
yourBitColumn = @value
, optymalizator nie może określić, czy filtrowany indeks jest użyteczny.100 milionów rekordów, a tylko kilka ma pole bitowe ustawione na 1? Tak, myślę, że indeksowanie pola bitowego zdecydowanie przyspieszyłoby odpytywanie rekordów bit = 1. Powinieneś pobrać logarytmiczny czas wyszukiwania z indeksu, a następnie dotknąć tylko kilku stron z rekordami bit = 1. W przeciwnym razie musiałbyś dotknąć wszystkich stron tabeli rekordów 100 milionów.
Z drugiej strony, zdecydowanie nie jestem ekspertem od baz danych i może brakować czegoś ważnego.
źródło
Jeśli twoja dystrybucja jest dość znana i niezrównoważona, na przykład 99% wierszy ma bit = 1, a 1% to bit = 0, kiedy wykonasz klauzulę WHERE z bitem = 1, pełne skanowanie tabeli będzie mniej więcej w tym samym czasie co skanowanie indeksu. Jeśli chcesz mieć szybkie zapytanie, w którym bit = 0, najlepszym sposobem, jaki znam, jest utworzenie przefiltrowanego indeksu, dodając klauzulę WHERE bit = 0. W ten sposób indeks ten będzie przechowywać tylko 1% wiersz. Wtedy wykonanie WHERE bit = 0 po prostu pozwoli optymalizatorowi zapytań wybrać ten indeks, a wszystkie wiersze z niego będą miały bit = 0. Masz również tę zaletę, że wymagana jest bardzo mała ilość miejsca na dysku, porównując pełny indeks na tym bicie .
źródło
Chociaż nie sądzę, żebym indeksował TYLKO kolumnę bitową samodzielnie, bardzo często dołącza się kolumny bitowe jako część indeksu złożonego.
Prostym przykładem może być indeks ACTIVE, LASTNAME zamiast tylko nazwiska, gdy Twoja aplikacja prawie zawsze szuka aktywnych klientów.
źródło
Jeśli tego nie czytałeś, Jason Massie napisał niedawno artykuł, w którym omówiono ten właśnie temat.
http://statisticsio.com/Home/tabid/36/articleType/ArticleView/articleId/302/Never-Index-a-BIT.aspx
Edycja: nowa lokalizacja artykułu - http://sqlserverpedia.com/blog/sql-server-bloggers/never-index-a-bit
Maszyna Wayback dla poprzednio „Nowego” artykułu: http://web.archive.org/web/20120201122503/http://sqlserverpedia.com/blog/sql-server-bloggers/never-index-a-bit/
Nowa lokalizacja SQL Server Pedia to Toadworld, w której znajduje się nowy artykuł od Kennetha Fishera omawiający ten temat:
http://www.toadworld.com/platforms/sql-server/b/weblog/archive/2014/02/17/dba-myths-an-index-on-a-bit-column-will-never-be- used.aspx
maszyna wayback: http://web.archive.org/web/20150508115802/http://www.toadworld.com/platforms/sql-server/b/weblog/archive/2014/02/17/dba-myths-an -index-on-a-bit-column-will-never-be-used.aspx
źródło
Oczywiście, że warto, zwłaszcza jeśli chcesz pobrać dane według tej wartości. Byłoby to podobne do użycia rzadkiej macierzy zamiast normalnej macierzy.
Teraz w SQL 2008 możesz korzystać z funkcji partycjonowania i możesz filtrować dane, które trafiają do indeksu. Wadą wcześniejszych wersji byłoby to, że indeks byłby tworzony dla wszystkich danych, ale można to zoptymalizować, przechowując interesujące wartości w oddzielnej grupie plików.
źródło
Jak powiedzieli inni, będziesz chciał to zmierzyć. Nie pamiętam, gdzie to przeczytałem, ale kolumna musi mieć bardzo wysoką liczność (około 95%), aby indeks był skuteczny. Najlepszym sposobem na to byłoby zbudowanie indeksu i zbadanie planów wykonania dla wartości 0 i 1 pola BIT. Jeśli widzisz operację wyszukiwania indeksu w planie wykonania, wiesz, że Twój indeks będzie używany.
Najlepszym sposobem postępowania byłoby przetestowanie podstawowej tabeli SELECT * FROM WHERE BitField = 1; zapytaj i powoli buduj funkcjonalność z tego miejsca krok po kroku, aż uzyskasz realistyczne zapytanie dla swojej aplikacji, sprawdzając plan wykonania na każdym kroku, aby upewnić się, że wyszukiwanie indeksu jest nadal używane. Wprawdzie nie ma gwarancji, że ten plan wykonania zostanie wykorzystany w produkcji, ale jest duża szansa, że tak będzie.
Niektóre informacje można znaleźć na forach sql-server-performance.com oraz w przywołanym artykule
źródło
„Pamiętam, jak kiedyś przeczytałem, że indeksowanie pola o niskiej liczności (mała liczba odrębnych wartości) nie jest naprawdę warte wykonywania”
Dzieje się tak, ponieważ SQL Server prawie zawsze okaże się bardziej efektywne, aby po prostu wykonać skanowanie tabeli niż odczytać indeks. Więc w zasadzie twój indeks nigdy nie zostanie użyty i szkoda go utrzymywać. Jak powiedzieli inni, może to być w porządku w indeksie złożonym.
źródło
Jeśli Twoim celem jest szybsze wyszukiwanie rekordów, w których wartość pola bitowego jest równa „1”, możesz wypróbować zindeksowany widok tabeli bazowej, która zawiera tylko rekordy, w których pole bitowe jest równe „1”. W wersji korporacyjnej, jeśli zapytanie może korzystać z widoku indeksowanego zamiast określonej tabeli w celu poprawy wydajności zapytania, użyje widoku. Teoretycznie zwiększyłoby to szybkość zapytań wybierających, które szukają tylko rekordów z wartością pola bitowego równą „1”.
http://www.microsoft.com/technet/prodtechnol/sql/2005/impprfiv.mspx
Wszystko to zakłada, że jesteś Microsoft SQL Server 2005 Enterprise. To samo może dotyczyć roku 2008, nie znam tej wersji.
źródło
Jeśli chcesz wiedzieć, czy indeks ma pożądane efekty: przetestuj i przetestuj ponownie.
Ogólnie rzecz biorąc, nie potrzebujesz indeksu, który nie zawęża wystarczająco tabeli, ze względu na koszt utrzymania indeksu. (koszt> zysk). Ale jeśli indeks w twoim przypadku przeciął stół na pół, możesz coś zyskać, ale nie wyrzucisz tego na stół. Wszystko zależy od dokładnego rozmiaru / struktury tabeli i tego, jak z niej korzystasz (liczba odczytów / zapisów).
źródło
Samo w sobie nie, ponieważ powoduje to bardzo małą selektywność. Jako część indeksu złożonego. całkiem możliwe, ale tylko po innych kolumnach równości.
źródło
Nie można indeksować pola bitowego w programie SQL Server 2000, jak wskazano wówczas w Books Online:
Tak, jeśli masz tylko kilka wierszy spośród milionów, indeks pomoże. Ale jeśli chcesz to zrobić w tym przypadku, musisz zrobić kolumnę a
tinyint
.Uwaga : Enterprise Manager nie pozwoli ci utworzyć indeksu na kolumnie bitowej. Jeśli chcesz, możesz nadal ręcznie utworzyć indeks na kolumnie bitowej:
Ale SQL Server 2000 tak naprawdę nie będzie korzystał z takiego indeksu - uruchamiając zapytanie, w którym indeks byłby idealnym kandydatem, np .:
SQL Server 2000 wykona zamiast tego skanowanie tabeli, zachowując się tak, jakby indeks w ogóle nie istniał. Jeśli zmienisz kolumnę na tinyint, SQL Server 2000 wykona przeszukiwanie indeksu. Ponadto następujące nieobjęte zapytanie:
Wykona przeszukiwanie indeksu, po którym nastąpi wyszukiwanie zakładek.
SQL Server 2005 ma ograniczoną obsługę indeksów w kolumnach bitowych. Na przykład:
spowoduje przeszukanie indeksu przez indeks pokrywający. Ale przypadek nieobjęty:
nie spowoduje przeszukania indeksu, po którym nastąpi wyszukiwanie zakładek, wykona skanowanie tabeli (lub skanowanie indeksu klastrowego) zamiast przeszukiwania indeksu, po którym nastąpi wyszukiwanie zakładek.
Weryfikowane przez eksperymenty i bezpośrednią obserwację.
źródło
bardzo późna odpowiedź ...
Tak, może być przydatne według zespołu SQL CAT (zaktualizowane, skonsolidowane)
źródło
Czy to typowe zapytanie? Może się to opłacać, szukając „garści” płyt, ale nie pomoże ci zbytnio w innych wierszach. Czy istnieją inne sposoby identyfikacji danych?
źródło
Kardynalność to jeden czynnik, a drugi to to, jak dobrze indeks dzieli dane. Jeśli masz około połowy jedynek i połowę zer, to pomoże. (Zakładając, że ten indeks jest lepszą ścieżką do wyboru niż jakiś inny indeks). Jednak jak często wstawiasz i aktualizujesz? Dodanie indeksów dla wydajności SELECT również szkodzi wydajności INSERT, UPDATE i DELETE, więc miej to na uwadze.
Powiedziałbym, że jeśli 1 do 0 (lub odwrotnie) nie jest lepsze niż 75% do 25%, nie przejmuj się.
źródło
mierzyć czas reakcji przed i po i przekonać się, czy warto; teoretycznie powinno to poprawić wydajność zapytań używających indeksowanych pól, ale tak naprawdę zależy to od dystrybucji wartości prawda / fałsz i innych pól zaangażowanych w zapytania, które Cię interesują
źródło
Ian Boyd ma rację, mówiąc, że nie można tego zrobić za pomocą Enterprise Manager dla SQL 2000 (patrz jego uwaga dotycząca tworzenia go za pomocą T-SQL.
źródło
Musisz być sprytny, aby zapytać, musisz znać wartość obciążenia swojej kolumny, jeśli w systemie jest więcej obciążenia z prawdą i chcesz sprawdzić wszystkie wartości prawdziwe, napisz zapytanie, aby sprawdzić, czy nie jest fałszywe .. to bardzo pomoże , to tylko sztuczka.
źródło