2013-07-25 15 views
12

W naszej bazie mamy ten stół z 200.000 wierszyDlaczego program SQL Server nie korzysta z mojego indeksu?

CREATE TABLE dbo.UserTask (
    UserTask_ID int NOT NULL IDENTITY (1, 1), 
    UserTask_SequenceNumber int NOT NULL DEFAULT 0, 
    UserTask_IdEntitat uniqueidentifier NOT NULL, 
    UserTask_Subject varchar(100) NOT NULL, 
    UserTask_Description varchar(500) NOT NULL, 
      ..... 
      ..... 
    CONSTRAINT [PK_UserTask] PRIMARY KEY CLUSTERED 
    (
     [UserTask_ID] ASC 
    ) ON [PRIMARY] 
) ON [PRIMARY] 

Stworzyłem indeksu na UserTask_IdEntitat kolumny

CREATE NONCLUSTERED INDEX IX_UserTask_IDEntitat ON dbo.UserTask 
(
    UserTask_IDEntitat 
) 

wykonując następujące zapytanie, plan wykonania pokazuje nam, że indeks UserTask_IDEntitat służy wykonać zapytanie:

SELECT UserTask_ID 
    FROM UserTask 
WHERE UserTask_IdEntitat = @IdEntitat 
ORDER BY UserTask_LastSendSystemDateTime desc 

ale jeśli dodać kolejną kolumnę w Select lista, wówczas indeks nie jest używany

SELECT UserTask_ID, UserTask_SequenceNumber, UserTask_IDEntitat, ....., UserTask_Subject 
    FROM UserTask 
WHERE UserTask_IdEntitat = @IdEntitat 
ORDER BY UserTask_LastSendSystemDateTime desc 

Dlaczego dodanie kolumna różni się od podstawowego klucza sprawia, że ​​plan wykonania SQL Server nie używa indeksu na kolumnie UserTask_IDEntitat?

Po tym linku http://bytes.com/topic/sql-server/answers/144592-sqlsever-not-using-index wydaje się, że liczba razy, że filtrowana wartość jest powtarzana w kolumnie, Może to spowodować, że indeks nie jest używany, ale próbowałem robić kwerendę z wartości @IdEntitat, która jest powtarzana 60 000 razy i inne, które powtarza się tylko 175 razy, a wyniki są takie same, indeks na kolumnie IDEntitat jest ignorowany.

To mnie doprowadza do szału !!!

Dzięki za pomoc.

+3

Jeśli jesteś na odpowiedniej wersji, a jest to wspólny zapytania, warto zajrzeć do 'ZAWIERAJĄ 'ing' _SequenceNumber' w indeksie. –

+0

... i 'LastSendSystemDateTime' również, jak sądzę. (Aby pomóc "zamówić przez"). –

Odpowiedz

32

OK - tak długo, jak wybrać tylko kolumny, która znajduje się w indeksie, czy coś z klucza klastrowego (zwykle jest to klucz podstawowy), to wskaźnik będzie używany, ponieważ SQL Server może znaleźć wszystkie potrzebne informacje (kolumna UserTask_IDEntitat i kolumna (y) klastra indeksu) na poziomie liścia struktury nawigacji indeksu. Dzięki temu może on zwrócić dane potrzebne do zapytania o numer SELECT bezpośrednio ze stron poziomu liścia indeksu.

Jednakże: jeśli trzeba wybrać drugą kolumnę, czyli ani w definicji indeksu ani częścią klucza klastrowego, a następnie SQL Server musiałby zrobić tzw zakładek wyszukiwanie do rzeczywistych stron danych.

Więc dla każdego rzędu stwierdzi w indeks nieklastrowany, musiałby przyjąć wartość indeksu grupowanie, wyszukiwanie indeksu klastrowego znaleźć rzeczywiste strony danych na poziomie liścia tego indeksu klastrowego, a następnie wybierz tę kolumnę, którą chcesz.

Wyszukiwanie zakładek doskonale nadaje się do niewielkiej liczby odsłon - są one całkowicie niszczycielskie dla wydajności, jeśli wybierasz tysiące wierszy. W takim przypadku optymalizator zapytań SQL Server poprawnie używa zamiast tego sklasyfikowanego indeksu , ponieważ w indeksie klastrowanym na poziomie liścia ma on od razu dostępne wszystkie wiersze.

więc: jeśli masz indeksu na UserTask_IDEntitat i czasami trzeba drugą kolumnę UserTask_SequenceNumber zbyt - następnie można obejmują że kolumna w tej nieklastrowany indeks Ciebie:

CREATE NONCLUSTERED INDEX IX_UserTask_IDEntitat 
ON dbo.UserTask(UserTask_IDEntitat) 
INCLUDE(UserTask_SequenceNumber) 

z tym, że dodatkowe kolumna jest obecna na poziomie poziomu liścia tylko dla tego niesklasyfikowanego indeksu (nie może być użyta w klauzuli WHERE - nie jest częścią struktury nawigacyjnej indeksu!) - a twoja druga SELECT może ponownie zadowolić się liściem węzły poziomu nieklastrowanego -> nie potrzebne są zadumane wyszukiwania zakładek -> Twój indeks zostanie ponownie użyty.

Krótko mówiąc: chyba że indeks nieklastrowany jest wysoce selektywne (np zwraca 1% swoich wierszy lub mniej), a chyba indeksu nieklastrowany jest obejmujące wskaźnik (indeks, który zawiera wszystko kolumny potrzebne do spełnienia określonego zapytania), a następnie zmiany są dość wysokie, że SQL Server będzie NOT użyć swojego nieklastrowanego indeksu.

Aby uzyskać więcej informacji:

+0

Dzięki za szczegółową odpowiedź i użyteczne linki, czego naprawdę potrzebuję w kwerendach produkcyjnych, nie tylko zwrócę UserTask_SequenceNumber, muszę zwrócić wszystkie kolumny, (Drugie zapytanie to był zły przykład), w tym przypadku nie ma jakakolwiek optymizacja wygody, nie? SqlServer robi najbardziej efektywny sposób jest możliwy. –

+2

@MarcCals: jeśli potrzebujesz ** wszystkich ** kolumn - wtedy większość czasu indeksy tak naprawdę nie pomogą, ponieważ skanowanie w klastrze indeksu jest zwykle bardziej wydajne niż wykonanie tysięcy drogich wyszukiwań zakładek –

Powiązane problemy