인덱스 열의 매우 큰 테이블에서 SELECT TOP 1이 매우 느리지 만 역순 (“desc”)이 아닙니다.


17

강력한 서버에서 SQL Server 2014를 실행하는 약 1TB의 큰 데이터베이스가 있습니다. 몇 년 동안 모든 것이 잘 작동했습니다. 약 2 주 전에 다음을 포함한 전체 유지 관리를 수행했습니다. 모든 소프트웨어 업데이트 설치; 모든 인덱스와 컴팩트 DB 파일을 다시 빌드하십시오. 그러나 실제로드가 동일 할 때 특정 단계에서 DB의 CPU 사용량이 100 %에서 150 % 이상 증가 할 것으로 예상하지 못했습니다.

많은 문제 해결 후 매우 간단한 쿼리로 범위를 좁혔지만 해결책을 찾지 못했습니다. 쿼리는 매우 간단합니다.

select top 1 EventID from EventLog with (nolock) order by EventID

항상 약 1.5 초가 걸립니다! 그러나 "desc"를 사용하는 유사한 쿼리는 항상 약 0ms가 걸립니다.

select top 1 EventID from EventLog with (nolock) order by EventID desc

PTable에는 약 5 억 개의 행이 있습니다. 데이터 유형이 bigint (Identity 열) 인 EventID기본 클러스터형 인덱스 열 (ordered ASC)입니다. 맨 위에있는 테이블에 데이터를 삽입하는 스레드가 여러 개 (큰 EventID) 있으며 맨 아래에서 데이터를 삭제하는 스레드가 하나 (작은 EventID)입니다.

SMSS에서는 두 쿼리가 항상 동일한 실행 계획을 사용하는지 확인했습니다.

  • 클러스터형 인덱스 스캔;

  • 예상 행 번호와 실제 행 번호는 모두 1입니다.

  • 예상 및 실제 실행 수는 모두 1입니다.

  • 예상 I / O 비용은 8500입니다 (높은 것으로 보입니다)

  • 연속적으로 실행하는 경우 쿼리 비용은 둘 다에 대해 동일한 50 %입니다.

색인 통계를 업데이트했는데 with fullscan문제가 지속되었습니다. 색인을 다시 작성하고 반나절 동안 문제가 사라진 것처럼 보였지만 다시 돌아 왔습니다.

나는 다음과 같이 IO 통계를 켰다.

set statistics io on

그런 다음 두 쿼리를 연속적으로 실행하고 다음 정보를 찾았습니다.

(첫 번째 쿼리의 경우 느린 쿼리)

'PTable'테이블. 스캔 카운트 1, 논리적 읽기 407670, 물리적 읽기 0, 미리 읽기 0, lob 논리적 읽기 0, lob 물리적 읽기 0, lob 미리 읽기 0.

(두 번째 쿼리의 경우 빠른 쿼리)

'PTable'테이블. 스캔 카운트 1, 논리적 읽기 4, 물리적 읽기 0, 미리 읽기 0, lob 논리적 읽기 0, lob 물리적 읽기 0, lob 미리 읽기 0.

논리적 읽기의 큰 차이점에 유의하십시오. 인덱스는 두 경우 모두에 사용됩니다.

인덱스 조각화는 약간 설명 할 수 있지만 그 영향은 매우 작습니다. 그리고 문제는 전에 일어난 적이 없습니다. 또 다른 증거는 다음과 같은 쿼리를 실행하는 것입니다.

select * from EventLog with (nolock) where EventID=xxxx   

xxxx를 테이블에서 가장 작은 EventID로 설정하더라도 쿼리는 항상 매우 빠릅니다.

확인했으며 잠금 / 차단 문제가 없습니다.

참고 : 위의 문제를 단순화하려고했습니다. "PTable"은 실제로 "EventLog"입니다. 는 PID것입니다 EventID.

NOLOCK힌트 없이 동일한 결과 테스트를 얻습니다 .

아무도 도와 줄 수 있습니까?

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

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

다음과 같은 XML의보다 자세한 쿼리 실행 계획 :

https://www.brentozar.com/pastetheplan/?id=SJ3eiVnob

https://www.brentozar.com/pastetheplan/?id=r1rOjVhoZ

create table 문을 제공하는 것이 중요하다고 생각하지 않습니다. 오래된 데이터베이스이며 유지 관리까지 오랫동안 완벽하게 실행되었습니다. 우리는 많은 연구를 스스로 해왔고 내 질문에 제공된 정보로 좁혔습니다.

테이블은 EventID열을 기본 키로 사용하여 정상적으로 작성되었으며 이는 identity유형 의 열입니다 bigint. 현재 색인 조각화에 문제가 있다고 생각합니다. 인덱스 재 구축 직후, 반나절 동안 문제가 사라진 것 같습니다. 근데 왜 이렇게 빨리 돌아 왔어?

답변:


18

Clustered Index Scan은 423,723 개의 논리적 읽기를 표시하여 첫 번째 행을 반환하며 1926ms가 걸립니다.

견과류

이것은 색인 순서에서 첫 번째 행을 찾는 데 많은 것 같습니다.

대부분의 경우 당신의 유령 정리 작업은 먼 길의 뒤에를 실행하거나 중지되었습니다. ghost_record_count클러스터형 인덱스를 확인하고 sys.dm_db_index_physical_stats시간이 지남에 따라 변경 사항을 모니터링 해야합니다 .

스캔 명령 이 반환하는 최초의 '살아있는'행을 찾기 전에 고스트 기록을 엄청 많이 이상 스캔이 일정 삭제 활동을보고있다 인덱스의 끝에서. 추가 논리적 읽기에 대해 설명합니다. b- 트리를 인덱스의 가장 낮은 값으로 탐색하면 고스트 레코드가 훨씬 적습니다.

성능에 영향을주는 또 다른 요소는 스토리지 엔진 내부 : Paul Randal의 고스트 정리 깊이에서 언급 한대로 스캔 자체가 고스트 레코드를 제거하는 역할을합니다 .

추적 플래그 661 (고스트 정리 비활성화)이 활성화되어 있지 않은지 확인해야합니다.

솔루션

고스트 정리 프로세스가 완전히 중지 된 경우 가장 효과적인 해결책은 일반적으로 SQL Server 인스턴스를 다시 시작하는 것입니다. 또한 SQL Server가 최신 누적 업데이트 중 하나를 실행하고 있는지 확인해야합니다. 수년 동안 많은 유령 정리 버그가있었습니다.

특정한 경우 :

동일한 서버의 다른 테스트 데이터베이스로 인해 문제가 발생한 것으로 나타났습니다. 해당 테스트 데이터베이스는 "데이터 손실"로 복원되었으며 손상되었습니다. 놀랍게도 고스트 정리 프로세스가 해당 데이터베이스에 걸린 것 같습니다. SMSS에서 손상된 데이터베이스를 삭제하면 문제가 저절로 해결되었습니다 (오래 걸렸으며 잠시 동안 DB가 잠겼을 수 있음).

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