태그 보관물: sql-server

sql-server

SQL Server 2012에서 빈 결과 집합으로 쿼리 오류가 발생하는 이유는 무엇입니까? 쿼리는 실패하지만 첫 번째 쿼리는 실패하지

MS SQL Server 2012에서 다음 쿼리를 실행할 때 두 번째 쿼리는 실패하지만 첫 번째 쿼리는 실패하지 않습니다. 또한 where 절없이 실행하면 두 쿼리가 모두 실패합니다. 둘 다 빈 결과 집합을 가져야하는데 왜 실패할까요? 모든 도움 / 통찰력을 부탁드립니다.

create table #temp
(id     int primary key)

create table #temp2
(id     int)

select 1/0
from #temp
where id = 1

select 1/0
from #temp2
where id = 1


답변

실행 계획을 처음 살펴보면 표현식 1/0이 Compute Scalar 연산자에 정의되어 있음을 보여줍니다 .

이제 실행 계획이 맨 왼쪽에서 실행되기 시작하지만 자식 반복자 에서 반복적으로 호출 Open하고 GetRow메서드를 반환하여 결과를 반환하지만 SQL Server 2005 이상에는 계산 이 종종 계산 스칼라에 의해서만 정의 되고 그 이후까지 평가가 지연 되는 최적화가 포함되어 있습니다. 작업 결과가 필요합니다 .

이 경우 표현식 결과 는 클라이언트로 리턴하기 위해 행을 어셈블 할 때만 필요합니다 (녹색 SELECT아이콘 에서 발생한다고 생각할 수 있음 ). 이 논리에 따르면 지연된 평가는 계획이 리턴 행을 생성하지 않으므로 표현식이 평가되지 않음을 의미합니다. 포인트를 조금만 사용하기 위해 Clustered Index Seek 또는 Table Scan이 행을 반환하지 않으므로 클라이언트로 반환하기 위해 어셈블 할 행이 없습니다.

그러나 일부 표현은 다음과 같이 확인 할 수있다 별도의 최적화가 런타임 상수쿼리 실행이 시작되기 전에 일단 평가는 . 이 경우 실행 계획 XML (왼쪽의 클러스터 된 인덱스 검색 계획, 오른쪽의 테이블 스캔 계획)에서이 문제가 발생했음을 나타냅니다.

기본 메커니즘 과이 블로그 게시물에서 성능 영향을 줄 수있는 방법에 대해 더 많이 썼습니다 . 여기에 제공된 정보를 사용하여 첫 번째 쿼리를 수정하여 실행이 시작되기 전에 두 표현식을 모두 평가하고 캐시 할 수 있습니다.

select 1/0 * CONVERT(integer, @@DBTS)
from #temp
where id = 1

select 1/0
from #temp2
where id = 1

이제 첫 번째 계획에는 상수 표현식 참조도 포함되어 있으며 두 쿼리 모두 오류 메시지를 생성합니다. 첫 번째 쿼리의 XML에는 다음이 포함됩니다.

추가 정보 : 계산 스칼라, 식 및 성능


답변

나는 지능적으로 추측 할 것입니다 (그리고 그 과정에서 아마도 실제로 자세한 답변을 줄 수있는 SQL Server 전문가를 끌어 들일 것입니다).

첫 번째 쿼리는 다음과 같이 실행에 접근합니다.

  1. 기본 키 인덱스 스캔
  2. 쿼리에 필요한 데이터 테이블에서 값을 찾으십시오.

where기본 키에 절이 있으므로이 경로를 선택합니다 . 두 번째 단계에 도달하지 않으므로 쿼리가 실패하지 않습니다.

두 번째는 실행할 기본 키가 없으므로 다음과 같이 쿼리에 접근합니다.

  1. 데이터의 전체 테이블 스캔을 수행하고 필요한 값을 검색하십시오.

이러한 값 중 하나가 1/0문제의 원인입니다.

쿼리를 최적화하는 SQL Server의 예입니다. 대부분의 경우 이것은 좋은 것입니다. SQL Server는에서 조건을 select테이블 스캔 작업으로 이동 합니다. 이것은 종종 쿼리 평가 단계를 저장합니다.

그러나이 최적화는 완화되지 않은 것이 아닙니다. 실제로이 절은 이전에 평가 된다는 SQL Server 설명서 자체 를 위반 한 것으로 보입니다 . 글쎄, 그들은 이것이 무엇을 의미하는지에 대한 설득력있는 설명을 가지고있을 것입니다. 그러나 대부분의 인간에게 논리적으로 이전을 처리하는 것은 “다른 것들과 함께” ” 사용자에게 반환되지 않은 행에서 -clause 오류를 생성하지 않음 “을 의미합니다.whereselectwhereselectselect


답변