SQL WHERE 절이 단락 되었습니까?


142

SQL WHERE 절의 부울 표현식 이 단락 평가 됩니까?

예를 들면 다음과 같습니다.

SELECT * 
FROM Table t 
WHERE @key IS NULL OR (@key IS NOT NULL AND @key = t.Key) 

@key IS NULL 이 true로 평가 되면 @key IS NOT NULL AND @key = t. 키가 평가됩니까?

아니라면 왜 안됩니까?

그렇다면, 보장됩니까? ANSI SQL의 일부입니까, 아니면 데이터베이스 특정입니까?

데이터베이스에 특정한 경우 SqlServer? 신탁? MySQL?


@key는 NULL이 아닙니까? LHS의 @key IS NULL 절이 이것을 처리합니까?
April

10
@ splender-질문에 대한 답변에 따라 다릅니다
Greg Dean

@ 그렉 : 나는 지출에 동의합니다. 나는 단락의 부족이 존재하는 것을 보지 못한다. @key가 NULL이면 @key = t.Key는 항상 NULL! = NULL과 같이 항상 false를 반환합니다 (그래서 우리는 결국 IS NULL을 사용합니다).
Michael Madsen

14
@Michael and @spender-문제의 요점은 두 번째 조건이 평가되는지 여부입니다. 문제의 요지는 아닙니다. 가능한 한 적은 문자로 작성된이 특정 SQL 문입니다. 더 복잡한 예제에서는 where 절이 단락되는 것처럼 의심의 여지가 없지만, 그렇지 않으면 잘못된 표현식을 작성할 수 있습니다.
Greg Dean

2
단락은 왼쪽에서 오른쪽으로 조건을 평가 함을 의미합니다. WHERE a = 1 AND b = 2데이터베이스 엔진이 b = 2 인 모든 행을 먼저 찾은 다음 a = 1을 필터링하는 것이 효율적일 수 있는 조건이 주어지면 보증을 요청하면 옵티마이 저가 쓸모 없게됩니다.
Salman A

답변:


72

ANSI SQL Draft 2003 5WD-01- 프레임 워크 -2003-09.pdf

6.3.3.3 규칙 평가 순서

[...]

우선 순위가 형식이나 괄호로 결정되지 않은 경우, 효과적인 표현 평가는 일반적으로 왼쪽에서 오른쪽으로 수행됩니다. 그러나 표현식이 실제로 왼쪽에서 오른쪽으로 평가되는지 여부, 특히 피연산자 또는 연산자가 조건을 발생시킬 수 있거나 표현식의 모든 부분을 완전히 평가하지 않고 표현식의 결과를 결정할 수있는 경우 구현에 따라 다릅니다 .


4
구현에 따라 다릅니 까? 큰. 알아두면 좋습니다. 적어도 CASE단락되었습니다.
dakab

3
이것이 표현식 평가가 잘못 정의되었음을 의미하지 않습니까? "(0 = 0 OR NULL)"은 모든 항이 평가되는 경우 항상 NULL이지만 왼쪽에서 오른쪽으로 단락 된 경우 항상 참입니다.
user48956

7
SQL은 선언적 언어이며 기본적으로 제어 흐름을 설명하지 않고 계산 논리를 표현합니다. 단락 평가의 필수 스타일과 그 결과와 모순되는 유형.
Jorge Garcia

나는 그렇게 생각하지 않았다 @JorgeGarcia. 단락 평가는 암시 적으로 작업 순서를 강제한다고 생각합니다. 미묘한 문제의 근본 원인이되는 코드로 씨름하고 있습니다. 통찰력에 감사드립니다.
Carnot Antonio Romero

58

위의 단락은 실제로 사용할 수 없습니다.

필요한 경우 Case 문을 제안합니다.

Where Case when Expr1 then Expr2 else Expr3 end = desiredResult

Expr1항상 평가하지만 중 하나입니다 Expr2Expr3행마다 평가됩니다.


3
그것은 내가 생각하는 RDBMS의 구현에 달려 있습니다. SQL Server의 경우 최소한이 동작을 나타내지 않는 것으로 문서화 된 예외가 하나 이상 있습니다 (예 : 단락). cf CASE (Transact-SQL)-설명 . 나는이 경우 인용 이 답변 내가 질문에 준 WHERE 조건을 명시 적으로 순서 - SQL을? .
TT.

1
문이 아닌 대소 문자 표현 .
jarlh

19

