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


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.