[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;
그것을 사용할 때 고려해야 할 요점 :
ORDER BY
사용이 필수적이다OFFSET ... FETCH
조항 합니다.OFFSET
이 조항은 필수입니다FETCH
. 사용할 수 없습니다ORDER BY ...
.
FETCHTOP
동일한 쿼리 표현식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에서 OFFSET
및 FETCH 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;
답변
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가 사용되었습니다.