나는 이것이 세 가지 이유로 단락되지 않은 것처럼 작성하는 경우 중 하나라고 생각합니다.

  1. MSSQL의 경우 명확한 위치에서 BOL을 살펴 보아도 해결되지 않으므로 정식으로 모호합니다.

  2. 적어도 내 코드가 작동한다는 것을 알고 있기 때문입니다. 그리고 더 중요한 것은, 나를 따르는 사람들도 마찬가지입니다. 그래서 나는 같은 질문을 반복해서 반복하도록 걱정하지 않습니다.

  3. 여러 DBMS 제품에 대해 자주 글을 쓰며 쉽게 해결할 수 있다면 차이점을 기억하고 싶지 않습니다.


4
좋은 제안. 그것은 질문에 대한 답은 아니지만 훌륭한 실용적 관점입니다. so +1
Greg Dean

12

SQL Server (2005)의 단락이 보장되는 것은 아닙니다. SQL Server는 효과적인 실행 계획을 세우기 위해 많은 것들 (인덱스, 통계, 테이블 크기, 리소스 등)을 고려한 최적화 알고리즘을 통해 쿼리를 실행합니다. 이 평가 후에는 단락 논리가 보장된다고 확신 할 수 없습니다.

나는 얼마 전에 같은 질문을 겪었고 나의 연구는 실제로 결정적인 대답을주지 못했다. 작은 쿼리를 작성하면 작동한다는 증거를 얻을 수 있지만 데이터베이스의로드가 증가함에 따라 테이블이 커지고 데이터베이스에서 상황이 최적화되고 변경된다는 결론을 얻을 수 있습니다. 보류. 나는주의를 기울일 수 없었고 단락을 보장하기 위해 WHERE 절에서 CASE를 사용했습니다.


7

데이터베이스 작동 방식을 명심해야합니다. 매개 변수화 된 쿼리가 주어지면 db는 매개 변수 값없이 해당 쿼리를 기반으로 실행 계획을 작성합니다. 이 쿼리는 실제 제공된 값에 관계없이 쿼리가 실행될 때마다 사용됩니다. 쿼리가 특정 값으로 단락되는지 여부는 실행 계획에 중요하지 않습니다.


6
실행 속도에 중요합니다!
user4951

그것이 현재 작동하는 방식이기 때문에 변경할 수 없다는 의미는 아닙니다. 모델 / 의미론을 구현과 분리해야합니다. 실행 계획은 쿼리 실행을 최적화하기 위해 내부적으로 구현되며 단락 시맨틱은 SQL의 선언적 특성과 모순 될뿐만 아니라 이러한 최적화를 제한 할 수 있습니다. 그러나 단락 평가 의미론이 DBMS에 의해 지원된다면, 실행 계획의 구현은 그러한 의미론을 지원하도록 변경 될 것이다.
Jorge Garcia

3

나는 일반적으로 이것을 선택적 매개 변수에 사용합니다. 단락과 동일합니까?

SELECT  [blah]
FROM    Emp
WHERE  ((@EmpID = -1) OR (@EmpID = EmpID))

이것은 나에게 -1을 전달하거나 옵션의 속성 검사를 설명 할 수있는 옵션을 제공합니다. 때로는 여러 테이블 또는 바람직하게는 뷰를 조인하는 것이 포함됩니다.

DB 엔진에 제공하는 추가 작업을 완전히 확신하지 못하는 매우 편리합니다.


2

SQL Server의 경우 버전에 따라 다르다고 생각하지만 SQL Server 2000에 대한 나의 경험은 @key가 null 인 경우에도 여전히 @key = t를 평가한다는 것입니다. 즉, WHERE 절을 평가할 때 효율적인 단락을 수행하지 않습니다.

사용자가 다양한 기준을 입력하거나 입력 할 수없는 유연한 쿼리를 수행하는 방법으로 예제와 같은 구조를 추천하는 사람들을 보았습니다. 내 관찰은 @key가 null 일 때 Key가 쿼리 계획에 여전히 관여하고 Key가 색인화되면 색인을 효율적으로 사용하지 않는다는 것입니다.

다양한 기준을 가진 이런 종류의 유연한 쿼리는 동적으로 생성 된 SQL이 실제로 가장 좋은 방법 일 수 있습니다. @key가 null이면 쿼리에 전혀 포함시키지 않습니다.


2

방금이 질문에 걸려서 이미 다음 블로그 항목을 발견했습니다 : http://rusanu.com/2009/09/13/on-sql-server-boolean-operator-short-circuit/

SQL 서버는 원하는 곳 어디에서나 쿼리를 자유롭게 최적화 할 수 있으므로 블로그 게시물에 제공된 예에서는 단락에 의존 할 수 없습니다.

