Disons que j'ai une seule table
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
);
Dans cet exemple, TicketId
la clé primaire.
Je souhaite que les utilisateurs puissent créer des requêtes "partiellement ad hoc" sur cette table. Je dis en partie parce que certaines parties de la requête seront toujours corrigées:
- La requête effectuera toujours un filtre de plage sur un
InsertDateTime
- La requête sera toujours
ORDER BY InsertDateTime DESC
- La requête affichera les résultats
L'utilisateur peut éventuellement filtrer sur n'importe quelle autre colonne. Ils peuvent filtrer sur aucun, un ou plusieurs. Et pour chaque colonne, l'utilisateur peut choisir parmi un ensemble de valeurs qui seront appliquées comme une disjonction. Par exemple:
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;
Supposons maintenant que la table comporte 100 000 000 lignes.
Le mieux que je puisse trouver est un index de couverture qui inclut chacune des colonnes "facultatives":
CREATE NONCLUSTERED INDEX IX_Ticket_Covering ON Ticket (
InsertDateTime DESC
) INCLUDE (
SiteId, StatusId, AssignedId, ReportedById, CategoryId
);
Cela me donne un plan de requête comme suit:
- SÉLECTIONNER
- Filtre
- Haut
- Projet de séquence (calcul scalaire)
- Segment
- Recherche d'index
- Segment
- Projet de séquence (calcul scalaire)
- Haut
- Filtre
Cela semble plutôt bien. Environ 80% à 90% du coût provient de l'opération Index Seek, ce qui est idéal.
Existe-t-il de meilleures stratégies pour mettre en œuvre ce type de recherche?
Je ne veux pas nécessairement décharger le filtrage optionnel sur le client car dans certains cas, le jeu de résultats de la partie "fixe" peut être de 100 ou de 1000. Le client serait alors également responsable du tri et de la pagination, ce qui pourrait trop fonctionner pour le client.
la source
RowNum BETWEEN 101 AND 200
?Réponses:
Si cette charge de travail particulière représente la majorité des requêtes sur la table, vous pouvez envisager:
Considérations:
Avantages:
la source
J'ai utilisé cette technique dans le passé. Le tableau n'était pas aussi grand mais les critères de recherche étaient plus complexes.
C'est la version courte.
la source
Compte tenu de vos deux premières conditions préalables, j'examinerais un index clusterisé
InsertDateTime
.la source
pourquoi ne considérez-vous pas le partitionnement? Il est disponible dans SQL 2008 et nécessite une édition Enterprise (ou une édition Developer).
Fondamentalement, vous divisez votre table sur plusieurs partitions et vous définissez vos critères de partition (fonction), serait-ce votre plage de dates?
https://www.simple-talk.com/sql/database-administration/gail-shaws-sql-server-howlers/
la source
Si les clients filtrent presque toujours de la même manière, vous pouvez créer un index pour ces requêtes.
Par exemple, le client filtre sur SiteId et StatusId, vous pouvez créer un index supplémentaire:
De cette façon, la plupart des requêtes «les plus courantes» pourraient s'exécuter rapidement.
la source