[sql] SQL Server에서 결과 페이지를 매기는 가장 좋은 방법은 무엇입니까

총 페이지 수 (페이지 매기기 전)를 얻으려면 SQL Server 2000, 2005, 2008, 2012에서 결과 페이지를 매기는 가장 좋은 방법 (성능 현명한 방법)은 무엇입니까?



답변

총 결과 수와 페이지 매김을 얻는 것은 두 가지 다른 작업입니다. 이 예제를 위해 다루고있는 쿼리가 다음과 같다고 가정 해 봅시다.

SELECT * FROM Orders WHERE OrderDate >= '1980-01-01' ORDER BY OrderDate

이 경우 다음을 사용하여 총 결과 수를 결정합니다.

SELECT COUNT(*) FROM Orders WHERE OrderDate >= '1980-01-01'

… 비효율적 인 것처럼 보일 수 있지만 모든 색인 등이 올바르게 설정되었다고 가정하면 실제로 성능이 뛰어납니다.

다음으로 실제 결과를 페이지 방식으로 되돌리려면 다음 쿼리가 가장 효율적입니다.

SELECT  *
FROM    ( SELECT    ROW_NUMBER() OVER ( ORDER BY OrderDate ) AS RowNum, *
          FROM      Orders
          WHERE     OrderDate >= '1980-01-01'
        ) AS RowConstrainedResult
WHERE   RowNum >= 1
    AND RowNum < 20
ORDER BY RowNum

원래 쿼리의 1-19 행을 반환합니다. 여기에서 특히 웹 앱의 경우 멋진 점은 반환 할 행 번호를 제외하고는 상태를 유지할 필요가 없다는 것입니다.


답변

드디어, Microsoft SQL Server 2012 가 출시되었습니다. 페이지 매김의 단순함이 정말 마음에 듭니다. 여기서 답변 한 것과 같은 복잡한 쿼리를 사용할 필요가 없습니다.

다음 10 개 행을 얻으려면 다음 쿼리를 실행하십시오.

SELECT * FROM TableName ORDER BY id OFFSET 10 ROWS FETCH NEXT 10 ROWS ONLY;

https://docs.microsoft.com/en-us/sql/t-sql/queries/select-order-by-clause-transact-sql#using-offset-and-fetch-to-limit-the-rows- 반환

그것을 사용할 때 고려해야 할 요점 :

  • ORDER BY 사용이 필수적이다 OFFSET ... FETCH조항 합니다.
  • OFFSET 이 조항은 필수입니다 FETCH . 사용할 수 없습니다 ORDER BY ...
    FETCH
    .
  • TOP동일한 쿼리 표현식 OFFSET과 결합하여 사용할 수 없습니다 FETCH.

답변

놀랍게도, 모든 SQL Server 버전에서 페이지 매김을 수행 하는 가장 빠른 방법을 언급 한 다른 답변은 없습니다 . 여기에서 벤치마킹 된 것처럼 큰 페이지 번호의 경우 오프셋이 매우 느려질 수 있습니다 . SQL에서 페이지 매김을 수행하는 완전히 다른 방법이 있습니다. 이 블로그 게시물 here에 설명 된대로이를 “검색 방법”또는 “키셋 페이지 매김”이라고 합니다 .

SELECT TOP 10 first_name, last_name, score, COUNT(*) OVER()
FROM players
WHERE (score < @previousScore)
   OR (score = @previousScore AND player_id < @previousPlayerId)
ORDER BY score DESC, player_id DESC

“검색어 술어”

@previousScore@previousPlayerId값은 이전 페이지에서 마지막 레코드의 각각의 값입니다. “다음”페이지를 가져올 수 있습니다. 경우 ORDER BY방향은 ASC단순히 사용> 대신.

위의 방법을 사용하면 이전 40 개의 레코드를 먼저 가져 오지 않고 4 페이지로 바로 이동할 수 없습니다. 그러나 종종, 당신은 어쨌든 그렇게 멀리 뛰어 가고 싶지 않습니다. 대신 인덱싱에 따라 일정한 시간에 데이터를 가져올 수있는 훨씬 빠른 쿼리를 얻습니다. 또한 기본 데이터가 변경 되더라도 (예 : 4 페이지, 1 페이지) 페이지가 “안정적”으로 유지됩니다.

예를 들어 웹 응용 프로그램에서 더 많은 데이터를 지연로드 할 때 페이지 매김을 구현하는 가장 좋은 방법입니다.

“검색 방법”은 키 세트 페이지 매김 이라고도합니다. 합니다.

페이지 매김 전의 총 레코드

COUNT(*) OVER()윈도우 함수는 “매김하기 전에”총 레코드 수를 계산하는 데 도움이됩니다. SQL Server 2000을 사용하는 경우에 대한 두 개의 쿼리를 사용해야합니다 COUNT(*).


답변

SQL Server 2012에서 OFFSETFETCH NEXT절을 사용 하여 페이지 매김을 달성 할 수 있습니다 .

