쿼리 저장소 검색을 종료하지 않습니다


10

처음부터 내 질문 / 문제 가이 이전 질문과 비슷하다고 말하지만 원인이나 시작 정보가 같은지 확실하지 않기 때문에 질문에 대한 자세한 내용을 게시하기로 결정했습니다.

당면한 문제 :

  • (업무 일이 끝날 무렵) 이상한 시간에 프로덕션 인스턴스가 잘못 작동하기 시작합니다.
    • 인스턴스의 높은 CPU (기준선에서 ~ 30 %에서 약 두 배로 증가했지만 여전히 증가하고 있음)
    • 초당 트랜잭션 수 증가 (앱로드에는 변화가 없지만)
    • 유휴 세션 수 증가
    • 이 동작을 표시하지 않은 세션 간 이상한 차단 이벤트 (커밋되지 않은 세션을 읽은 경우에도 차단이 발생 함)
    • 간격에 대한 상위 대기가 1 위에서 비 페이지 래치였으며 잠금이 2 위를 차지했습니다.

초기 조사 :

  • sp_whoIsActive를 사용하여 모니터링 도구에 의해 실행 된 쿼리가 매우 느리게 실행되고 이전에는 발생하지 않았던 CPU를 많이 사용하기로 결정했습니다.
  • 격리 수준을 커밋되지 않은 상태로 읽었습니다.
  • 약 150TB의 예상 데이터가 반환되는 엉뚱한 숫자 인 StatementEstRows = "3.86846e + 010"을 본 계획을 살펴 보았습니다.
  • 모니터링 도구의 쿼리 모니터 기능이 원인 인 것으로 의심되어 해당 기능을 사용하지 않도록 설정했습니다 (제공자에게 문제가 있는지 확인하기 위해 티켓을 열었습니다)
  • 첫 번째 사건부터 몇 번 더 일어났습니다. 세션을 종료 할 때마다 모든 것이 정상으로 돌아갑니다.
  • 쿼리가 모니터링 저장소 모니터링을 위해 BOL에서 MS에 의해 사용 된 쿼리 중 하나 와 매우 유사하다는 것을 알고 있습니다. 최근에 성능이 저하 된 쿼리 (다른 시점 비교)
  • 동일한 쿼리를 수동으로 실행하고 동일한 동작 (CPU 사용 증가, 래치 대기 증가, 예기치 않은 잠금 등)을 확인합니다.

유죄 질의 :

Select qt.query_sql_text, 
    q.query_id, 
    qt.query_text_id, 
    rs1.runtime_stats_id AS runtime_stats_id_1,
    interval_1 = DateAdd(minute, -(DateDiff(minute, getdate(), getutcdate())), rsi1.start_time), 
    p1.plan_id AS plan_1, 
    rs1.avg_duration AS avg_duration_1, 
    rs2.avg_duration AS avg_duration_2,
    p2.plan_id AS plan_2, 
    interval_2 = DateAdd(minute, -(DateDiff(minute, getdate(), getutcdate())), rsi2.start_time), 
    rs2.runtime_stats_id AS runtime_stats_id_2
From sys.query_store_query_text AS qt 
Inner Join sys.query_store_query AS q 
    ON qt.query_text_id = q.query_text_id 
Inner Join sys.query_store_plan AS p1 
    ON q.query_id = p1.query_id 
Inner Join sys.query_store_runtime_stats AS rs1 
    ON p1.plan_id = rs1.plan_id 
Inner Join sys.query_store_runtime_stats_interval AS rsi1 
    ON rsi1.runtime_stats_interval_id = rs1.runtime_stats_interval_id 
 Inner Join sys.query_store_plan AS p2 
    ON q.query_id = p2.query_id 
Inner Join sys.query_store_runtime_stats AS rs2 
    ON p2.plan_id = rs2.plan_id 
Inner Join sys.query_store_runtime_stats_interval AS rsi2 
    ON rsi2.runtime_stats_interval_id = rs2.runtime_stats_interval_id
Where rsi1.start_time > DATEADD(hour, -48, GETUTCDATE()) 
    AND rsi2.start_time > rsi1.start_time 
    AND p1.plan_id <> p2.plan_id
    AND rs2.avg_duration > rs1.avg_duration * 2
Order By q.query_id, rsi1.start_time, rsi2.start_time

설정 및 정보 :

  • Windows Server 2012R2 클러스터의 SQL Server 2016 SP1 CU4 Enterprise
  • 쿼리 저장소가 활성화되고 기본값으로 구성됨 (설정이 변경되지 않음)
  • SQL 2005 인스턴스에서 가져온 데이터베이스 (그리고 여전히 호환성 수준 100)