그러나 CASE는 서면 순서대로 평가하기 위해 문서화되어 있습니다. 해당 블로그 게시물의 의견을 확인하십시오.


1

단락 평가의 주요 특징은 결과가 결정 되 자마자 식 평가 평가를 중단한다는 것입니다. 즉, 평가 여부에 관계없이 결과가 동일하므로 나머지 표현식을 무시할 수 있습니다.

이진 부울 연산자는 계산적이며 다음을 의미합니다.

a AND b == b AND a
a OR  b == b OR  a
a XOR b == b XOR a

따라서 평가 순서에 대한 보장은 없습니다. 평가 순서는 쿼리 최적화 프로그램에 의해 결정됩니다.

객체가있는 언어에서는 단락 평가만으로 평가할 수있는 부울 표현식을 작성할 수있는 상황이있을 수 있습니다. 샘플 코드 구성은 종종 이러한 언어 (C #, Delphi, VB)로 사용됩니다. 예를 들면 다음과 같습니다.

if(someString == null | someString.Length == 0 )
  printf("no text in someString");

이 C # 예제는 someString == null완전히 평가되므로 예외가 발생 합니다. 단락 평가에서는 매번 작동합니다.

SQL은 초기화 할 수없는 스칼라 변수 (객체 없음)에서만 작동하므로 평가할 수없는 부울 표현식을 작성할 방법이 없습니다. NULL 값이 있으면 비교시 false가 반환됩니다.

즉, SQL에서는 단락 또는 전체 평가 사용에 따라 다르게 평가되는 표현식을 작성할 수 없습니다.

SQL 구현에서 단락 평가를 사용하면 쿼리 실행 속도가 빨라질 수 있습니다.


1
그러나 부울 연산자는 교환 형입니다. 나는 물건과 관련이 없다고 생각합니다.
Greg Dean

1

나는 짧은 순환에 대해 모른다.하지만 if-else 문으로 쓰겠 다.

if (@key is null)
begin

     SELECT * 
     FROM Table t 

end
else
begin

     SELECT * 
     FROM Table t 
     WHERE t.Key=@key

end

또한 변수는 항상 방정식의 오른쪽에 있어야합니다. 이것은 처칠 수 있습니다.

http://en.wikipedia.org/wiki/Sargable


1
누구나 오른쪽의 변수에 대해 그것을 확증 할 수 있습니까? 어떤 이유로 나는 그것을 믿기가 힘들다.
Greg Dean

searchoracle.techtarget.com/expert/KnowledgebaseAnswer/… 다른 많은 것을 지금 찾을 수 없습니다
DForck42

기사를 이해하면 열 이름의 함수가 Sargable이 아닌 것에 대해 이야기하고 있습니다. 이해합니다. 그러나 (A = @a) 또는 (@a = A)가 중요하다고 생각하지 않습니다.
Greg Dean

내가 틀렸을지도 모른다. 아직 존재하지 않는 경우 좋은 질문이 될 수 있습니다.
DForck42

1

SQL Server 2008 R2에 대한 빠르고 더러운 테스트는 다음과 같습니다.

SELECT *
FROM table
WHERE 1=0
AND (function call to complex operation)

레코드없이 즉시 반환됩니다. 단락 동작이 발생했습니다.

그런 다음 이것을 시도하십시오 :

SELECT *
FROM table
WHERE (a field from table) < 0
AND (function call to complex operation)

레코드가 없다는 것을 알면이 조건을 충족시킬 수 있습니다.

(a field from table) < 0

이 작업에는 몇 초가 걸렸으며 단락 동작이 더 이상없고 복잡한 작업이 모든 레코드에 대해 평가되고 있음을 나타냅니다.

이것이 도움이되기를 바랍니다.


1
내 생각에 첫 번째 쿼리는 계획 실행이 실제로 시작되기 전에 컴파일 시간에 "단락"되었다는 것입니다.
루이 소머

1

다음은 MySQL이 WHERE 절 단락을 수행함 을 증명하는 데모입니다 .

http://rextester.com/GVE4880

다음과 같은 쿼리가 실행됩니다.

SELECT myint FROM mytable WHERE myint >= 3 OR myslowfunction('query #1', myint) = 1;
SELECT myint FROM mytable WHERE myslowfunction('query #2', myint) = 1 OR myint >= 3;

이들 간의 유일한 차이점은 OR 조건에서 피연산자의 순서입니다.

myslowfunction의도적으로 1 초 동안 휴면 상태가 될 때마다 로그 테이블에 항목을 추가하면 부작용이 발생합니다. 위 두 쿼리를 실행할 때 기록 된 결과는 다음과 같습니다.

myslowfunction called for query #1 with value 1
myslowfunction called for query #1 with value 2
myslowfunction called for query #2 with value 1
myslowfunction called for query #2 with value 2
myslowfunction called for query #2 with value 3
myslowfunction called for query #2 with value 4

위의 내용은 다른 피연산자가 항상 참이 아닌 (단락으로 인해) OR 조건의 왼쪽에 나타날 때 느린 기능이 더 많이 실행됨을 보여줍니다.


4
흠 당신이 아마 말을 의미 "여기하는 것은 MySQL이 수행 않음을 증명하는 데모가 WHERE 절 단락 이 특정 인스턴스에서 "
TT.

1
물론-그것이 일어날 수 있다는 증거 일뿐입니다.
Steve Chambers

0

쿼리 분석기에서 추가로 4 초가 걸리므로 IF에서 확인할 수있는 것까지도 부족합니다 ...

SET @ADate = NULL

IF (@ADate IS NOT NULL)
BEGIN
    INSERT INTO #ABla VALUES (1)
        (SELECT bla from a huge view)
END

보장 된 방법을 갖는 것이 좋을 것입니다!


-2

MS Sql 서버가 단락 이론을 지원하여 불필요한 검사를 피함으로써 성능을 향상시키는 것은 분명하지만,

지원 예 :

SELECT 'TEST'
WHERE 1 = 'A'

SELECT 'TEST'
WHERE 1 = 1 OR 1 = 'A'

여기서 첫 번째 예는 'varchar 값'A '를 데이터 유형 int로 변환 할 때 변환에 실패했습니다.'라는 오류가 발생합니다.

조건 1 = 1이 TRUE로 평가되어 두 번째 조건이 전혀 실행되지 않으므로 두 번째는 쉽게 실행됩니다.

SELECT 'TEST'
WHERE 1 = 0 OR 1 = 'A'

여기서 첫 번째 조건은 false로 평가되므로 DBMS는 두 번째 조건으로 가고 다시 위의 예와 같이 변환 오류가 발생합니다.

참고 : 오류가 발생한 쿼리 결과가 조건을 실행하고 단축 된 다른 방법을 의미하는 경우 조건이 실행되거나 단축 된 오류를 재조정하기 위해 잘못된 조건을 작성했습니다.

간단한 설명

치다,

WHERE 1 = 1 OR 2 = 2

첫 번째 조건이 TRUE 로 평가됨에 따라 어떤 값 으로든 평가가 결과에 전혀 영향을 미치지 않기 때문에 두 번째 조건을 평가하는 것은 의미가 없으므로 Sql 서버가 불필요한 조건 확인 또는 평가를 생략하여 쿼리 실행 시간을 절약 할 수있는 좋은 기회 .

경우 "OR" 첫째 조건으로 평가되면 TRUE 로 연결된 전체 체인 "OR" 다른 평가 않고 참으로 평가로 간주한다.

condition1 OR condition2 OR ..... OR conditionN

condition1이 true로 평가되면 conditionN을 건너 뛸 때까지 모든 조건을 유지하십시오. 첫 번째 TRUE 결정시 일반화 된 단어에서 OR로 연결된 다른 모든 조건은 건너 뜁니다.

두 번째 조건을 고려하십시오

WHERE 1 = 0 AND 1 = 1

첫 번째 조건이 FALSE 로 평가됨에 따라 두 번째 조건을 평가하는 것은 의미가 없으므로 어떤 값으로도 결과에 영향을 미치지 않으므로 Sql 서버가 불필요한 조건 확인 또는 평가를 건너 뛰어 쿼리 실행 시간을 절약 할 수있는 좋은 기회 .

있는 경우는 "AND" 제 조건에 따라 평가되는 경우 FALSE 접속 전체 체인 "AND" 다른 평가없이 FALSE로 평가를 고려 것이다.

condition1 AND condition2 AND ..... conditionN

조건 1가에 평가되는 경우 FALSE ,까지 모든 조건 휴식 conditionN을 생략 할 것이다. 첫 번째 거짓 을 결정할 때 일반화 된 단어에서 AND로 연결된 다른 모든 조건 은 건너 뜁니다.

현명한 프로그래머 인 THEREFOR는 항상 비용이 많이 들거나 가장 적은 양의 조명 조건을 평가하거나 짧은 회로의 최대 이익을 얻을 수있는 방법으로 조건을 설정하는 방식으로 항상 조건의 체인을 프로그램해야합니다.


공감대 이유 : 항상 실제 데이터를 사용하여 실제 서버에서 사물을 테스트하십시오. 내 이전 의견을 먹은 것 같습니다.
재스민
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.