SQL Server의 경우 다음을 시도하십시오.

SQL Server 2012에서는 ORDER BY 절에 새로운 기능이 추가되어 집합 데이터의 최적화를 쿼리하여 SQL Server의 전체 실행 계획뿐만 아니라 T-SQL로 작성하는 모든 사람의 데이터 페이징 작업이 쉬워졌습니다.

이전 예에서 사용한 것과 동일한 논리를 사용하는 T-SQL 스크립트 아래

--CREATING A PAGING WITH OFFSET and FETCH clauses IN "SQL SERVER 2012"
DECLARE @PageNumber AS INT, @RowspPage AS INT
SET @PageNumber = 2
SET @RowspPage = 10
SELECT ID_EXAMPLE, NM_EXAMPLE, DT_CREATE
FROM TB_EXAMPLE
ORDER BY ID_EXAMPLE
OFFSET ((@PageNumber - 1) * @RowspPage) ROWS
FETCH NEXT @RowspPage ROWS ONLY;

TechNet : SQL Server를 사용하여 쿼리 페이징


답변

MSDN : ROW_NUMBER (Transact-SQL)

각 파티션의 첫 번째 행에 대해 1부터 시작하여 결과 세트의 파티션 내에서 행의 순차 번호를 리턴합니다.

다음 예제는 OrderDate 순서로 숫자가 50-60 인 행을 리턴합니다.

WITH OrderedOrders AS
(
    SELECT
        ROW_NUMBER() OVER(ORDER BY FirstName DESC) AS RowNumber,
        FirstName, LastName, ROUND(SalesYTD,2,1) AS "Sales YTD"
    FROM [dbo].[vSalesPerson]
)
SELECT RowNumber,
    FirstName, LastName, Sales YTD
FROM OrderedOrders
WHERE RowNumber > 50 AND RowNumber < 60;
  RowNumber FirstName    LastName               SalesYTD
  --- -----------  ---------------------- -----------------
  1   Linda        Mitchell               4251368.54
  2   Jae          Pak                    4116871.22
  3   Michael      Blythe                 3763178.17
  4   Jillian      Carson                 3189418.36
  5   Ranjit       Varkey Chudukatil      3121616.32
  6   José         Saraiva                2604540.71
  7   Shu          Ito                    2458535.61
  8   Tsvi         Reiter                 2315185.61
  9   Rachel       Valdez                 1827066.71
  10  Tete         Mensa-Annan            1576562.19
  11  David        Campbell               1573012.93
  12  Garrett      Vargas                 1453719.46
  13  Lynn         Tsoflias               1421810.92
  14  Pamela       Ansman-Wolfe           1352577.13


답변

http://www.codeproject.com/KB/aspnet/PagingLarge.aspx 에는 다양한 페이징 기술에 대한 개요가 있습니다 .

ROWCOUNT 방법을 주로 SQL Server 2000에서 자주 사용했습니다 (2005 및 2008에서도 작동하고 ROW_NUMBER와 비교하여 성능 만 측정). 번개는 빠르지 만 정렬 된 열이 (주로 ) 고유 한 값.


답변

SQL Server 2000의 경우 IDENTITY 열이있는 테이블 변수를 사용하여 ROW_NUMBER ()를 시뮬레이션 할 수 있습니다.

DECLARE @pageNo int -- 1 based
DECLARE @pageSize int
SET @pageNo = 51
SET @pageSize = 20

DECLARE @firstRecord int
DECLARE @lastRecord int
SET @firstRecord = (@pageNo - 1) * @pageSize + 1 -- 1001
SET @lastRecord = @firstRecord + @pageSize - 1   -- 1020

DECLARE @orderedKeys TABLE (
  rownum int IDENTITY NOT NULL PRIMARY KEY CLUSTERED,
  TableKey int NOT NULL
)

SET ROWCOUNT @lastRecord
INSERT INTO @orderedKeys (TableKey) SELECT ID FROM Orders WHERE OrderDate >= '1980-01-01' ORDER BY OrderDate

SET ROWCOUNT 0

SELECT t.*
FROM Orders t
  INNER JOIN @orderedKeys o ON o.TableKey = t.ID
WHERE o.rownum >= @firstRecord
ORDER BY o.rownum

이 방법은 다중 열 키가있는 테이블로 확장 될 수 있으며 OR (인덱스 사용을 건너 뛰는)을 사용하는 경우 성능 오버 헤드가 발생하지 않습니다. 단점은 데이터 세트가 매우 크고 마지막 페이지에 가까운 경우 사용 된 임시 공간의 양입니다. 이 경우 커서 성능을 테스트하지는 않았지만 더 좋을 수 있습니다.

이 방법은 데이터의 첫 페이지에 최적화 될 수 있습니다. 또한 TOP은 SQL Server 2000에서 변수를 허용하지 않으므로 ROWCOUNT가 사용되었습니다.