Czytałem o composite indexes
i jestem trochę zdezorientowany co do zamawiania. Ta dokumentacja (nieco mniej niż w połowie) mówi
Ogólnie rzecz biorąc, w indeksie należy umieścić kolumnę, która ma być najczęściej używana.
Jednak wkrótce potem mówi
utwórz indeks złożony, stawiając na pierwszym miejscu najbardziej selektywną kolumnę; to znaczy kolumna z największą liczbą wartości.
Innymi słowy, Oracle mówi to tutaj
Jeśli wszystkie klucze są używane w klauzulach WHERE jednakowo często, wówczas uporządkowanie tych kluczy od najbardziej selektywnego do najmniej selektywnego w instrukcji CREATE INDEX najlepiej poprawia wydajność zapytania.
Znalazłem jednak odpowiedź SO, która mówi inaczej. To mówi
Ułóż kolumny tak, aby kolumna najmniej selektywna była pierwsza, a kolumna najbardziej selektywna na końcu. W przypadku ołowiu wiążącego z kolumną, który z większym prawdopodobieństwem będzie używany samodzielnie.
Pierwsza dokumentacja, o której wspomniałem, mówi, że powinieneś najpierw przejść do najczęściej używanych, podczas gdy odpowiedź SO mówi, że powinno to dotyczyć tylko rozstrzygania remisów. Następnie różnią się również w kolejności.
Ta dokumentacja również mówi skip scanning
i mówi
Pomijanie skanowania jest korzystne, jeśli w wiodącej kolumnie indeksu złożonego jest kilka różnych wartości i wiele różnych wartości w kluczu nieprowadzącym indeksu.
Kolejny artykuł mówi
Kolumna prefiksu powinna być najbardziej dyskryminująca i najczęściej używana w zapytaniach
co moim zdaniem najbardziej dyskryminujące oznaczałoby najbardziej charakterystyczne.
Wszystkie te badania wciąż prowadzą mnie do tego samego pytania; czy najbardziej selektywna kolumna powinna być pierwsza czy ostatnia? Czy pierwsza kolumna powinna być najczęściej używana i tylko najbardziej selektywna w przypadku remisu?
Artykuły te wydają się ze sobą sprzeczne, ale podają kilka przykładów. Z tego, co zebrałem, wydaje się, że bardziej efektywne least selective column
jest bycie pierwszym w kolejności, jeśli się spodziewasz Index Skip Scans
. Ale nie jestem pewien, czy to prawda.
źródło
Odpowiedzi:
Od AskTom
Jednym z argumentów za ułożeniem kolumn w indeksie złożonym w kolejności od najmniej rozróżniających (mniej wyraźnych wartości) do najbardziej dyskryminujących (bardziej wyraźnych wartości) jest kompresja klucza indeksu.
Według statystyk indeksu pierwszy indeks jest bardziej ściśliwy.
Innym jest sposób wykorzystania indeksu w zapytaniach. Jeśli najczęściej używane są zapytania
col1
,Na przykład jeśli masz pytania takie jak-
select * from t where col1 = :a and col2 = :b;
select * from t where col1 = :a;
-występowałby
index(col1,col2)
lepiej.Jeśli najczęściej używane są zapytania
col2
,select * from t where col1 = :a and col2 = :b;
select * from t where col2 = :b;
-występowałby
index(col2,col1)
lepiej. Jeśli wszystkie zapytania zawsze określają obie kolumny, nie ma znaczenia, która kolumna jest pierwsza w indeksie złożonym.Podsumowując, kluczowymi zagadnieniami przy porządkowaniu kolumn indeksu złożonego są kompresja klucza indeksu i sposób użycia tego indeksu w zapytaniach.
Bibliografia:
źródło
Najpierw najbardziej selektywna jest przydatna tylko wtedy, gdy kolumna znajduje się w rzeczywistej klauzuli WHERE.
Gdy SELECT jest według większej grupy (mniej selektywnej), a następnie być może według innych, nieindeksowanych wartości, indeks z mniej selektywnymi kolumnami może być nadal użyteczny (jeśli istnieje powód, aby nie tworzyć innego).
Jeśli jest tabela ADRES, z
COUNTRY CITY STREET, coś jeszcze ...
indeksowanie ULICY, MIASTA, PAŃSTWO przyniesie najszybsze zapytania o nazwie ulicy. Ale zapytanie do wszystkich ulic miasta, indeks będzie bezużyteczne, a zapytanie prawdopodobnie wykona pełny skan tabeli.
Indeksowanie KRAJ, MIASTO, ULICA może być nieco wolniejsze dla poszczególnych ulic, ale indeksu można używać do innych zapytań, wybierając tylko według kraju i / lub miasta.
źródło
Wybierając kolejność kolumn indeksu, nadrzędnym problemem jest:
Czy w moich zapytaniach są predykaty (równości) względem tej kolumny?
Jeśli kolumna nigdy nie pojawia się w klauzuli where, nie warto indeksować (1)
OK, więc masz tabelę i zapytania dotyczące każdej kolumny. Czasami więcej niż jeden.
Jak decydujesz, co indeksować?
Spójrzmy na przykład. Oto tabela z trzema kolumnami. Jedna zawiera 10 wartości, kolejna 1000, ostatnia 10.000:
Są to liczby wypełnione zerami. Pomoże to zwrócić uwagę na kompresję później.
Masz trzy typowe zapytania:
Co indeksujesz?
Indeks tylko kilku_wartości jest tylko nieznacznie lepszy niż pełny skan tabeli:
Jest więc mało prawdopodobne, aby warto było samodzielnie indeksować. Zapytania na Lot_vals zwracają kilka wierszy (w tym przypadku tylko 1). Jest to zdecydowanie warte indeksowania.
Ale co z zapytaniami do obu kolumn?
Jeśli indeksujesz:
LUB
Podchwytliwe pytanie!
Odpowiedź nie jest żadna.
Jasne, że kilka_wartości jest długim ciągiem. Dzięki temu możesz uzyskać dobrą kompresję. I możesz (może) uzyskać skanowanie pomijania indeksu dla zapytań przy użyciu (kilka_wartości, wiele_wartości), które mają predykaty tylko na wartości_wielkości. Ale mnie tu nie ma, chociaż działa znacznie lepiej niż pełny skan:
Czy lubisz hazard? (2)
Nadal potrzebujesz indeksu z Lot_Vals jako wiodącą kolumną. I przynajmniej w tym przypadku indeks złożony (kilka, partii) wykonuje tyle samo pracy, co jeden na jednym (partiach)
Zdarzają się przypadki, w których indeks złożony oszczędza 1-2 IO. Ale czy warto mieć dwa indeksy dla tego oszczędzania?
I jest inny problem z indeksem złożonym. Porównaj współczynnik klastrowania dla trzech indeksów, w tym LOTS_VALS:
Zauważ, że współczynnik grupowania dla kilku_botów jest 10-krotnie wyższy niż dla wielu i wielu_lotów! I to jest na stole demo z doskonałym klastrowaniem na początek. W rzeczywistych bazach danych efekt będzie prawdopodobnie gorszy.
Co w tym takiego złego?
Czynnik grupowania jest jednym z kluczowych czynników decydujących o tym, jak „atrakcyjny” jest indeks. Im wyższy, tym mniej prawdopodobne jest, że optymalizator go wybierze. Zwłaszcza jeśli lot_vals nie jest tak naprawdę unikalny, ale zwykle ma kilka wierszy na wartość. Jeśli masz pecha, może to wystarczyć, aby optymalizator uznał, że pełne skanowanie jest tańsze ...
OK, więc indeksy złożone z parametrami kilka_wartości i wartości_lotów mają tylko zalety przewagi przypadku.
Co z zapytaniami filtrującymi kilka_wartości i wiele_wartości?
Indeksy z pojedynczymi kolumnami dają tylko niewielkie korzyści. Ale w połączeniu zwracają niewiele wartości. Tak więc indeks złożony jest dobrym pomysłem. Ale w którą stronę?
Jeśli umieścisz kilka pierwszych, skompresowanie wiodącej kolumny spowoduje jej zmniejszenie
Przy mniejszej liczbie różnych wartości w kolumnie wiodącej kompresuje się lepiej. Więc jest niewiele mniej pracy na odczytanie tego indeksu. Ale tylko nieznacznie. Oba są już dobrym kawałkiem mniejszym niż oryginał (zmniejszenie rozmiaru o 25%).
I możesz pójść dalej i skompresować cały indeks!
Teraz oba indeksy powróciły do tego samego rozmiaru. Zauważ, że wykorzystuje to fakt, że istnieje relacja między nielicznymi a wieloma. Ponownie jest mało prawdopodobne, że zobaczysz tego rodzaju korzyści w prawdziwym świecie.
Do tej pory mówiliśmy tylko o kontrolach równości. Często z indeksami złożonymi będziesz mieć nierówność względem jednej z kolumn. np. zapytania takie jak „otrzymaj zamówienia / przesyłki / faktury dla klienta w ciągu ostatnich N dni”.
Jeśli masz tego rodzaju zapytania, potrzebujesz równości z pierwszą kolumną indeksu:
Zauważ, że używają przeciwnego indeksu.
TL; DR
1: W niektórych przypadkach warto uwzględnić kolumnę w indeksie, jeśli oznacza to, że wszystkie kolumny w zapytaniu znajdują się w indeksie. Umożliwia to skanowanie tylko indeksu, więc nie musisz uzyskiwać dostępu do tabeli.
2: Jeśli masz licencję na diagnostykę i strojenie, możesz zmusić plan do pominięcia skanowania za pomocą SQL Plan Management
ADDEDNDA
PS - cytowane tam dokumenty pochodzą z 9i. To naprawdę stare. Zostałbym przy czymś nowszym
źródło
select count (distinct few_vals || ':' || many_vals || ':' || lots_vals )
naprawdę powszechne? Czy Oracle nie zezwala na składnięselect count (distinct few_vals, many_vals, lots_vals )
- która nie dokonuje konkatenacji ciągów, nie potrzebuje kolumn jako typów tekstowych i nie polega na braku:
znaku?count ( distinct x, y, z )
w Oracle. Musisz więc wykonać odrębne podzapytanie i policzyć wyniki lub konkatenację jak wyżej. Zrobiłem to tutaj, aby wymusić dostęp do tabeli (zamiast skanowania tylko indeksu) i po prostu mieć jeden wiersz w wynikuJest więcej elementów zapytania, które przyczyniają się do ostatecznej decyzji o tym, od czego powinien zacząć się indeks złożony i / lub oprócz selektywności kolumny.
na przykład:
„>,> =, <, <=”
jednak aby zachować aktualność rozmowy, moja poniższa odpowiedź dotyczy następującej sytuacji:
ciągu znaków”
Z mojego doświadczenia wynika, że zarówno DBA powinna mieć na uwadze.
1) Jeśli utworzę indeks z najbardziej selektywną kolumną jako pierwszą, ale kolumna ta nie jest faktycznie używana przez większość zapytań w tej tabeli, to nie ma zastosowania dla silnika db.
2) Jeśli utworzę indeks z najczęściej używaną kolumną w zapytaniu, która jest pierwsza w indeksie, ale kolumna ma niską selektywność, wówczas moja wydajność zapytania nie będzie dobra.
Wymienię kolumny, które są najczęściej używane w 90% zapytań tabelowych. Następnie ułóż je tylko w kolejności od największej do najmniejszej.
Używamy indeksów do poprawy wydajności zapytania do odczytu, a przepływ pracy (typy zapytania do odczytu) powinien tylko napędzać tworzenie indeksu. W rzeczywistości, gdy dane rosną (miliardy wierszy), skompresowany indeks może zaoszczędzić miejsce, ale na pewno pogorszy wydajność zapytania do odczytu.
źródło
Teoretycznie najbardziej selektywna kolumna daje najszybsze wyszukiwanie. Ale w pracy natknąłem się na sytuację, w której mamy indeks złożony z 3 części, z których najbardziej selektywna jest część pierwsza. (data, autor, firma wydawnicza, powiedzmy, w tej kolejności, tabela monitoruje kciuki do góry na postach) i mam zapytanie, które wykorzystuje wszystkie 3 części. Mysql domyślnie korzysta z autorskiego indeksu tylko pomijając indeks złożony zawierający firmę i datę, mimo że są one obecne w moim zapytaniu. Użyłem indeksu siły, aby użyć kompozytu, a zapytanie faktycznie działało wolniej. Dlaczego tak się stało? Powiem ci:
Wybrałem zakres w dniu, więc pomimo tego, że data jest bardzo wybiórcza, fakt, że używamy go do skanowania zasięgu (chociaż zasięg jest stosunkowo krótki, 6 miesięcy z 6 lat danych) spowodował, że kompozyt był szkodliwy dla mysql. Aby użyć kompozytu w tym konkretnym przypadku, mysql musi pobrać wszystkie artykuły napisane od nowego roku, a następnie zanalizować, kim jest autor, i biorąc pod uwagę, że autor nie napisał tylu artykułów w porównaniu do innych autorów, mysql wolał po prostu znaleźć tego autora .
W innym przypadku zapytanie działało znacznie szybciej na kompozycie, tak było w przypadku, gdy autor był niezwykle popularny i był właścicielem większości rekordów, sortowanie według daty miało sens. Ale mysql nie wykrył tej sprawy automatycznie, musiałem wymusić indeks ... Więc wiesz, to się zmienia. Skany zakresu mogą sprawić, że Twoja selektywna kolumna nie będzie użyteczna. Dystrybucja danych może sprawić, że kolumny będą bardziej selektywne dla różnych rekordów ...
To, co zrobiłbym inaczej, to przesunięcie daty (która teoretycznie jest najbardziej selektywna) w prawo, ponieważ wiem, że teraz wykonam na niej skanowanie zakresu i to robi różnicę.
źródło
WHERE (date BETWEEN @x AND @y) AND (author = @a) AND (publishing company = @p)
to indeks włączony(author, publishing_company, date)
lub włączony(publishing_company, author, date)
byłby lepszy i zostałby użyty - bez wymuszania go.Różne przypadki dla różnych sytuacji. Poznaj swój cel; następnie utwórz swoje indeksy i uruchom plany wyjaśniania dla każdego z nich, a uzyskasz najlepszą odpowiedź na swoją sytuację.
źródło
Z kolejności kolumn w Indeksie na Zapytaj Toma:
Zgadzam się, że musimy uporządkować kolumny na podstawie klauzuli where, ale stwierdzenie „(selektywność a lub b wcale się nie liczy)” nie jest poprawne.) „Najbardziej selektywne kolumny powinny być wiodące, jeśli spełniają pierwszą rolę („klauzula gdzie”)
źródło