"때때로"느린 쿼리 진단에 대한 조언


20

커버링 인덱스를 통해 인덱싱 된 뷰에서 결과를 반환하는 저장 프로 시저가 있습니다. 일반적으로 빠르게 (~ 10ms) 실행되며 때로는 최대 8 초까지 실행될 수 있습니다.

다음은 임의 실행의 예입니다 (참고 : 속도는 느리지 않지만 쿼리 텍스트는 전달 된 값과 동일합니다).

declare @p2 dbo.IdentityType
insert into @p2 values(5710955)
insert into @p2 values(5710896)
insert into @p2 values(5710678)
insert into @p2 values(5710871)
insert into @p2 values(5711103)
insert into @p2 values(6215197)
insert into @p2 values(5710780)

exec ListingSearch_ByLocationAndStatus @statusType=1,@locationIds=@p2

SPROC는 다음과 같습니다.

ALTER PROCEDURE [dbo].[ListingSearch_ByLocationAndStatus]
    @LocationIds IdentityType READONLY,
    @StatusType TINYINT
AS
BEGIN
    SET NOCOUNT ON;

    SELECT      -- lots of fields
    FROM        [dbo].[ListingSearchView][a] WITH (NOEXPAND)
    INNER JOIN  @LocationIds [b] ON [a].[LocationId] = [b].[Id]
    WHERE       [a].[StatusType] = @statusType
    OPTION (RECOMPILE);

