Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

579
Vistas
¿Hay alguna opción mejor para aplicar la paginación sin aplicar OFFSET en SQL Server?

Quiero aplicar la paginación en una tabla con una gran cantidad de datos. Todo lo que quiero saber es una mejor opción que usar OFFSET en SQL Server.

Aquí está mi consulta simple:

 SELECT * FROM TableName ORDER BY Id DESC OFFSET 30000000 ROWS FETCH NEXT 20 ROWS ONLY
over 4 years ago · Santiago Trujillo
3 Respuestas
Responde la pregunta

0

Puede usar Paginación de conjunto de claves para esto. Es mucho más eficiente que usar la paginación de conjuntos de filas (paginación por número de fila).

En la paginación de conjuntos de filas, se deben leer todas las filas anteriores antes de poder leer la página siguiente. Mientras que en Keyset Pagination, el servidor puede saltar inmediatamente al lugar correcto en el índice, por lo que no se leen filas adicionales que no es necesario.

En este tipo de paginación, no puede saltar a un número de página específico. Salta a una clave específica y lee desde allí. Para que esto funcione bien, debe tener un índice único en esa clave, que incluye cualquier otra columna que necesite consultar.

Un gran beneficio , además de la ganancia de eficiencia obvia, es evitar el problema de "fila faltante" al paginar, causado por la eliminación de filas de páginas leídas anteriormente. Esto no sucede al paginar por clave, porque la clave no cambia.


Aquí hay un ejemplo:

Supongamos que tiene una tabla llamada TableName con un índice en Id y desea comenzar con el último valor de Id y trabajar hacia atrás.

Empiezas con:

 SELECT TOP (@numRows) * FROM TableName ORDER BY Id DESC;

Tenga en cuenta el uso de ORDER BY para garantizar que el pedido sea correcto

El cliente conservará el último valor de Id recibido (el más bajo en este caso). En la siguiente solicitud, salta a esa tecla y continúa:

 SELECT TOP (@numRows) * FROM TableName WHERE Id < @lastId ORDER BY Id DESC;

Tenga en cuenta el uso de < no <=

En caso de que se lo pregunte, en un índice típico de B-Tree+, la fila con el ID indicado no se lee, es la fila posterior la que se lee.


La clave elegida debe ser única , por lo que si está paginando por una columna no única, debe agregar una segunda columna tanto a ORDER BY como a WHERE . Necesitaría un índice en OtherColumn, Id por ejemplo, para admitir este tipo de consulta. No olvides INCLUDE columnas en el índice.

SQL Server no admite comparadores de fila/tupla , por lo que no puede hacer (OtherColumn, Id) < (@lastOther, @lastId) (sin embargo, esto es compatible con PostgreSQL, MySQL, MariaDB y SQLite).

En su lugar, necesita lo siguiente:

 SELECT TOP (@numRows) * FROM TableName WHERE ( OtherColumn = @lastOther AND Id < @lastId) OR OtherColumn < @lastOther ) ORDER BY OtherColumn DESC, Id DESC;

Esto es más eficiente de lo que parece, ya que SQL Server puede convertirlo en un < adecuado para ambos valores.

La presencia de NULL s complica aún más las cosas. Es posible que desee consultar esas filas por separado.

over 4 years ago · Santiago Trujillo Denunciar

0

En un sitio web comercial muy grande, usamos un compuesto técnico de identificadores almacenados en una tabla pseudo temporal y los unimos con esta tabla a las filas de la tabla de productos.

Permítanme hablar con un ejemplo claro.

Tenemos un diseño de mesa de esta manera:

 CREATE TABLE S_TEMP.T_PAGINATION_PGN (PGN_ID BIGINT IDENTITY(-9 223 372 036 854 775 808, 1) PRIMARY KEY, PGN_SESSION_GUID UNIQUEIDENTIFIER NOT NULL, PGN_SESSION_DATE DATETIME2(0) NOT NULL, PGN_PRODUCT_ID INT NOT NULL, PGN_SESSION_ORDER INT NOT NULL); CREATE INDEX X_PGN_SESSION_GUID_ORDER ON S_TEMP.T_PAGINATION_PGN (PGN_SESSION_GUID, PGN_SESSION_ORDER) INCLUDE (PGN_SESSION_ORDER); CREATE INDEX X_PGN_SESSION_DATE ON S_TEMP.T_PAGINATION_PGN (PGN_SESSION_DATE);

Tenemos una tabla de productos muy grande llamada T_PRODUIT_PRD y un cliente la filtró con muchos predicados. INSERTAMOS filas del SELECT filtrado en esta tabla de esta manera:

 DECLARE @SESSION_ID UNIQUEIDENTIFIER = NEWID(); INSERT INTO S_TEMP.T_PAGINATION_PGN SELECT @SESSION_ID , SYSUTCDATETIME(), PRD_ID, ROW_NUMBER() OVER(ORDER BY --> custom order by FROM dbo.T_PRODUIT_PRD WHERE ... --> custom filter

Luego, cada vez que necesitamos una página deseada, compuesta de productos @N, agregamos una unión a esta tabla como:

 ... JOIN S_TEMP.T_PAGINATION_PGN ON PGN_SESSION_GUID = @SESSION_ID AND 1 + (PGN_SESSION_ORDER / @N) = @DESIRED_PAGE_NUMBER AND PGN_PRODUCT_ID = dbo.T_PRODUIT_PRD.PRD_ID

¡Todos los índices harán el trabajo!

Por supuesto, regularmente tenemos que purgar esta tabla y es por eso que tenemos un trabajo programado que elimina las filas cuyas sesiones se generaron hace más de 4 horas:

 DELETE FROM S_TEMP.T_PAGINATION_PGN WHERE PGN_SESSION_DATE < DATEADD(hour, -4, SYSUTCDATETIME());
over 4 years ago · Santiago Trujillo Denunciar

0

En el mismo espíritu que la solución SQLPro, propongo:

 WITH CTE AS (SELECT 30000000 AS N UNION ALL SELECT N-1 FROM CTE WHERE N > 30000000 +1 - 20) SELECT T.* FROM CTE JOIN TableName T ON CTE.N=T.ID ORDER BY CTE.N DESC

¡Probé con 2 mil millones de líneas y es instantáneo! Es fácil convertirlo en un procedimiento almacenado... Por supuesto, válido si los identificadores se suceden.

over 4 years ago · Santiago Trujillo Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda