SQL Server에서 ROW_NUMBER와 페이징은 어떻게 작동합니까?


13

Employee백만 개의 레코드 가있는 테이블이 있습니다. 웹 응용 프로그램에서 데이터를 페이징하기 위해 다음 SQL이 있습니다. 잘 작동합니다. 그러나 내가 문제로 보는 것은 파생 테이블 이 값 을 만들기 위해 테이블의 tblEmployee모든 레코드를 선택 Employee한다는 것 MyRowNumber입니다.

이로 인해 Employee테이블 의 모든 레코드가 선택 됩니다.

정말 효과가 있습니까? 아니면 SQL Server가 원본 Employee테이블 에서 5 개의 레코드 만 선택하도록 최적화 되었습니까?

DECLARE @Index INT;
DECLARE @PageSize INT;

SET @Index = 3;
SET @PageSize = 5;

SELECT *  FROM
  (SELECT  ROW_NUMBER() OVER (ORDER BY EmpID asc) as MyRowNumber,*
  FROM Employee) tblEmployee
WHERE MyRowNumber BETWEEN ( ((@Index - 1) * @PageSize )+ 1) AND @Index*@PageSize 

3
sqlservercentral.com/articles/T-SQL/66030 및보다 중요한 다음 논의를 참조하십시오 .
Aaron Bertrand

답변:


17

테스트의 대안은 다음과 같습니다.

;WITH x AS (SELECT EmpID, k = ROW_NUMBER() OVER (ORDER BY EmpID) FROM dbo.Emp)
SELECT e.columns
FROM x INNER JOIN dbo.Emp AS e
ON x.EmpID = e.EmpID
WHERE x.k BETWEEN (((@Index - 1) * @PageSize) + 1) AND @Index * @PageSize
ORDER BY ...;

예, 테이블을 두 번 누르십시오. 그러나 전체 테이블을 스캔하는 CTE에서는 모든 데이터가 아니라 키만 잡습니다. 그러나이 기사를 실제로 봐야합니다.

http://www.sqlservercentral.com/articles/T-SQL/66030/

그리고 후속 토론 :

http://www.sqlservercentral.com/Forums/Topic672980-329-1.aspx

물론 SQL Server 2012에서는 새로운 OFFSET/ FETCH NEXT구문을 사용할 수 있습니다 .

;WITH x AS 
(
  SELECT EmpID FROM dbo.Emp
    ORDER BY EmpID
    OFFSET  @PageSize * (@Index - 1) ROWS
    FETCH NEXT @PageSize ROWS ONLY
)
SELECT e.columns
FROM x INNER JOIN dbo.Emp AS e
ON x.EmpID = e.EmpID
ORDER BY ...; 

OFFSET / FETCH NEXT는 CTE 방법에 비해 성능상의 이점을 제공하지 않습니다.
Akash

2
@Akash 당신은 이것을 철저히 테스트 했습니까? 몇 가지 계획 차이를 관찰했지만 광범위한 테스트를 수행하지 않았으므로 성능에 대해 특별히 언급하지 않았습니다. 성능이 동일하더라도 구문이 약간 성가시다. 난 여기에 대한 블로그 않았다 sqlblog.com/blogs/aaron_bertrand/archive/2010/11/10/...
아론 버트 랜드

1
아, 맞습니다. 성능 차이가 있습니다. :이 읽은 blogs.technet.com/b/dataplatforminsider/archive/2011/11/01/... 그 차이를 언급,하지만 단지 톱 channel9.msdn.com/posts/SQL11UPD03-REC-02을 그가 프로그래머를 도시 많은 차이 .. (오디오에서 성능 차이를 강조하지만)
Akash

2

배후의 메커니즘을 모르더라도 쿼리 성능을 다음과 비교하여 직접 테스트 할 수 있습니다. select * from Employee.

최신 버전의 SQL Server는 최적화 작업을 잘 수행하지만 몇 가지 요소에 따라 달라질 수 있습니다.

ROW_NUMBER 함수의 수행 방식은 Order By 절에 의해 결정됩니다. 귀하의 예에서 대부분 EmpID가 기본 키라고 생각합니다.

몇 가지가 있습니다 너무 복잡 및 / 또는 잘못 코딩 또는 색인 조항은, 당신은 단지 전체 데이터 집합을 (이 드문 고정 할 수 있습니다) 반환 더 나을 수 있습니다. BETWEEN 사용에 문제가 있습니다.

모든 행을 응용 프로그램에 반환하고 알아내는 것이 더 좋다고 가정하기 전에 쿼리 최적화 작업을 수행해야합니다. 추정치를 확인하십시오. 쿼리 분석기에 문의하십시오. 몇 가지 대안을 테스트하십시오.


2

질문은 row_number ()에 관한 것이지만 SQL Server 2012의 새로운 기능 하나를 추가하고 싶습니다. SQL Server 2012의 새로운 기능 OFFSET Fetch는 다음에 도입되었으며 row_number ()보다 매우 빠릅니다. 나는 그것을 사용했으며 좋은 결과를 얻었습니다.

http://blogfornet.com/2013/06/sql-server-2012-offset-use/에서 예제를 찾았습니다.

유용합니다. 새로운 기능을 구현하는 데 도움이되기를 바랍니다 ....


-2

원래 테이블의 모든 행을 반환한다고 평가하지는 않습니다. SQL 서버가 최적화됩니다. 그렇지 않으면 백만 항목을 선택하는 데 많은 시간이 걸립니다. 나는 현재 이것을 사용하고 있으며 모든 행을 선택하는 것보다 훨씬 빠릅니다. 따라서 모든 행을 얻지는 못합니다. 그러나 처음 다섯 행을 가져 오는 것보다 느립니다. 아마 순서대로 걸리는 시간 때문입니다.


-2
DECLARE @PageIndex int;
DECLARE @PageSize int;
SET @PageIndex = 4;
SET @PageSize = 5;
;With ranked AS   --- Or you can make it a view
(
   SELECT ROW_NUMBER() OVER(ORDER BY IdentityId) AS RowNum,  *
   FROM logeventnew
)
SELECT *   --Your fields here
FROM Ranked
WHERE RowNum BETWEEN ((@PageIndex - 1) * @PageSize + 1)
    AND (@PageIndex * @PageSize)
ORDER BY IdentityId

4
답을 넓힐 수 있습니까? 문제는 페이징이 SQL Server 내부에서 작동 하는 방식 , 즉 데이터베이스 엔진이 요청을 수행하기 위해 수행하는 방식에 관한 것입니다. 불행히도 현재로서는 귀하의 답변이 실제 문제를 해결하지 못합니다.
Mr.Brownstone
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.