web-dev-qa-db-fra.com

Obtenir le nombre total de lignes à partir de OFFSET / FETCH NEXT

J'ai donc une fonction qui renvoie un certain nombre d'enregistrements pour lesquels je souhaite implémenter la pagination sur mon site Web. Il m'a été suggéré d'utiliser le décalage/extraction suivant dans SQL Server 2012 pour accomplir cela. Sur notre site Web, nous avons une zone qui répertorie le nombre total d'enregistrements et la page sur laquelle vous vous trouvez à ce moment-là.

Auparavant, je disposais de tout le jeu d'enregistrements et j'étais capable de construire la pagination sur ce programme. Mais en utilisant la méthode SQL avec FETCH NEXT X ROWS UNIQUEMENT, on ne me restitue que X rangées. Je ne sais donc pas quel est mon jeu d’enregistrements total ni comment calculer mes pages min et max. La seule façon pour moi de faire cela consiste à appeler la fonction deux fois et à compter les lignes sur la première, puis à exécuter la seconde avec FETCH NEXT. Existe-t-il un meilleur moyen de ne pas exécuter la requête deux fois? J'essaie d'accélérer les performances, pas de les ralentir.

77
CrystalBlue

Vous pouvez utiliser COUNT(*) OVER() ... voici un exemple rapide utilisant sys.all_objects:

DECLARE 
  @PageSize INT = 10, 
  @PageNum  INT = 1;

SELECT 
  name, object_id, 
  overall_count = COUNT(*) OVER()
FROM sys.all_objects
ORDER BY name
  OFFSET (@PageNum-1)*@PageSize ROWS
  FETCH NEXT @PageSize ROWS ONLY;

Cependant, cela devrait être réservé aux petits ensembles de données; sur de plus grands ensembles, la performance peut être catastrophique. Voir cet article de Paul White pour de meilleures alternatives , y compris la gestion des vues indexées (qui ne fonctionne que si le résultat n'est pas filtré ou si vous connaissez les clauses WHERE à l'avance) et l'utilisation de ROW_NUMBER() des trucs.

99
Aaron Bertrand

J'ai rencontré des problèmes de performances lors de l'utilisation de la méthode COUNT () OVER (). Je ne sais pas s'il s'agissait du serveur, car il a fallu 40 secondes pour renvoyer 10 enregistrements, puis aucun problème ne s'est produit ultérieurement.) Cette technique a fonctionné dans toutes les conditions sans avoir à utiliser COUNT () OVER () et accomplit la même chose:

DECLARE 
    @PageSize INT = 10, 
    @PageNum  INT = 1;

WITH TempResult AS(
    SELECT ID, Name
    FROM Table
), TempCount AS (
    SELECT COUNT(*) AS MaxRows FROM TempResult
)
SELECT *
FROM TempResult, TempCount
ORDER BY TempResult.Name
    OFFSET (@PageNum-1)*@PageSize ROWS
    FETCH NEXT @PageSize ROWS ONLY
127
James Moberg

Basé sur réponse de James Moberg :

C'est une alternative en utilisant Row_Number(), si vous n'avez pas SQL Server 2012 et que vous ne pouvez pas utiliser OFFSET.

DECLARE 
    @PageNumEnd INT = 10, 
    @PageNum  INT = 1;

WITH TempResult AS(
    SELECT ID, NAME
    FROM Tabla
), TempCount AS (
    SELECT COUNT(*) AS MaxRows FROM TempResult
)

select * 
from
(
    SELECT
     ROW_NUMBER() OVER ( ORDER BY PolizaId DESC) AS 'NumeroRenglon', 
     MaxRows, 
     ID,
     Name
    FROM TempResult, TempCount

)resultados
WHERE   NumeroRenglon >= @PageNum
    AND NumeroRenglon <= @PageNumEnd
ORDER BY NumeroRenglon
1
elblogdelbeto