(참고 : OPTION (RECOMPILE)최근에 조언을 한 후에 힌트를 추가 했지만 도움이되지 않았습니다.

커버링 인덱스는 다음과 같습니다 (참고 : 뷰에는 클러스터 된 인덱스도 있습니다. ListingId고유)

CREATE NONCLUSTERED INDEX [IX_ListingSearchView_ForAPI] ON [dbo].[ListingSearchView]
(
    [LocationId] ASC,
    [StatusType] ASC
)
INCLUDE ( -- all the fields in the query) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
GO

실행 계획 XML 통계와 함께 프로파일 러 추적을 설정했습니다.

느린 것 (6 초)과 관련 계획은 다음과 같습니다. 여기에 이미지 설명을 입력하십시오

예상대로 정확하게 보이고 쿼리가 빠를 때와 동일한 계획입니다.

도움이 될 경우 계획에서 비용이 많이 드는 부분을 확대하면 다음과 같습니다. 여기에 이미지 설명을 입력하십시오

도움이되는 경우보기 / 백업 테이블의 전체 스키마는 다음과 같습니다. https://pastebin.com/wh1sRcbQ

노트:

  • 인덱스가 조각 모음되어 통계가 최신 상태입니다.
  • 원래 쿼리는 뷰와 인라인되었지만 SPROC로 이동하여 안정화하려고 시도했습니다. 도움이되지 않았습니다.
  • WITH OPTION (RECOMPILE);힌트 추가 (작동하지 않았으므로 매개 변수 스니핑 할 수 없습니까?)
  • 시스템의 다른 쿼리도 때때로 느리게 실행되며 계획에 명백한 문제가 없습니다.
  • 잠글 수 있습니까? 확인 방법을 잘 모르겠습니다.

다음에 시도 할 수있는 아이디어가 있습니까?

감사


1
의견은 긴 토론을위한 것이 아닙니다. 이 대화는 채팅 으로 이동 되었습니다 . 모두 : 이 질문에 대한 자세한 논의를 위해 해당 시설을 이용하십시오.
— Paul White에 따르면 GoFundMonica는

주어진 링크가 작동하지 않습니다 .proc 쿼리는 간단합니다. 실제와 예상 행 수 사이에 큰 차이가 있습니다. 문제가 뷰 쿼리에 있다고 생각합니다. 데이터가 충분하지 않다고 생각합니다
— KumarHarsh

쿼리가 실행되는 동안 WhoIsActive (Adam Machanic 작성)를 실행 해 보셨습니까? whoisactive.com 대기중인 작업에 대한 정보를 포함하며 올바른 방향으로 안내해야합니다.
— MJH

이 문제를 일으키는 DB 외부의 무언가를 제거 했습니까? 아마도 다른 응용 프로그램이 DB와 ​​공유 된 스토리지에 동기 IO를 유발합니까?
— Johan

답변:


2

나는 OPTION (RECOMPILE)매개 변수 스니핑 가능성을 제거하는 효과적인 방법을 사용한다고 생각하지 않습니다 .

매개 변수 스니핑은 SQL이 특정 쿼리에 대해 혼란 스러울 때 발생하며 새로운 매개 변수를보고 새로운 쿼리를 생각합니다. 새로운 실행 계획을 생성하는 데 시간이 더 걸리기 때문에 속도가 느립니다.

이 모든 옵션은 SQL이 매번 새로운 계획을 생성하도록 강제하는 것입니다. 대신이 힌트를 사용하여 기본 매개 변수를 추가하는 것이 좋습니다.

OPTION(OPTIMIZE FOR(@LocationIds='xx',@StatusType='xx'))

기본값으로 매개 변수를 선택할 때 통계적으로 대표되는 세트를 사용해야합니다.
이렇게하면 매번 같은 계획이 사용되며 매개 변수 스니핑 가능성이 없어집니다. 일단 그렇게하고 도움이되지 않았다고 판단되면 매개 변수 스니핑을 가능성으로 무시하는 것이 안전 할 것입니다.


1

아마도 순서를 강제하려고 시도 할 수도 있으므로 항상 작은 테이블 (변수)로 시작하는 것일 수 있습니다. 그래도보기가 까다로워집니다 ...

    SELECT  -- lots of fields
    FROM    @LocationIds [b] WITH (NOEXPAND)
            INNER JOIN  [dbo].[ListingSearchView][a] WITH (NOEXPAND) 
                ON [a].[LocationId] = [b].[Id]
    WHERE   [a].[StatusType] = @statusType
    OPTION (FORCE ORDER);

또는 일반적으로 테이블 변수를 뷰에 조인하는 방법 인 경우 루프 조인을 강제 실행할 수 있습니다.

    SELECT  -- lots of fields
    FROM    @LocationIds [b] WITH (NOEXPAND)
            INNER LOOP JOIN  [dbo].[ListingSearchView][a] WITH (NOEXPAND) 
                ON [a].[LocationId] = [b].[Id]
    WHERE   [a].[StatusType] = @statusType
    --leaving this here so you don't get an annoying warning 
    OPTION (FORCE ORDER);

0

쿼리 편집기에서 저장 프로 시저 이름을 쓴 다음 저장 프로 시저를 선택하십시오. 이름 & 다음 예상 실행 계획 표시를 선택하거나 (Ctrl + L)을 클릭하십시오. 이 이미지 아래.

디스플레이 예상 실행 계획 이미지

그러면 실행 계획이 쿼리 편집기 맨 아래의 메시지 탭 옆에 표시됩니다. 녹색 선에 누락 된 인덱스 세부 사항이 표시되면 마우스 오른쪽 단추를 클릭하십시오. 그런 다음 새 탭에서 새 쿼리를 연 다음 INDEX를 만듭니다. 그런 다음 쿼리가 빠르게 실행됩니다.

그래서 나는이 방법을 사용하여 느리게 작동하는 쿼리를 진단했습니다. 또한 사용할 수있는 쿼리 나 메소드가 너무 많습니다.

세부 사항이 포함 된 실행 계획


-1

문제가 차단되고 있다고 생각되면 낙관적 트랜잭션 격리 수준 읽기 커밋 된 스냅 샷을 사용하는 것이 좋습니다 (tempDB에 오버 헤드가 발생 함을 명심하십시오).

참조 : https://docs.microsoft.com/en-us/dotnet/framework/data/adonet/sql/snapshot-isolation-in-sql-server

문제가 읽기 / 쓰기 차단에 있지 않으므로 뷰에 인덱스를 추가해 볼 수 있습니다 (인덱스를 선택하는 가장 좋은 방법은 데이터의 선택성에 따라 다름)

CREATE NONCLUSTERED INDEX IX_ListingSearchView (LocationID, StatusType) INCLUDE (other columns...)

1
제안한 색인이 이미 존재합니다 IX_ListingSearchView_ForAPI(질문의 스크립트 참조).
— Paul White에 따르면 GoFundMonica는

1
대답 해줘서 고마워 내 질문에서 말했듯 이 수정 사항을 적용하기 전에 문제가 무엇인지 알고 싶습니다 . 그렇지 않으면 실제 문제를 간과하고있을 수 있습니다. 내 질문은 먼저 문제를 찾은 다음 올바른 해결책에 관한 것입니다.
— RPM1984

로컬 환경에서 느린 쿼리를 얻을 수 있습니까? 동일한 쿼리가 때때로 느리게 실행되고 때로는 빠르게 실행되는 경우 입력 매개 변수에 따라 달라질 수 있습니다. 느린 쿼리에서 반환 된 논리적 읽기 수와 총 행 수를 제공 할 수 있습니까?
— Artashes Khachatryan

@ArtashesKhachatryan 네, 때로는 로컬에서도 느리게 실행됩니다. 실행 계획으로 질문을 업데이트했습니다. 말씀 드린 것처럼 느린 쿼리가 빠른 쿼리보다 많은 행을 반환하는 것과 관련이 있는지 궁금합니다.
— RPM1984
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.