복붙노트

[SQL] SQL 서버 조건부 흐름

SQL

SQL 서버 조건부 흐름

나는 IF 두 SELECT 문 심지어 첫 번째 SELECT false를 반환하는 경우 두 쿼리가 실행됩니까, 이러한 선택 쿼리 사이에 AND 절 조건을 EXISTS 작성하는 경우?

IF EXISTS (SELECT....) AND EXISTS(SELECT ....)
BEGIN

END

은 SQL Server 엔진은 모두이 시나리오에서 SQL 문 실행합니까?

감사 Krish 수출

해결법

  1. ==============================

    1.나뿐만 테스트를 다시 것

    나뿐만 테스트를 다시 것

    IF CASE
         WHEN EXISTS (SELECT ...) THEN CASE
                                       WHEN EXISTS (SELECT ...) THEN 1
                                     END
       END = 1  
    

    여기에 설명하지만 의미 않는 한 단락이 보장 당신은 옵티마이에 그것을 떠나보다 앞 오히려 위로 평가하기에 가장 저렴한 하나를 선택해야합니다.

    테스트 할 때 다음 아래에있는 내 매우 제한 테스트에서 성립 듯

    가 존재하는 버전이 가장 문제가 보인다 존재한다. 이 체인 함께 일부 외부 반 조인. 사건의 아무도에서는 (이 블로그 게시물의 후반에서 논의 된 문제를) 시도하고 첫 번째 싼를 할 수있는 테스트의 순서를 재 배열했다. 그것이 단락하지 않았다으로 한 경우 IF ... 버전은 어떤 차이를 만들어 않았을 것이다. 이 결합 조건은 WHERE 절 계획의 변경에 넣고는 그 재 배열이 도움이되었습니다 수 있도록 단락을 수행한다 그러나 때.

    /*All tests are testing "If False And False"*/
    
    IF EXISTS(SELECT COUNT(*) FROM master..spt_monitor HAVING COUNT(*)=2)  
    AND EXISTS (SELECT COUNT(*) FROM master..spt_values HAVING COUNT(*)=1)
    PRINT 'Y'
    /*
    Table 'spt_values'. Scan count 1, logical reads 9
    Table 'spt_monitor'. Scan count 1, logical reads 1
    */
    
    IF EXISTS (SELECT COUNT(*) FROM master..spt_values HAVING COUNT(*)=1) 
    AND EXISTS(SELECT COUNT(*) FROM master..spt_monitor HAVING COUNT(*)=2) 
    PRINT 'Y'
    /*
    Table 'spt_monitor'. Scan count 1, logical reads 1
    Table 'spt_values'. Scan count 1, logical reads 9
    */
    
    SELECT 1
    WHERE  EXISTS(SELECT COUNT(*) FROM master..spt_monitor HAVING COUNT(*)=2)  
    AND EXISTS (SELECT COUNT(*) FROM master..spt_values HAVING COUNT(*)=1)
    /*
    Table 'Worktable'. Scan count 0, logical reads 0
    Table 'spt_monitor'. Scan count 1, logical reads 1
    */
    
    SELECT 1
    WHERE  EXISTS (SELECT COUNT(*) FROM master..spt_values HAVING COUNT(*)=1) 
    AND EXISTS(SELECT COUNT(*) FROM master..spt_monitor HAVING COUNT(*)=2) 
    /*
    Table 'Worktable'. Scan count 0, logical reads 0
    Table 'spt_values'. Scan count 1, logical reads 9
    
    */
    

    모든 이들의 계획은 매우 유사하게 나타납니다. 은 SELECT 1 WHERE ... 버전과 IF 사이에 동작의 차이에 대한 이유는 ... 버전은 이전의 하나의 조건이 다음 올바른 행동이 그것을 단지 체인 외부 SEMI 그래서 어떤 결과를 반환하지 않는 것입니다 false 인 경우이다 조인과 하나가 거짓이라면 제로 행은 다음 단계로 이월.

    그러나 IF 버전은 항상 1 또는 0의 결과를 반환 할 필요가있다. 그 외부 결합하고이 테스트 (단순히 폐기 행 이하) 전달되지 있으면 false로 설정이 계획은 프로브 열을 이용한다. 1 개 행 먹이 다음 가입하고 항상 실행됩니다에 항상 있다는 것을이 의미합니다.

    케이스 버전은 매우 비슷한 계획을 가지고 있지만 그것은 이전 THEN 조건이 충족되지 않은 경우 조인의 실행을 건너 뛸 사용하는 경유 술어를 사용합니다. 나는 결합 AND 연산이 같은 방법을 사용하지 않을 이유를 모르겠어요.

    는 OR 버전은 외부 결합 세미 이너 입력으로서 연결 (UNION ALL) 연산자를 사용 EXISTS 존재한다. 첫 번째가 반환되면 즉시 내측에서 행 요청을 중지 할 수있는 이러한 배열 수단 (즉, 그 수 효과적으로 단락) 모든 4 개 쿼리 저렴 선언문이 먼저 계산 된 동일한 계획을 끝냈다.

    /*All tests are testing "If True Or True"*/
    
    IF EXISTS(SELECT COUNT(*) FROM master..spt_monitor HAVING COUNT(*)=1)  
    OR EXISTS (SELECT COUNT(*) FROM master..spt_values HAVING COUNT(*)<>1)
    PRINT 'Y'
    /*
    Table 'Worktable'. Scan count 0, logical reads 0
    Table 'spt_monitor'. Scan count 1, logical reads 1
    */
    
    IF EXISTS (SELECT COUNT(*) FROM master..spt_values HAVING COUNT(*)<>1) 
    OR EXISTS(SELECT COUNT(*) FROM master..spt_monitor HAVING COUNT(*)= 1) 
    PRINT 'Y'
    /*
    Table 'Worktable'. Scan count 0, logical reads 0
    Table 'spt_monitor'. Scan count 1, logical reads 1
    */
    
    SELECT 1
    WHERE  EXISTS(SELECT COUNT(*) FROM master..spt_monitor HAVING COUNT(*)= 1)  
    OR EXISTS (SELECT COUNT(*) FROM master..spt_values HAVING COUNT(*)<>1)
    /*
    Table 'Worktable'. Scan count 0, logical reads 0
    Table 'spt_monitor'. Scan count 1, logical reads 1
    */
    
    SELECT 1
    WHERE  EXISTS (SELECT COUNT(*) FROM master..spt_values HAVING COUNT(*)<>1) 
    OR EXISTS(SELECT COUNT(*) FROM master..spt_monitor HAVING COUNT(*)=1) 
    /*
    Table 'Worktable'. Scan count 0, logical reads 0
    Table 'spt_monitor'. Scan count 1, logical reads 1
    */
    

    변환에 AND OR에 드 모건의 법칙을 시도하고 그 차이를 만든 있는지 확인하기 위해 나에게 발생했습니다. 첫 번째 쿼리가 제공 변환

    IF NOT ((NOT EXISTS(SELECT COUNT(*) FROM master..spt_monitor HAVING COUNT(*)=2)  
    OR NOT EXISTS (SELECT COUNT(*) FROM master..spt_values HAVING COUNT(*)=1)))
    PRINT 'Y'
    ELSE
    PRINT 'N'
    /*
    Table 'spt_monitor'. Scan count 1, logical reads 1
    Table 'spt_values'. Scan count 1, logical reads 9
    */
    

    이 그래서 여전히 단락의 행동에 어떤 차이가되지 않습니다. 당신이 NOT을 제거하고는 IF의 순서 ... ELSE 조건을 역 그러나 경우에 지금 단락한다!

    IF (NOT EXISTS(SELECT COUNT(*) FROM master..spt_monitor HAVING COUNT(*)=2)  
    OR NOT EXISTS (SELECT COUNT(*) FROM master..spt_values HAVING COUNT(*)=1))
    PRINT 'N'
    ELSE
    PRINT 'Y'
    /*
    Table 'Worktable'. Scan count 0, logical reads 0
    Table 'spt_monitor'. Scan count 1, logical reads 1
    */
    
  2. ==============================

    2.난 당신이 대부분의 IF 문장의 단락 행동에 모든 경우에, 현대 언어에 의존 수 있다고 생각합니다. 먼저 진정한 조건을 넣고과 같이, 단락이 발생하지 않는 경우 제로 오류에 의해 당신에게 나누어 줄 것이다 1/0로 두 번째 조건을 교체하여 테스트를 시도 할 수 있습니다 :

    난 당신이 대부분의 IF 문장의 단락 행동에 모든 경우에, 현대 언어에 의존 수 있다고 생각합니다. 먼저 진정한 조건을 넣고과 같이, 단락이 발생하지 않는 경우 제로 오류에 의해 당신에게 나누어 줄 것이다 1/0로 두 번째 조건을 교체하여 테스트를 시도 할 수 있습니다 :

    IF 1>0 OR 1/0 BEGIN
      PRINT 'Short Circuited'
    END
    

    당신이 신뢰하지 않는 경우, 당신은 항상 이렇게 쿼리를 다시 작성할 수 있습니다 :

    IF EXISTS(SELECT...) BEGIN
      IF EXISTS(SELECT...) BEGIN
        ...
      END
    END
    
  3. ==============================

    3.내가와 함께 쿼리를 실행하면, 그렇다하더라도, 두 테이블은 액세스 할 수 있습니다

    내가와 함께 쿼리를 실행하면, 그렇다하더라도, 두 테이블은 액세스 할 수 있습니다

    SET STATISTICS IO ON IF 존재 (master..spt_values ​​선택 * 여기서 [이름] = 'rpcc')과 EXISTS (master..spt_monitor 선택 * 여기서 pack_sent = 5,235,252) PRINT 'Y'

    테이블 'spt_monitor'. 1 카운트 스캔 논리 1을 판독하고, 실제는 0 판독, 미리 읽기 0 논리 로브가 0 판독 로브 물리적 0, LOB 앞서 읽을 0을 판독 판독 읽는다. 테이블 'spt_values'. 1 카운트 스캔 논리 17 판독 물리적 0을 판독하고, 미리 읽기 0 논리 로브가 0 판독 로브 물리적 0, LOB 앞서 읽을 0을 판독 판독 읽는다.

  4. ==============================

    4.나는 sqlteam에서 다음 블로그 항목에서 다음 따옴표를 복용하고 있습니다 :

    나는 sqlteam에서 다음 블로그 항목에서 다음 따옴표를 복용하고 있습니다 :

    어떻게 SQL Server가 단락 WHERE 조건 평가

    더 자세한 내용은 다른 블로그에 선도 위의 블로그 항목에서 첫 번째 링크를 확인 :

    SQL 서버 단락 회로합니까?

  5. ==============================

    5.흥미로운 관찰을했다. 나는 두 개의 테이블 TBLA 및 tblb 있습니다. TBLA는 tblb 내의 외부 키로서 사용되는 기본 키 (idvalue)을 갖는다. 모두 idvalue = 1 행 있지만 -1 idvalue 아니 행을 갖는다. 이제 쿼리 사용 아래 하나 개의 테이블

    흥미로운 관찰을했다. 나는 두 개의 테이블 TBLA 및 tblb 있습니다. TBLA는 tblb 내의 외부 키로서 사용되는 기본 키 (idvalue)을 갖는다. 모두 idvalue = 1 행 있지만 -1 idvalue 아니 행을 갖는다. 이제 쿼리 사용 아래 하나 개의 테이블

    select 1
    where exists
    (select 1 from tbla where idvalue = -1)
    and exists (select 1 from tblb where idvalue= 1)
    

    부여

    Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
    Table 'tbla'. Scan count 0, logical reads 3, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
    

    최적화가 기본 키 - 외래 키 관계가 있기 때문에 값이 TBLA에없는 경우, 그래서, 그것은 tblb에 존재하지 않을 수 있다는 것을 알고 있기 때문에이 분명하다. 그래서, 최적화가 필요하지 않습니다 tblb에 추구 런타임에 결정합니다.

    그러나, 나는 쿼리 등을 작성하는 경우

    select 1
    where exists
    (select 1 from tbla where idvalue = 1)
    and exists (select 1 from tblb where idvalue= -1)
    

    다음 두 테이블은 액세스 할 수 있습니다. 옵티마이이 확인 AND 조건이 만족되는 것으로 두 곳에서 확인하는 것을 알고 여기에 있기 때문에 이것은 매우 분명하다.

    그러나 두 경우에, 실제 실행 계획 쇼 TBLA와 tblb 모두 추구한다. 이것은 나에게 이상한 것 같다. 이것에 대한 어떤 생각?

  6. ==============================

    6.아니.

    아니.

    난 그냥 SQL 서버 2008에서 테스트 첫 번째 평가가 실패 할 경우 즉시 IF 블록을 건너 뜁니다.

    이 테스트에 매우 쉽습니다.

    첫 번째 평가를 위해 다음 실제 간부 계획을 보여 1 = 0이 두 번째 할 일을 아무것도 그런 짓을. 광산에서 그것은 단지 상수 스캔은 그 상수를 평가 후면 않습니다.

  7. ==============================

    7.이 작업을 수행하여 두 번째 스캔을 방지 할 수 있습니다 :

    이 작업을 수행하여 두 번째 스캔을 방지 할 수 있습니다 :

    declare @test bit
    select @test = case when exists(select 1...) then 1 else 0 end
    if @test = 1
    begin
        --1st test passed
        select @test = case when exists(select 2...) then 1 else 0 end
    end
    if @test = 1
    begin
        print 'both exists passed'
    end
    
  8. from https://stackoverflow.com/questions/5542927/sql-server-conditional-flow by cc-by-sa and MIT license