a = 0 및 b = 0의 성능 및… z = 0 vs a + b + c + d = 0


20

이것은 대답을 찾을 수없는 간단한 질문입니다.

성능 측면에서 WHERE와 같은 조항 이있는 a=0 and b=0 and ... z=0경우 해당 조건을로 바꾸면 성능이 향상 a+b+...+z=0됩니까?

즉, 다음을 교체하여 성능이 향상 되었습니까?

Select * 
From MyTable 
Where A=0 and B=0 and C=0 and D=0...

Select * 
From MyTable 
Where A+B+C+D=0...

인덱스에 의존 할 수 있다는 것을 알고 있지만이 목적으로 인덱스가 없다고 가정 해 봅시다. 산술 연산자 (+)가 "OR"또는 "AND"논리 연산자보다 성능이 우수합니까?

AND 또는 OR이있는 여러 조건보다 추가가 더 잘 수행된다는 인상을 받고 있습니다.

시험 결과

420 만 행의 테이블에서

A = 0 B = 0 및 C = 0-> 351748 행인 경우 행 반환

덧셈 (A + B + C = 0)은 5 초가 걸리고 논리 조건 A = 0 및 B = 0 및 C = 0은 11 초가 걸렸습니다.

반면에

A <> 0 B <> 0 또는 C> 0-> 3829750 인 행 반환 58 초

F65 + F67 + f64 <> 0-> 3829750 행 57 초 행 반환

OR의 경우 큰 차이가없는 것 같습니다.

나는 gbn에 동의합니다.

A가 -1이고 B가 1이면 A + B = 0이지만 A = 0이고 B = 0은 거짓입니다.

그리고 AMtwo와 함께 :

ABS (A) + ABS (B) + ABS (C) + ABS (D) ... 양수 값만 예상하더라도 열에 음수 값이 허용되면 하나가 발생할 수 있다고 가정해야합니다.

내가 생각한 것처럼 결과는 매우 인상적입니다. 논리 연산자보다 추가가 훨씬 빠릅니다.

A = 플로트, B = 돈 및 C = 플로트. 사용 된 쿼리는 다음과 같습니다. 제 경우에는 모두 양수입니다. 색인이 없습니다. 논리적 조건보다 추가가 더 빠르다는 것은 제 생각에 논리적입니다!


이거 부울인가요? 4 (예) 또는 26 (제목)에 대해 몇 개의 열을 이야기하고 있습니까? 차이가 있습니다. 어떤 버전의 SQL Server입니까? FLOAT와 MONEY는 어디에서 사용됩니까? 우리는 몇 개의 행을 가정합니까? 이 질문에는 많은 요소가 있습니다.
Evan Carroll

@Evan Carroll 부울이 아니며 색인이없는 숫자 (int, float, money 등)입니다. SQL 버전 (SQL2012 이상), 행 또는 열 수에 관계없이 문제는 어떤 연산자가 논리 연산자와 산술 연산자보다 더 나은지 알아내는 것이 었습니다. 보시다시피 Max Vernon은 그의 예제를 통해 이론을 완벽하게 보여줍니다.
JohnG

답변:


46

귀하의 질문에, 추가 옵션이 이산 열을 비교하는 것보다 빠르다는 것을 "증명"할 수 있도록 준비한 일부 테스트에 대해 자세히 설명합니다. @gbn과 @srutzky가 암시 한 것처럼 테스트 방법이 여러 가지 방식으로 결함이 있다고 생각합니다.

먼저 SQL Server Management Studio (또는 사용중인 클라이언트)를 테스트하지 않아야합니다. 예를 들어 SELECT *3 백만 개의 행이있는 테이블에서 실행하는 경우 주로 SQL Server에서 행을 가져 와서 화면에 렌더링하는 SSMS 기능을 테스트하는 것입니다. SELECT COUNT(1)네트워크를 통해 수백만 행을 가져 와서 화면에 렌더링해야 할 필요성을 없애는 것과 같은 것을 사용하는 것이 훨씬 좋습니다 .

둘째, SQL Server의 데이터 캐시를 알고 있어야합니다. 일반적으로 스토리지에서 데이터를 읽고 콜드 캐시에서 데이터를 처리하는 속도를 테스트합니다 (예 : SQL Server의 버퍼가 비어 있음). 간혹 웜 캐시를 사용하여 모든 테스트를 수행하는 것이 합리적이지만이를 염두에두고 명시 적으로 테스트에 접근해야합니다.

