SQL 2005와 SQL 2008R2에서 다르게 실행되는 쿼리


9

내 사무실에는 꽤 추한 쿼리가 있지만 프로덕션 및 개발 환경 (각각 20 초 및 4 초)에서 잘 실행됩니다. 그러나 테스트 환경에서는 4 시간 이상이 소요됩니다. SQL2005 (+ 최신 패치)가 프로덕션 및 개발에서 실행 중입니다. SQL2008R2가 테스트 중입니다.

쿼리 계획을 살펴본 결과 SQL2008R2가 연결된 서버에서 반환 된 행을 저장하기 위해 테이블 ​​스풀 (lazy spool)을 통해 TempDB를 사용하고 있음을 보여줍니다. 다음 단계는 쿼리의 96.3 %를 차지하는 중첩 루프 (왼쪽 반 세미 조인)를 표시하는 것입니다. 두 사업자 사이의 노선은 5,398MB입니다!

SQL 2005에 대한 쿼리 계획은 tempdb를 사용하지 않고 Left Anti Semi Join을 사용하지 않음을 보여줍니다.

아래는 위생 처리 된 코드이며 실행 계획은 2005 년 계획을 맨 위에, 2008R2는 맨 아래를 계획합니다.

급격한 속도 저하 및 변화의 원인은 무엇입니까? 다른 실행 계획을 기대하고 있었기 때문에 귀찮게하지 않습니다. 쿼리 시간이 크게 느려지면 문제가 발생합니다.

2008R2 버전이 tempdb를 사용하고 있기 때문에 기본 하드웨어를 살펴 봐야합니까, 사용법을 최적화하는 방법을 살펴 봐야합니까?

쿼리를 작성하는 더 좋은 방법이 있습니까?

도와 주셔서 감사합니다.

    INSERT INTO Table1_GroupLock (iGroupID, dLockedDate)
SELECT 
 Table1.iGroupID,
 GETDATE()
FROM Table1
WHERE 
 NOT EXISTS (
  SELECT 1
  FROM LinkedServer.Database.Table2 Alias2
  WHERE 
   (
    Alias2.FirstName + Alias2.LastName = dbo.fnRemoveNonLetter(Table1.FullName)
    AND NOT dbo.fnRemoveNonLetter(Table1.FullName) IS NULL
    AND NOT Alias2.FirstName IS NULL 
    AND NOT Alias2.LastName  IS NULL
   ) OR (
    Alias2.FamilyName = dbo.fnRemoveNonLetter(Table1.FamilyName)
    AND Alias2.Child1Name = dbo.fnRemoveNonLetter(Table1.Child1Name)
    AND NOT dbo.fnRemoveNonLetter(Table1.FamilyName) IS NULL
    AND NOT dbo.fnRemoveNonLetter(Table1.Child1Name) IS NULL
    AND NOT Alias2.Familyname IS NULL
    AND NOT Alias2.Child1Name IS NULL
   ) OR (
    Alias2.StepFamilyName = dbo.fnRemoveNonLetter(Table1.StepFamilyName)
    AND Alias2.StepFamilyNameChild1 = dbo.fnRemoveNonLetter(Table1.StepFamilyNameChild2)
    AND NOT Alias2.StepFamilyName IS NULL
    AND NOT Alias2.StepFamilyNameChild1 IS NULL
    AND NOT dbo.fnRemoveNonLetter(Table1.StepFamilyName) IS NULL
    AND NOT dbo.fnRemoveNonLetter(Table1.StepFamilyNameChild2) IS NULL
   )  
 ) AND NOT EXISTS (
  SELECT 1
  FROM Table3
  INNER JOIN Table4
   ON Table4.FirstNameType = Table3.FirstNameType 
  INNER JOIN table5
   ON table5.LastNameType = Table3.LastNameType 
  WHERE 
   Table3.iGroupID = Table1.iGroupID
   AND Table3.bIsClosed = 0
   AND Table4.sNameTypeConstant = 'new_lastname'
   AND table5.sFirstNameConstant = 'new_firstname'
 )

SQL-2005


SQL2008R2

