Powiedzmy, że mam jeden stolik
CREATE TABLE Ticket (
TicketId int NOT NULL,
InsertDateTime datetime NOT NULL,
SiteId int NOT NULL,
StatusId tinyint NOT NULL,
AssignedId int NULL,
ReportedById int NOT NULL,
CategoryId int NULL
);
W tym przykładzie TicketId
jest klucz podstawowy.
Chcę, aby użytkownicy mogli tworzyć zapytania „częściowo ad-hoc” dla tej tabeli. Mówię częściowo, ponieważ kilka części zapytania zawsze zostanie naprawionych:
- Zapytanie zawsze wykona filtr zakresu na
InsertDateTime
- Zapytanie będzie zawsze
ORDER BY InsertDateTime DESC
- Zapytanie wyświetli wyniki strony
Użytkownik może opcjonalnie filtrować według dowolnej innej kolumny. Mogą filtrować według żadnego, jednego lub wielu. I dla każdej kolumny użytkownik może wybrać z zestawu wartości, które zostaną zastosowane jako rozłączenie. Na przykład:
SELECT
TicketId
FROM (
SELECT
TicketId,
ROW_NUMBER() OVER(ORDER BY InsertDateTime DESC) as RowNum
FROM Ticket
WHERE InsertDateTime >= '2013-01-01' AND InsertDateTime < '2013-02-01'
AND StatusId IN (1,2,3)
AND (CategoryId IN (10,11) OR CategoryId IS NULL)
) _
WHERE RowNum BETWEEN 1 AND 100;
Załóżmy teraz, że tabela ma 100 000 000 wierszy.
Najlepsze, co mogę wymyślić, to indeks obejmujący każdą z „opcjonalnych” kolumn:
CREATE NONCLUSTERED INDEX IX_Ticket_Covering ON Ticket (
InsertDateTime DESC
) INCLUDE (
SiteId, StatusId, AssignedId, ReportedById, CategoryId
);
To daje mi plan zapytań w następujący sposób:
- WYBIERZ
- Filtr
- Top
- Sequence Project (Compute Scalar)
- Człon
- Indeks Szukaj
- Człon
- Sequence Project (Compute Scalar)
- Top
- Filtr
Wygląda całkiem nieźle. Około 80% -90% kosztów pochodzi z operacji indeksowania, która jest idealna.
Czy istnieją lepsze strategie wdrażania tego rodzaju wyszukiwania?
Niekoniecznie chcę odciążyć opcjonalne filtrowanie do klienta, ponieważ w niektórych przypadkach zestaw wyników z części „ustalonej” może wynosić 100s lub 1000s. Klient byłby wówczas także odpowiedzialny za sortowanie i stronicowanie, które może zbyt wiele dla niego działać.
źródło
RowNum BETWEEN 101 AND 200
?Odpowiedzi:
Jeśli to szczególne obciążenie pracą stanowi większość zapytań do tabeli, możesz rozważyć:
Uwagi:
Zalety:
źródło
Użyłem tej techniki w przeszłości. Tabela nie była prawie tak duża, ale kryteria wyszukiwania były bardziej złożone.
To jest krótka wersja.
źródło
Biorąc pod uwagę dwa pierwsze warunki, przyjrzałbym się indeksowi klastrowemu
InsertDateTime
.źródło
dlaczego nie rozważasz partycjonowania? Jest dostępny w wersji SQL 2008 w górę, ale wymaga edycji Enterprise (lub Edycji programisty).
Zasadniczo podzieliłeś tabelę na wiele partycji i zdefiniowałeś kryteria podziału (funkcji), czy byłbyś zakresem dat?
https://www.simple-talk.com/sql/database-administration/gail-shaws-sql-server-howlers/
źródło
Jeśli klienci filtrują w prawie taki sam sposób w kółko, możesz utworzyć indeks dla tych zapytań.
Np. Klient filtruje na SiteId i StatusId, możesz utworzyć dodatkowy indeks:
W ten sposób większość „bardziej powszechnych” zapytań może działać szybko.
źródło