Au fil des ans, un tas de sueur de développeur a été consacré à la pagination efficace des ensembles de résultats. Pourtant, il n'y a pas de réponse unique - cela dépend de votre cas d'utilisation. Une partie du cas d'utilisation consiste à obtenir votre page efficacement, une partie consiste à déterminer le nombre de lignes dans un ensemble de résultats complet. Désolé si je m'égare un peu dans la pagination, mais les deux sont assez étroitement liés dans mon esprit.
Il existe de nombreuses stratégies, dont la plupart sont mauvaises si vous avez un volume de données quelconque et ne correspondent pas au cas d'utilisation. Bien que cette liste ne soit pas complète, voici quelques-unes des options .....
Exécuter un Count(*)
séparé
- exécuter une requête distincte qui fait un simple "select count(*) from MyTable"
- simple et facile pour une petite table
- bon sur une grande table non filtrée qui est étroite ou qui a un index compact non clusterisé que vous pouvez utiliser
- tombe en panne lorsque vous avez un
WHERE/JOIN
compliqué car l'exécution deWHERE/JOIN
le double coûte cher. - tombe en panne sur un index large car le nombre de lectures augmente.
Combiner ROW_Number() OVER()
et COUNT(1) OVER(PARTITION By 1)
- Ceci a été suggéré par @RBarryYoung. Il a l'avantage d'être simple à mettre en œuvre et très flexible.
- L'inconvénient est qu'il existe de nombreuses raisons pour lesquelles cela peut rapidement devenir extrêmement coûteux.
- Par exemple, dans une base de données sur laquelle je travaille actuellement, il y a une table Media avec environ 6000 lignes. Il n'est pas particulièrement large, a un PK entier en cluster et, ainsi qu'un index unique compact. Pourtant, un simple
COUNT(*) OVER(PARTITION BY 1) as TotalRows
donne environ 12 000 lectures. Comparez cela à un simpleSELECT COUNT(*) FROM Media
-- 12 lectures. Wowzers.
Tables temporaires / Variables de table
- Il existe de nombreuses stratégies qui prennent un ensemble de résultats et insèrent des clés ou des segments de résultats pertinents dans des tables temporaires/variables de table.
- Pour les ensembles de résultats de petite/moyenne taille, cela peut donner d'excellents résultats.
- Ce type de stratégie fonctionne sur presque toutes les plates-formes/versions de SQL.
- Il est également facile d'opérer plusieurs fois sur un ensemble de résultats (souvent une exigence).
- L'inconvénient est que lorsque vous travaillez avec de grands ensembles de résultats... l'insertion de quelques millions de lignes dans une table temporaire a un coût.
- Pour aggraver le problème, dans un système à volume élevé, la pression sur TempDB peut être un facteur important, et les tables temporaires fonctionnent efficacement dans TempDB.
Somme gaussienne / Nombre de lignes doubles
- Cette idée repose sur sous-ensemble de quelque chose que le mathématicien Gauss a compris (comment additionner une série de nombres). Le sous-ensemble est de savoir comment obtenir le nombre de lignes à partir de n'importe quel point du tableau.
- À partir d'une série de nombres (
Row_Number()
) le nombre de lignes pour 1 à N est(N + 1) - 1
. Plus d'explications dans les liens. - La formule semble se résumer à N, mais si vous vous en tenez à la formule, des choses intéressantes se produisent, vous pouvez déterminer le nombre de lignes à partir d'une page au milieu du tableau.
- Le résultat net est que vous faites
ROW_Number() OVER(Order by ID)
etROW_Number() OVER(Order by ID DESC)
puis additionnez les deux nombres et soustrayez 1. - En prenant mon tableau Media comme exemple, mes lectures sont passées de 12 000 à environ 75.
- Dans une page plus grande, vous avez fini par répéter des données plusieurs fois, mais le décalage des lectures peut en valoir la peine.
- Je n'ai pas testé cela sur trop de scénarios, il peut donc s'effondrer dans d'autres scénarios.
Haut (@n) / DÉFINIR ROWCOUNT
- Il ne s'agit pas de stratégies spécifiques en soi, mais d'optimisations basées sur ce que nous savons de l'optimiseur de requêtes.
- L'utilisation créative de Top(@n) [top peut être une variable dans SQL 2008] ou SET ROWCOUNT peut réduire votre ensemble de travail... même si vous tirez une page du milieu d'un ensemble de résultats, vous pouvez toujours affiner le résultat
- Ces idées fonctionnent en raison du comportement de l'optimiseur de requête... un service pack/correctif peut modifier le comportement (mais probablement pas).
- Dans certains cas, SET ROWCOUNT peut être un peu inexact
- Cette stratégie ne tient pas compte de l'obtention du nombre total de lignes, mais rend simplement la pagination plus efficace
Qu'est-ce qu'un développeur doit faire ?
Lisez mon bonhomme, lisez. Voici quelques articles sur lesquels je me suis appuyé...
- Une méthode plus efficace pour parcourir de grands ensembles de résultats
- Optimisation de la pagination côté serveur – Partie I
- Optimisation de la pagination côté serveur – Partie 2
- Explication de la somme gaussienne
- Renvoyer des résultats classés avec Microsoft SQL Server 2005
- ROW_NUMBER() OVER Pas assez rapide avec un grand ensemble de résultats
- Récupération des N premiers enregistrements d'une requête SQL
- Paging côté serveur avec SQL Server 2005
- Pourquoi sont les lectures logiques pour les fonctions d'agrégation fenêtrées sont-elles si élevées ?
J'espère que ça aide.