복붙노트

[SQL] 어떤 SQL 쿼리가 빠르다? 필터에 대한 기준이나 Where 절을하세요?

SQL

어떤 SQL 쿼리가 빠르다? 필터에 대한 기준이나 Where 절을하세요?

이 2 개 개의 쿼리를 비교. 이 빨리 기준을 가입에 필터를 넣어 또는이었다 절에서하는 것입니다. 나는 항상 더 빨리는 조속한 가능한 순간에 결과 집합을 줄일 수 있기 때문에이 기준 가입에 있음을 느꼈다, 그러나 나는 확실히 모른다.

내가보고 몇 가지 검사를 구축하는거야,하지만 나는 또한 것뿐만 아니라 읽을 명확있는 의견을 얻고 싶었다.

쿼리 1

SELECT      *
FROM        TableA a
INNER JOIN  TableXRef x
        ON  a.ID = x.TableAID
INNER JOIN  TableB b
        ON  x.TableBID = b.ID
WHERE       a.ID = 1            /* <-- Filter here? */

쿼리 2

SELECT      *
FROM        TableA a
INNER JOIN  TableXRef x
        ON  a.ID = x.TableAID
        AND a.ID = 1            /* <-- Or filter here? */
INNER JOIN  TableB b
        ON  x.TableBID = b.ID

편집하다

나는 몇 가지 테스트를 실행하고 결과는 매우 가까운 사실이지만, WHERE 절은 약간 빠른 실제로 보여! =)

나는 절대적으로는 WHERE 절에 필터를 적용 더 많은 의미가 있음을 동의합니다, 나는 성능에 미치는 영향에 관해서는 그냥 궁금했다.

경과 시간 WHERE 기준 : 143,016 MS 경과 시간 기준 가입 : 143,256 밀리 초

테스트

SET NOCOUNT ON;

DECLARE @num    INT,
        @iter   INT

SELECT  @num    = 1000, -- Number of records in TableA and TableB, the cross table is populated with a CROSS JOIN from A to B
        @iter   = 1000  -- Number of select iterations to perform

DECLARE @a TABLE (
        id INT
)

DECLARE @b TABLE (
        id INT
)

DECLARE @x TABLE (
        aid INT,
        bid INT
)

DECLARE @num_curr INT
SELECT  @num_curr = 1

WHILE (@num_curr <= @num)
BEGIN
    INSERT @a (id) SELECT @num_curr
    INSERT @b (id) SELECT @num_curr

    SELECT @num_curr = @num_curr + 1
END

INSERT      @x (aid, bid)
SELECT      a.id,
            b.id
FROM        @a a
CROSS JOIN  @b b

/*
    TEST
*/
DECLARE @begin_where    DATETIME,
        @end_where      DATETIME,
        @count_where    INT,
        @begin_join     DATETIME,
        @end_join       DATETIME,
        @count_join     INT,
        @curr           INT,
        @aid            INT

DECLARE @temp TABLE (
        curr    INT,
        aid     INT,
        bid     INT
)

DELETE FROM @temp

SELECT  @curr   = 0,
        @aid    = 50

SELECT  @begin_where = CURRENT_TIMESTAMP
WHILE (@curr < @iter)
BEGIN
    INSERT      @temp (curr, aid, bid)
    SELECT      @curr,
                aid,
                bid
    FROM        @a a
    INNER JOIN  @x x
            ON  a.id = x.aid
    INNER JOIN  @b b
            ON  x.bid = b.id
    WHERE       a.id = @aid

    SELECT @curr = @curr + 1
END
SELECT  @end_where = CURRENT_TIMESTAMP

SELECT  @count_where = COUNT(1) FROM @temp
DELETE FROM @temp

SELECT  @curr = 0
SELECT  @begin_join = CURRENT_TIMESTAMP
WHILE (@curr < @iter)
BEGIN
    INSERT      @temp (curr, aid, bid)
    SELECT      @curr,
                aid,
                bid
    FROM        @a a
    INNER JOIN  @x x
            ON  a.id = x.aid
            AND a.id = @aid
    INNER JOIN  @b b
            ON  x.bid = b.id

    SELECT @curr = @curr + 1
