SQL Server의 페이지 매김


17

약 100GB의 매우 큰 데이터베이스가 있습니다. 쿼리를 실행 중입니다.

select * from <table_name>;

100 ~ 200 번째 행만 표시하고 싶습니다.

내부적으로 어떻게되는지 이해하고 싶습니다. 데이터베이스가 디스크의 모든 레코드를 메모리로 가져 와서 100 ~ 400 번째 행을 쿼리 클라이언트로 다시 전송합니까? 또는 B- 트리 등과 같은 인덱싱 메커니즘을 사용하여 데이터베이스에서 해당 레코드 (100 ~ 200 번째) 만 가져 오도록하는 메커니즘이 있습니까?

이것이 페이지 매김 개념과 관련이 있다는 것을 알았지 만 데이터베이스 수준에서 내부적으로 어떻게 발생하는지 정확하게 알 수 없었습니다.

답변:


37

당신이 게시 한 쿼리에서 :

select * from <table_name>;

ORDER BY를 지정하지 않았으므로 100 ~ 200 번째 행은 없습니다. 많은 흥미로운 이유로 ORDER BY를 포함시키지 않으면 주문이 보장되지 않지만 실제로는 그렇지 않습니다.

요점을 설명하기 위해 테이블을 사용하겠습니다. Stack Overflow 데이터 덤프 에서 Users 테이블을 사용 하고이 쿼리를 실행하겠습니다.

SELECT * FROM dbo.Users ORDER BY DisplayName;

기본적으로 DisplayName 필드에는 인덱스가 없으므로 SQL Server는 전체 테이블을 스캔 한 다음 DisplayName을 기준으로 정렬해야합니다. 실행 계획은 다음과 같습니다 .

정렬 된 클러스터형 인덱스 스캔

약 30k의 서브 트리 비용이 추정되는 것은 많은 일입니다. PasteThePlan에서 select 연산자 위로 마우스를 가져 가면 알 수 있습니다. 따라서 100-200 행만 원하면 어떻게됩니까? 이 구문은 SQL Server 2012+에서 사용할 수 있습니다.

SELECT * FROM dbo.Users ORDER BY DisplayName OFFSET 100 ROWS FETCH NEXT 100 ROWS ONLY;

그것에 대한 실행 계획 도 꽤 추악합니다.

정렬 및 맨 위의 클러스터형 인덱스 스캔

SQL Server는 여전히 전체 테이블을 스캔하여 행 100-200을 제공하기 위해 정렬 된 목록을 작성하지만 비용은 여전히 ​​약 30k입니다. 더 나쁜 것은이 전체 목록은 쿼리가 실행될 때마다 다시 작성됩니다 (결국 누군가가 자신의 DisplayName을 변경했을 수 있기 때문입니다).

더 빠르게하기 위해 DisplayName에 비 클러스터형 인덱스를 만들 수 있습니다.이 인덱스는 특정 필드를 기준으로 정렬 된 테이블의 복사본입니다.

CREATE INDEX IX_DisplayName ON dbo.Users(DisplayName);

해당 인덱스를 사용하여 쿼리의 실행 계획은 이제 인덱스 탐색을 수행합니다.

인덱스 탐색 및 키 조회

쿼리는 즉시 완료되며 예상 하위 트리 비용은 0.66입니다 (30k와 반대).

요약하면 자주 실행하는 쿼리를 지원하는 방식으로 데이터를 구성하면 SQL Server에서 바로 가기를 수행하여 쿼리 속도를 높일 수 있습니다. 반면에 힙이나 클러스터형 인덱스 만 있으면 문제가 생길 수 있습니다.


"기본적으로 DisplayName 필드에는 인덱스가 없으므로 SQL Server는 전체 테이블을 스캔 한 다음 DisplayName을 기준으로 정렬해야합니다."이것이 매우 기본적인 질문 인 경우에는 용서해주십시오. "전체 테이블을 스캔하십시오"라고 말하면 모든 데이터가 메모리로 가져와 정렬됩니다 (올바른 방식으로 보이지 않음)?
AV94

귀하의 답변에서, 필드가 색인화 된 경우 SQL이 색인 (B-tree 등)을 찾고 해당 지점 (100 번째 행)으로 직접 이동하여 100 ~ 200 번째 행 가져 오기와 같은 쿼리를 만드는 것이 매우 효율적이라는 것을 이해합니다. 이것이 올바른 이해인지 말해 주시겠습니까?
AV94

첫 번째 질문에 대한 @AnilVedala-예, 데이터를 정렬해야합니다. 데이터베이스가 정렬되지 않은 목록으로 어떻게 그것을 달성 할 수 있습니까?
브렌트 오자르

1
. 두 번째 질문에 대한 @AnilVedala - (. 당신이 실행 계획을 읽어 그랜트 Fritchey에 의해 책의 실행 계획을 선택하는 방법에 대한 요구가있는 경우) 내가 준 마지막 실행 계획이 들어오는 곳이다
브렌트 Ozar

15

비 피복 인덱스를 사용하여 정렬을 피할 때 브렌트의 답변에 추가 된 것처럼, 다음 페이지 번호를 실행하면 아래를 실행하여 볼 수있는 잠재적 인 문제가 있습니다

SELECT * 
FROM dbo.Users 
ORDER BY DisplayName 
OFFSET 100000 ROWS 
FETCH NEXT 100 ROWS ONLY;

실행 계획은 100 개 행을 제외한 모든 행이 TOP 연산자에 의해 필터링 되더라도 조회가 100,100 회 실행되었음을 보여줍니다.

여기에 이미지 설명을 입력하십시오

아래 패턴을 사용하여 완화 할 수 있습니다.

WITH T
     AS (SELECT Id,
                DisplayName
         FROM   dbo.Users
         ORDER  BY DisplayName
        OFFSET 100000 ROWS 
        FETCH NEXT 100 ROWS ONLY
        )
SELECT U.*
FROM   dbo.Users U
       JOIN T
         ON U.Id = T.Id
ORDER  BY T.DisplayName 

이렇게하면 조회를 수행 하기 전에 마지막 100 개의 행을 제외한 모든 행을 필터링하여 큰 오프셋 값의 속도에 큰 영향을 줄 수 있습니다.

여기에 이미지 설명을 입력하십시오


3

쿼리 내에서 페이지 매김을 구현하는 방법, 데이터의 특성 및 시스템 구성 방식에 따라 달라집니다. SQL Server는 최소한의 노력으로 느끼는 것을 사용하여 데이터를 반환하려고 시도하는 것이 안전합니다. 명시적인 정렬 순서, 필터링, 그룹화 또는 윈도우 화가없는 경우 SQL Server는 쿼리 계획을 최적화하여 쿼리에 필요한 데이터가 포함 된 디스크의 페이지 만 반환 할 수 있습니다. 버퍼 풀. 정렬, 그룹화, 창 및 필터링을 포함하도록 쿼리 변경을 시작하자마자 복잡해지기 시작합니다.

여기 에는 다양한 페이지 매김 방법과 이들이 쿼리 계획에 미치는 영향에 대해 자세히 설명하는 SQL 성능에 관한 매우 유용한 기사 가 있습니다. 나는 그것을 읽고 나서 그들이 지적하는 다양한 방법 중 일부를 시도하고 자신의 시스템에서 어떤 쿼리 계획이 선택되었는지 확인하는 것이 좋습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.