경험적 관찰 :

  • 엉뚱한 통계로 인해, 우리는 잘못된 추정 계획에 사용 된 모든 * plan_persist ** 객체를 가져 왔고 (실제 계획은 아직 쿼리를 완료하지 못함) 통계를 확인했습니다. 계획에 사용 된 일부 인덱스에는 통계가 없었습니다. (DBCC SHOWSTATISTICS가 아무것도 반환하지 않았습니다. sys.stats에서 선택하면 일부 인덱스에 대해 NULL stats_date () 함수가 표시되었습니다.

빠르고 더러운 솔루션 :

  • Query Store와 관련된 시스템 개체에 대해 누락 된 통계를 수동으로 생성하거나
  • 새로운 CE (traceflag)를 사용하여 쿼리를 강제 실행합니다. 또한 필요한 통계를 생성 / 업데이트하거나
  • 데이터베이스의 호환성 수준을 130으로 변경 (기본적으로 새 CE를 사용함)

따라서 내 실제 질문은 다음과 같습니다.

Query Store의 쿼리로 인해 전체 인스턴스에서 성능 문제가 발생하는 이유는 무엇입니까? Query Store에서 버그 영역에 있습니까?

추신 : 일부 파일 (인쇄 화면, IO 통계 및 계획)을 짧은 시간에 업로드합니다.

Dropbox에 추가 된 파일 .

계획 1- 초기 엉뚱한 생산 계획

계획 2- 테스트 환경에서 실제 계획, 오래된 CE (동일한 동작, 엉뚱한 통계)

계획 3- 테스트 환경에서 실제 계획, 새로운 CE


1
결국 쿼리 저장소를 비활성화하고 근본 원인이 무엇인지 확인했습니다 (확실히 하나 이상의 문제가 있음). 결국 CPU는 쿼리 저장소에서 통계를 표시하기 위해 클릭 한 모든 것을 증가시킵니다.
A_V

답변:


6

대답에서 말했듯이 경험적 테스트는 통계가 생성되지 않은 sys.plan_persisted * 시스템 객체에 대한 인덱스가 있음을 보여줍니다. 데이터베이스가 SQL 2005 인스턴스에서 마이그레이션되어 호환성 수준 100으로 일정 시간 유지되어 새 CE를 사용하지 않았기 때문입니다.

행 개수 확인 :

Select count(1) from NoNameDB.sys.plan_persist_runtime_stats with (nolock) --60362   
Select count(1) from NoNameDB.sys.plan_persist_plan with (nolock) --1853    
Select count(1) from NoNameDB.sys.plan_persist_runtime_stats_interval with (nolock) --671    
Select count(1) from NoNameDB.sys.plan_persist_query with (nolock) --1091    
Select count(1) from NoNameDB.sys.plan_persist_query_text with (nolock) --911

이는 초기 추정치가 잘못되었음을 나타냅니다. DAC 연결로 완료되었습니다. 그렇지 않으면 테이블을 쿼리 할 수 ​​없습니다.

통계 확인 :

DBCC SHOW_STATISTICS ('sys.plan_persist_runtime_stats_interval', plan_persist_runtime_stats_interval_cidx);    
DBCC SHOW_STATISTICS ('sys.plan_persist_runtime_stats', plan_persist_runtime_stats_idx1);    
DBCC SHOW_STATISTICS ('sys.plan_persist_runtime_stats', plan_persist_runtime_stats_cidx);    
DBCC SHOW_STATISTICS ('sys.plan_persist_plan', plan_persist_plan_cidx);    
DBCC SHOW_STATISTICS ('sys.plan_persist_plan', plan_persist_plan_idx1);    
DBCC SHOW_STATISTICS ('sys.plan_persist_query', plan_persist_query_cidx)    
DBCC SHOW_STATISTICS ('sys.plan_persist_query_text', plan_persist_query_text_cidx);

이것은 일부 인덱스에 빈 통계가 있음을 보여주었습니다 (없음, 없음, 0).

초기 수정 :

UPDATE STATISTICS sys.plan_persist_runtime_stats WITH fullscan;
UPDATE STATISTICS sys.plan_persist_plan WITH fullscan;
UPDATE STATISTICS sys.plan_persist_runtime_stats_interval WITH fullscan;
UPDATE STATISTICS sys.plan_persist_query WITH fullscan;
UPDATE STATISTICS sys.plan_persist_query_text WITH fullscan;

이런 종류의 통계를 수정하고 쿼리를 10-12 초 만에 완료했습니다.

두번째 수정 :

(테스트 환경에서만 확인 됨) 쿼리에 대한 최상의 통계를 보여 주었으므로 데이터베이스의 호환성 수준을 130으로 변경하는 것이 가장 적절했을 것입니다. 결과적으로 쿼리가 약 10-12 초 후에 종료되었습니다. 일반 숫자 통계 (10k 행).

중급 수정 :

DBCC TRACEON (2312) -- new CE

시스템 숨김 테이블의 통계에 대한 일부 관련 도움말


3

SSMS에서 실제 계획을 열고 CPU 사용량을 살펴 보거나 XML을 검토 할 때 표시되는 기본 문제는 TVF 인 노드 32입니다. 느린 Query Store 쿼리의 원인은 메모리 내 TVF에 대한 반복 액세스입니다 .

TVF 비용

이 TVF에서 리턴되는 행 수는 중요하지 않으며 액세스 한 횟수 만 중요합니다. 수정은 계획을 여러 번 읽지 않도록하기 위해 할 수있는 모든 조치입니다.

제한적인 디버깅 (기술과 소비 시간 모두)을 기반으로, 내 가설은 Query Store 데이터의 특정 메모리 내 구성 요소에 할당 된 전체 메모리가 각 TVF 실행과 함께 스캔된다는 것입니다. sp_query_store_flush_db또는 로이 메모리 할당에 영향을 미치지 못했습니다 DBCC FREESYSTEMCACHE.

지금까지의 성공적인 해결 방법에는 계획 지침, 힌트 ( OPTION(HASH JOIN, LOOP JOIN)지금까지는 충분히 효과가 있었음 ) 및 AG의 읽기 전용 노드에서 쿼리 저장소 쿼리 실행이 포함됩니다.

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