감기 캐시 테스트를 위해, 당신은 실행해야 CHECKPOINT하고 DBCC DROPCLEANBUFFERS시험의 각 실행하기 전에.

귀하의 질문에 대해 귀하가 요청한 테스트를 위해 다음 테스트 베드를 만들었습니다.

IF COALESCE(OBJECT_ID('tempdb..#SomeTest'), 0) <> 0
BEGIN
    DROP TABLE #SomeTest;
END
CREATE TABLE #SomeTest
(
    TestID INT NOT NULL
        PRIMARY KEY 
        IDENTITY(1,1)
    , A INT NOT NULL
    , B FLOAT NOT NULL
    , C MONEY NOT NULL
    , D BIGINT NOT NULL
);

INSERT INTO #SomeTest (A, B, C, D)
SELECT o1.object_id, o2.object_id, o3.object_id, o4.object_id
FROM sys.objects o1
    , sys.objects o2
    , sys.objects o3
    , sys.objects o4;

SELECT COUNT(1) 
FROM #SomeTest;

내 컴퓨터에서 260,144,641의 수를 반환합니다.

"추가"방법을 테스트하기 위해 다음을 실행합니다.

CHECKPOINT 5;
DBCC FREEPROCCACHE;
DBCC DROPCLEANBUFFERS;

SET STATISTICS IO, TIME ON;
GO
SELECT COUNT(1)
FROM #SomeTest st
WHERE (st.A + st.B + st.C + st.D) = 0;
GO
SET STATISTICS IO, TIME OFF;

메시지 탭에 다음이 표시됩니다.

테이블 '#SomeTest'. 스캔 카운트 3, 논리적 읽기 1322661, 물리적 읽기 0, 미리 읽은 읽기 1313877, lob 논리적 읽기 0, lob 물리적 읽기 0, lob read-ahead read 0

SQL Server 실행 시간 : CPU 시간 = 49047ms, 경과 시간 = 173451ms

"이산 형 열"테스트의 경우 :

CHECKPOINT 5;
DBCC FREEPROCCACHE;
DBCC DROPCLEANBUFFERS;

SET STATISTICS IO, TIME ON;
GO
SELECT COUNT(1)
FROM #SomeTest st
WHERE st.A = 0
    AND st.B = 0
    AND st.C = 0
    AND st.D = 0;
GO

SET STATISTICS IO, TIME OFF;

메시지 탭에서 다시 :

테이블 '#SomeTest'. 스캔 횟수 3, 논리적 읽기 1322661, 물리적 읽기 0, 미리 읽기 읽기 1322661, lob 논리적 읽기 0, lob 물리적 읽기 0, lob read-ahead 읽기 0

SQL Server 실행 시간 : CPU 시간 = 8938ms, 경과 시간 = 162581ms

위의 통계에서 두 번째 변형을 볼 수 있습니다. 이산 열은 0과 비교되고 경과 시간은 약 10 초 짧으며 CPU 시간은 약 6 배 짧습니다. 위의 테스트에서 긴 시간은 대부분 디스크에서 많은 행을 읽은 결과입니다. 행 수를 3 백만으로 줄이면 디스크 I / O의 영향이 훨씬 적기 때문에 비율은 거의 동일하지만 경과 시간이 눈에 띄게 줄어드는 것을 볼 수 있습니다.

"추가"방법으로 :

테이블 '#SomeTest'. 스캔 횟수 3, 논리적 읽기 15255, 물리적 읽기 0, 미리 읽기 0, lob 논리적 읽기 0, lob 물리적 읽기 0, lob 미리 읽기 0

SQL Server 실행 시간 : CPU 시간 = 499ms, 경과 시간 = 256ms

"이산 열"방법으로 :

테이블 '#SomeTest'. 스캔 횟수 3, 논리적 읽기 15255, 물리적 읽기 0, 미리 읽기 0, lob 논리적 읽기 0, lob 물리적 읽기 0, lob 미리 읽기 0

SQL Server 실행 시간 : CPU 시간 = 94ms, 경과 시간 = 53ms

이 테스트에서 실제로 큰 차이를 만드는 것은 무엇입니까? 다음과 같은 적절한 색인 :

CREATE INDEX IX_SomeTest ON #SomeTest(A, B, C, D);

"추가"방법 :

테이블 '#SomeTest'. 스캔 카운트 3, 논리적 읽기 14235, 물리적 읽기 0, 미리 읽기 0, lob 논리적 읽기 0, lob 물리적 읽기 0, lob 미리 읽기 0.

