Скажімо, у мене єдина таблиця
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
);
У цьому прикладі TicketId
є Первинний ключ.
Я хочу, щоб користувачі могли створити "частково спеціальні" запити проти цієї таблиці. Я частково кажу, тому що кілька частин запиту завжди буде виправлено:
- Запит завжди виконуватиме фільтр діапазону на
InsertDateTime
- Запит буде завжди
ORDER BY InsertDateTime DESC
- Запит відображатиме результати на сторінці
Користувач може додатково фільтрувати будь-який з інших стовпців. Вони можуть фільтрувати на жодному, одному або багатьох. І для кожного стовпця користувач може вибрати з набору значень, які застосовуватимуться як диз'юнкція. Наприклад:
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;
Тепер припустимо, що таблиця має 100 000 000 рядків.
Найкраще, що я можу придумати, - це індекс покриття, який включає кожен із "необов'язкових" стовпців:
CREATE NONCLUSTERED INDEX IX_Ticket_Covering ON Ticket (
InsertDateTime DESC
) INCLUDE (
SiteId, StatusId, AssignedId, ReportedById, CategoryId
);
Це дає мені план запитів наступним чином:
- ВИБІРИ
- Фільтр
- Зверху
- Послідовність проекту (Обчислити скаляр)
- Сегмент
- Шукати покажчик
- Сегмент
- Послідовність проекту (Обчислити скаляр)
- Зверху
- Фільтр
Це здається досить непоганим. Близько 80% -90% витрат припадає на операцію Index Seek, що є ідеальним.
Чи є кращі стратегії здійснення такого типу пошуку?
Я не обов'язково хочу завантажувати додаткову фільтрацію для клієнта, оскільки в деяких випадках набір результатів із "фіксованої" частини може становити 100s або 1000s. Тоді клієнт також несе відповідальність за сортування та пейджинги, які можуть занадто багато працювати для клієнта.
RowNum BETWEEN 101 AND 200
?