:: EDIT :: 다른 SQL2005 인스턴스에서 쿼리를 실행했습니다. "좋은 인스턴스"와 거의 동일한 실행 계획입니다. 2008R2 인스턴스보다 2008R2 인스턴스보다 두 2005 버전이 2008R2 연결된 서버에서 어떻게 더 잘 실행되는지 확실하지 않습니다.

코드가 일부 작업을 사용할 수 있다는 것을 부인하지는 않지만 코드가 문제라면 모든 시험에서 동일한 실행 계획이 보이지 않습니까? SQL 버전에 관계없이?

:: 편집 :: SP1과 CU3을 2008R2 인스턴스 모두에 적용했지만 주사위는 없습니다. 연결된 서버에서 배열을 구체적으로 설정했습니다. 주사위는 없습니다. 두 인스턴스 모두에서 사용자 계정의 권한을 sysadmin으로 설정했습니다. 또한 SQL Server 2008 내부 및 문제 해결을 기억했으며, 어떻게 추적 할 수 있는지 확인할 것입니다.

도움과 팁을 주셔서 감사합니다.

:: 편집 :: 연결된 서버에 대한 다양한 권한 변경을 수행했습니다. SQL 로그인, 도메인 로그인, 사용자를 가장하고 "이 보안 컨텍스트를 사용하여 작성"옵션을 사용했습니다. 서버에서 sysadmin 권한을 가진 연결된 서버의 양쪽에 사용자를 만들었습니다. 아이디어가 없습니다.

SQL2005가 SQL2008R2와 크게 다른 쿼리를 실행하는 이유를 여전히 알고 싶습니다. 잘못된 쿼리 인 경우 SQL2005와 SQL2008R2 모두에서 4 시간 이상의 런타임이 표시됩니다.

답변:


5

쿼리를 재 작업하고 싶습니다.

Sargability 문제가 있으며 스칼라 함수 호출을 사용하여 쿼리를 손상시킬 수도 있습니다. Table2에 FullName 계산 열을 만들고 인덱스를 추가하여 인덱스에 FirstName 및 LastName이 포함되도록 할 수 있습니다. 또한 다른 쪽을 돕는 색인을 추가해야합니다

또한 "RemoveNonLetter"기능을 수행 할 수 있도록 인라인 테이블 반환 함수를 만들고 여기에서 한 것처럼 APPLY를 사용하여 쿼리를 다시 사용하십시오.

그리고 바울의 대답이 말하는 그 벌레를 확실히 확인하십시오 .

INSERT INTO Table1_GroupLock (iGroupID, dLockedDate)
SELECT 
 Table1.iGroupID,
 GETDATE()
FROM Table1
OUTER APPLY (SELECT NonLettersRemoved FROM dbo.ifnRemoveNonLetter(Table1.FullName)) AS fn (FullName)
OUTER APPLY (SELECT NonLettersRemoved FROM dbo.ifnRemoveNonLetter(Table1.FamilyName)) AS famn (FamilyName)
OUTER APPLY (SELECT NonLettersRemoved FROM dbo.ifnRemoveNonLetter(Table1.Child1Name)) AS c1n (Child1Name)
OUTER APPLY (SELECT NonLettersRemoved FROM dbo.ifnRemoveNonLetter(Table1.StepFamilyName)) AS sfn (StepFamilyName)
OUTER APPLY (SELECT NonLettersRemoved FROM dbo.ifnRemoveNonLetter(Table1.StepFamilyNameChild2)) AS sfnc2 (StepFamilyNameChild2)
WHERE 
 NOT EXISTS (
  SELECT 1
  FROM LinkedServer.Database.Table2 Alias2
  WHERE Alias2.FullName = fn.FullName
  UNION ALL
  SELECT 1
  FROM LinkedServer.Database.Table2 Alias2
  WHERE Alias2.FamilyName = famn.FamilyName AND Alias2.Child1Name = c1n.Child1Name
  UNION ALL
  SELECT 1
  FROM LinkedServer.Database.Table2 Alias2
  WHERE Alias2.StepFamilyName = sfn.StepFamilyName AND Alias2.StepFamilyNameChild1 = sfnc2.StepFamilyNameChild2
 ) 
 AND NOT EXISTS (
  SELECT 1
  FROM Table3
  INNER JOIN Table4
   ON Table4.FirstNameType = Table3.FirstNameType 
  INNER JOIN table5
   ON table5.LastNameType = Table3.LastNameType 
  WHERE 
   Table3.iGroupID = Table1.iGroupID
   AND Table3.bIsClosed = 0
   AND Table4.sNameTypeConstant = 'new_lastname'
   AND table5.sFirstNameConstant = 'new_firstname'
 )