SQL Server 실행 시간 : CPU 시간 = 546ms, 경과 시간 = 314ms

"이산 열"방법 :

테이블 '#SomeTest'. 스캔 횟수 1, 논리적 읽기 3, 물리적 읽기 0, 미리 읽기 0, lob 논리적 읽기 0, lob 물리적 읽기 0, lob 미리 읽기 0

SQL Server 실행 시간 : CPU 시간 = 0ms, 경과 시간 = 0ms

위의 인덱스를 사용하여 각 쿼리의 실행 계획이 상당히 좋습니다.

"추가"방법은 전체 색인의 스캔을 수행해야합니다.

여기에 이미지 설명을 입력하십시오

선행 인덱스 열 A이 0 인 인덱스의 첫 번째 행을 검색 할 수있는 "이산 열"방법 :

여기에 이미지 설명을 입력하십시오


24

A, B, C 및 D에 대한 색인이 있다고 가정합니다. 필터링 할 수도 있습니다.

이것은 인덱스를 더한 다음 사용할 가능성이 높습니다.

Where A=0 and B=0 and C=0 and D=0

다른 소식으로, A가 -1이고 B가 1 A+B=0이면 참이지만 A=0 and B=0거짓입니다.


7

(이 답변은 질문에 언급 된 테스트 전에 제출되었습니다. 질문의 텍스트는 테스트 결과 섹션 바로 위에서 끝났습니다 .)

AND옵티마이 저가 연산을 먼저 할 필요없이 하나의 값이 0 이 아닌 경우 연산을 단락시킬 가능성이 높기 때문에 별도의 조건이 바람직 하다고 생각합니다.

그러나 이는 성능 문제이므로 먼저 하드웨어 에 대한 답변을 결정하기위한 테스트를 설정 해야 합니다. 그 결과를보고하고, 테스트 코드를 보여주고, 다른 사람들이 그것을 테스트하여 좋은 테스트인지 확인하도록 요청하십시오. 고려하지 않은 다른 고려 사항이있을 수 있습니다.


3

어떤 일반적인 추론, 만약 당신이 어떤 인덱스를 가지고 있지 않다면 당신이 선택한 두 가지 솔루션 중 어느 것이 중요하지 않을 것이라고 생각합니다. 반면에 술어의 하나 이상의 컬럼에 대한 인덱스가 있으면 첫 번째 컬럼이 두 번째 컬럼보다 성능이 우수 할 것입니다. 두 번째 컬럼은 아마도 인덱스를 사용할 수 없기 때문입니다.

일반적으로 분리 (OR)는 연결 (AND)보다 성능이 좋지 않지만, 분리에 대한 쿼리가 있어도 첫 번째에 돈을 씁니다.


2

이것은 간단한 질문입니다

전혀 그렇지 않다. 이 (종류의) 질문은 많은 DBA 및 소프트웨어 개발자가 매일 매일 괴롭히는 문제이며 사소한 것이 아닙니다.

답을 찾지 못하는 것 같습니다.

그렇습니다. 최소한 일반적인 대답은 아닙니다. 우선, 사용중인 RDBMS에 크게 의존합니다 (OK, 사용 하지만 여전히). 한 버전의 RDBMS에서 다음 버전으로 갈 때 변경 될 수도 있습니다.

그런 다음 계획 옵티 마이저 등의 문제를 혼동하는 하위 선택 / 조인이있는 경우 DB가 데이터를 저장하는 방법과 같은 다른 많은 세부 정보에 의존 할 수 있습니다. 옵티마이 저는 사용자에게 다른 실행 계획을 제공 할 수 있습니다. 얼마나 많은 행이 있는지 ...

실제 테스트는 일반적으로 이와 같은 문제를 해결하는 유일한 유용한 방법입니다. 또한 이와 같은 "arcane"최적화를 통해 얻은 이익은 일반적으로 현명한 인덱스 선택으로 10 배나 높아 지므로 인덱스 사용이 실제로 배제되기 전에 너무 많은 시간을 소비하지 않을 것입니다.


0

이것은 분명있을 수 있지만, 열이있는 경우 INT, 다음 a+b+c경우 제로도 동일 할 수 아무도 그 중 실제로 제로 없습니다. 두 가지 다른 것을 테스트하고 있습니다!


@gbn이 그의 대답에서 이것을 언급했습니다.
Ross Presser
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.