END
SELECT  @end_join = CURRENT_TIMESTAMP

SELECT  @count_join = COUNT(1) FROM @temp
DELETE FROM @temp

SELECT  @count_where AS count_where,
        @count_join AS count_join,
        DATEDIFF(millisecond, @begin_where, @end_where) AS elapsed_where,
        DATEDIFF(millisecond, @begin_join, @end_join) AS elapsed_join

해결법

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

    1.성능 현명한, 그들은 동일 (같은 계획을 만들 수)

    성능 현명한, 그들은 동일 (같은 계획을 만들 수)

    논리적으로, 당신은 당신이 내부 조인 왼쪽으로 가입 교체 할 경우 여전히 감각이 작업을해야한다.

    당신의 아주 경우이 다음과 같이 표시됩니다

    SELECT  *
    FROM    TableA a
    LEFT JOIN
            TableXRef x
    ON      x.TableAID = a.ID
            AND a.ID = 1
    LEFT JOIN
            TableB b
    ON      x.TableBID = b.ID
    

    아니면 이거:

    SELECT  *
    FROM    TableA a
    LEFT JOIN
            TableXRef x
    ON      x.TableAID = a.ID
    LEFT JOIN
            TableB b
    ON      b.id = x.TableBID
    WHERE   a.id = 1
    

    이전 쿼리는 후자의 구문 때문에 논리적으로 일관성이다 (WHERE 포함), 1 이외의 a.id에 대한 실제 일치를 반환하지 않습니다.

  2. ==============================

    2.내부를 들어 당신이 당신의 기준을 어디다 그것은 중요하지 않습니다 합류했다. SQL 컴파일러는 필터링 조인 아래 발생하는 실행 계획으로 모두 변환 (즉. 조인 조건으로 필터 식에 표시되어있는 것처럼).

    내부를 들어 당신이 당신의 기준을 어디다 그것은 중요하지 않습니다 합류했다. SQL 컴파일러는 필터링 조인 아래 발생하는 실행 계획으로 모두 변환 (즉. 조인 조건으로 필터 식에 표시되어있는 것처럼).

    필터의 장소 쿼리의 의미를 변경하기 때문에 외부는 다른 문제입니다 합류했다.

  3. ==============================

    3.지금까지 두 가지 방법이가는대로.

    지금까지 두 가지 방법이가는대로.

    당신이 다르게 사용할 수있는 동안은 항상 나에게 냄새처럼 보인다.

    그것은이 문제가 될 때 성능 거래. 그럼 당신은 "최적화"로 볼 수있다.

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

    4.센트 어떤 쿼리 최적화로 .... 그들은 동일합니다.

    센트 어떤 쿼리 최적화로 .... 그들은 동일합니다.

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

    5.PostgreSQL의에서 그들은 동일합니다. 당신은 쿼리의 각 분석 설명 할 경우, 계획이 동일하게 나오는 때문에 우리는 이것을 알고있다. 이 예제를 보자

    PostgreSQL의에서 그들은 동일합니다. 당신은 쿼리의 각 분석 설명 할 경우, 계획이 동일하게 나오는 때문에 우리는 이것을 알고있다. 이 예제를 보자

    # explain analyze select e.* from event e join result r on e.id = r.event_id and r.team_2_score=24;
    
                                                      QUERY PLAN                                                   
    ---------------------------------------------------------------------------------------------------------------
     Hash Join  (cost=27.09..38.22 rows=7 width=899) (actual time=0.045..0.047 rows=1 loops=1)
       Hash Cond: (e.id = r.event_id)
       ->  Seq Scan on event e  (cost=0.00..10.80 rows=80 width=899) (actual time=0.009..0.010 rows=2 loops=1)
       ->  Hash  (cost=27.00..27.00 rows=7 width=8) (actual time=0.017..0.017 rows=1 loops=1)
             Buckets: 1024  Batches: 1  Memory Usage: 9kB
             ->  Seq Scan on result r  (cost=0.00..27.00 rows=7 width=8) (actual time=0.006..0.008 rows=1 loops=1)
                   Filter: (team_2_score = 24)
                   Rows Removed by Filter: 1
     Planning time: 0.182 ms
     Execution time: 0.101 ms
    (10 rows)
    
    # explain analyze select e.* from event e join result r on e.id = r.event_id where r.team_2_score=24;
                                                      QUERY PLAN                                                   
    ---------------------------------------------------------------------------------------------------------------
     Hash Join  (cost=27.09..38.22 rows=7 width=899) (actual time=0.027..0.029 rows=1 loops=1)
       Hash Cond: (e.id = r.event_id)
       ->  Seq Scan on event e  (cost=0.00..10.80 rows=80 width=899) (actual time=0.010..0.011 rows=2 loops=1)
       ->  Hash  (cost=27.00..27.00 rows=7 width=8) (actual time=0.010..0.010 rows=1 loops=1)
             Buckets: 1024  Batches: 1  Memory Usage: 9kB
             ->  Seq Scan on result r  (cost=0.00..27.00 rows=7 width=8) (actual time=0.006..0.007 rows=1 loops=1)
                   Filter: (team_2_score = 24)
                   Rows Removed by Filter: 1
     Planning time: 0.140 ms
     Execution time: 0.058 ms
    (10 rows)
    

    그들은 모두 동일한 최소 및 최대 비용뿐만 아니라 동일한 쿼리 계획을 가지고있다. 또한,도 상위 쿼리에 team_score_2가 '필터'로 적용됩니다 통지.

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

    6.이의 배치가 성능을 결정하는 요소가 될 것입니다 가입 정말 어렵다. 나는 TSQL에 대한 실행 계획을 속속들이 잘 알고 아니지만, 그것은 그들이 유사한 계획을 자동으로 최적화 될 가능성이 높습니다.

    이의 배치가 성능을 결정하는 요소가 될 것입니다 가입 정말 어렵다. 나는 TSQL에 대한 실행 계획을 속속들이 잘 알고 아니지만, 그것은 그들이 유사한 계획을 자동으로 최적화 될 가능성이 높습니다.

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

    7.실행을 몇 가지 벤치 마크를 볼 # 0 규칙! 정말 빠를 것이다 말할 수있는 유일한 방법은 그것을 시도하는 것입니다. 벤치 마크의 이러한 유형은 SQL 프로파일 러를 사용하여 수행하는 것은 매우 쉽습니다.

    실행을 몇 가지 벤치 마크를 볼 # 0 규칙! 정말 빠를 것이다 말할 수있는 유일한 방법은 그것을 시도하는 것입니다. 벤치 마크의 이러한 유형은 SQL 프로파일 러를 사용하여 수행하는 것은 매우 쉽습니다.

    또한,이 가입하기로하고 절은 차이가 눈에 띄는 것을 볼 수있는 WHERE 작성 쿼리에 대한 실행 계획을 검토한다.

    다른 사람이 말한 마지막으로,이 두 SQL 서버에 내장 된 것을 포함하여 어떤 점잖은 최적화 동일하게 취급되어야한다.

  8. ==============================

    8.더 빨리인가? 그것을 시도하고 참조하십시오.

    더 빨리인가? 그것을 시도하고 참조하십시오.

    어느 쉽게 읽을 수있다? 이동 된 상태가 조인과는 정말 아무것도 없기 때문에 나에게 첫 번째는, 더 "정확한"보인다.

  9. ==============================

    9.이 데이터를 통해보다 구체적인 필터를 만드는 때문에, 그 첫 번째 같아요. 그것은 등 데이터의 크기, 서버 하드웨어에 매우 다른 deppending을 할 수 있기 때문에 그러나 당신은 어떤 최적화로, 실행 계획을 볼 수

    이 데이터를 통해보다 구체적인 필터를 만드는 때문에, 그 첫 번째 같아요. 그것은 등 데이터의 크기, 서버 하드웨어에 매우 다른 deppending을 할 수 있기 때문에 그러나 당신은 어떤 최적화로, 실행 계획을 볼 수

  10. from https://stackoverflow.com/questions/2509987/which-sql-query-is-faster-filter-on-join-criteria-or-where-clause by cc-by-sa and MIT license