;

6

이전 답변에 추가하여 계획 회귀의 이유는 계획에 반반 결합이 포함 된 경우 알려진 카디널리티 추정 버그 때문일 있습니다. KB 2222998 참조

2005 계획이 허용 가능한 성능을 냈다고 가정하면 해당 수정 사항이 포함 된 버전으로 서버를 가져 오면 (TF4199를 활성화하여) '좋은'계획으로 돌아갈 수 있습니다.

즉, 해당 쿼리를 개선 할 수있는 다른 많은 기회가 있으므로 지금은이 작업에 집중해야합니다.


5

원격 데이터 중 하나가 로컬로 스풀링되도록 제안합니다.

  1. 연결된 서버 설정 (예 : 데이터 정렬)이 동일하지 않습니다
  2. 연결된 서버 설정에도 불구하고 로컬 데이터 정렬은 원격과 동일하지 않습니다.
  3. 권한으로 인해 쿼리를 원격으로 올바르게 실행할 수 없습니다

포인트 1의 경우 sp_serveroption
및 포인트 2의 경우 서버 / DB 데이터 정렬도 확인하십시오.

포인트 3은 Linchi Shea에서 다음을 참조하십시오.

내 대답에 따라 SQL Server에 모든 데이터를 로컬로 처리하도록 요청 합니다.보기에서 OPENQUERY 사용의 성능 영향

편집하다

두 번째로, "좋은"계획에 대한 두 개의 원격 호출이 하나가 아닌 것을 봅니다. 이것은 내가 여기서 말하는 것을 확인합니다.


오래 기다려서 죄송합니다. 1 : 연결된 서버 설정을 확인했는데 같은 것입니다. 2 : 연결된 서버 속성의 데이터 정렬을 확인하고 암시 적으로 원격 서버로 설정했습니다. 3 : 여전히 A / B 테스트를 수행하는 보안 컨텍스트입니다. 나는 여전히 다른 실행 계획의 배후에있는 논리에 대해 고민하고 있습니다. R2 서버에서 R2 서버까지는 선택 (150K 행 이상) 만 실행 한 다음 조인을 수행합니다. 2005에서 R2까지는 선택을 수행하고 원격 서버에서 조인합니다. 두 시나리오의 보안 컨텍스트는 동일합니다.
RateControl

3

datagod에서 쿼리 주석을 다시 작성해보십시오.

또한 연결된 서버 측의 권한 문제로 인해 속도가 느려지는지 궁금합니다. 얼마 전에이 연결된 서버 속도 저하 에 대해 블로그에 올렸습니다 . perms를 검증 할 가치가있을 수 있습니다 (SQL 연결된 서버입니까? 아니면 다른 DBMS입니까?

테스트 환경에 SQL Server 2005가 있어도이 쿼리를 시도하고 환경을 배제해야합니까?

업그레이드 이후 통계를 다시 작성 했습니까?


3

이 비교에는 많은 문제가 있습니다 ... 나는 어디에서 시작 해야할지 모르겠습니다.

  1. 생산 및 테스트 기계에 대한 정확한 사양을 확인하십시오.

  2. 두 환경에서 다양한 링크 된 서버 사이의 네트워크 링크를 결정하십시오. 그들은 같은 속도입니까? 서버가 두 환경에서 서로 옆에 있습니까?

  3. 연결된 서버를 사용하지 않기 위해 쿼리를 다시 작성할 수있는 방법이 있습니까? 여러 서버에서 테이블을 조인하면 토폴로지 변경에 취약 해지며 대부분의 경우 그의 속도가 느려집니다.

  4. NOT 및 OR을 사용하면 일반적으로 전체 테이블 스캔이 발생합니다. 쿼리를 다시 작성하십시오.

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