복붙노트

[SQL] 왜 IN 조건은 SQL에서 "="보다 느린 것입니까?

SQL

왜 IN 조건은 SQL에서 "="보다 느린 것입니까?

이 SELECT 쿼리가 마무리 180 초 정도 걸립니다 질문을 확인 (질문 자체에 대한 의견을 확인). IN은 하나의 값과 비교 될 수 있지만, 여전히 시간 차이는 엄청나 다. 왜 그렇게입니까?

해결법

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

    1.요약 :이 MySQL의에서 알려진 문제와 MySQL의 5.6.x.에 고정 IN을 사용하여 하위 쿼리가 잘못 따라 하위 쿼리 대신 독립적 인 하위 쿼리로 indentified 때 문제로 인해 누락 최적화하는 것입니다.

    요약 :이 MySQL의에서 알려진 문제와 MySQL의 5.6.x.에 고정 IN을 사용하여 하위 쿼리가 잘못 따라 하위 쿼리 대신 독립적 인 하위 쿼리로 indentified 때 문제로 인해 누락 최적화하는 것입니다.

    원래 쿼리에 EXPLAIN 실행할 때이 반환합니다 :

    1  'PRIMARY'             'question_law_version'  'ALL'  ''  ''  ''  ''  10148  'Using where'
    2  'DEPENDENT SUBQUERY'  'question_law_version'  'ALL'  ''  ''  ''  ''  10148  'Using where'
    3  'DEPENDENT SUBQUERY'  'question_law'          'ALL'  ''  ''  ''  ''  10040  'Using where'
    

    당신이 투표를 변경 = 때 당신이 얻을 :

    1  'PRIMARY'   'question_law_version'  'ALL'  ''  ''  ''  ''  10148  'Using where'
    2  'SUBQUERY'  'question_law_version'  'ALL'  ''  ''  ''  ''  10148  'Using where'
    3  'SUBQUERY'  'question_law'          'ALL'  ''  ''  ''  ''  10040  'Using where'
    

    이에 포함 된 쿼리의 행에 한 번 서브 쿼리는 한 번만 실행되는 반면, 각 따라 하위 쿼리가 실행됩니다. MySQL을 할 수 때로는 최적화 따라 하위 쿼리 경우가 아니라 그 여기에 가입 변환 할 수 있지만 조건이있다.

    지금 이것은 물론 잎의 MySQL이 생각하는 이유의 문제는 IN 버전은 종속 서브 쿼리 할 필요가있다. 나는 도움에 쿼리의 단순화 된 버전이 조사를 만들었습니다. 나는 두 테이블 'foo는'와 (내가 외래 키 제약 조건을 생성하지 않았지만) 전자는 단지 id 컬럼을 포함하고, 후자는 ID와 푸 ID가 모두 포함 '줄'을 만들었습니다. 그럼 1000 개 행이 두 테이블을 채워 :

    CREATE TABLE foo (id INT PRIMARY KEY NOT NULL);
    CREATE TABLE bar (id INT PRIMARY KEY, foo_id INT NOT NULL);
    
    -- populate tables with 1000 rows in each
    
    SELECT id
    FROM foo
    WHERE id IN
    (
        SELECT MAX(foo_id)
        FROM bar
    );
    

    이 간단한 쿼리는 이전과 같은 문제가있다 - 내부 선택이 종속 하위 쿼리로 취급되고 더 최적화 행에 한 번 실행되도록 내부 쿼리를 일으키는 원인이 수행되지 않습니다. 쿼리를 실행하는 데 거의 1 초 걸립니다. =에 IN을 변경하면 다시 쿼리가 거의 즉시 실행할 수 있습니다.

    나는 테이블을 채우는 데 사용되는 코드는 경우에 사람이 결과를 재현하고자, 다음과 같습니다.

    CREATE TABLE filler (
            id INT NOT NULL PRIMARY KEY AUTO_INCREMENT
    ) ENGINE=Memory;
    
    DELIMITER $$
    
    CREATE PROCEDURE prc_filler(cnt INT)
    BEGIN
            DECLARE _cnt INT;
            SET _cnt = 1;
            WHILE _cnt <= cnt DO
                    INSERT
                    INTO    filler
                    SELECT  _cnt;
                    SET _cnt = _cnt + 1;
            END WHILE;
    END
    $$
    
    DELIMITER ;
    
    CALL prc_filler(1000);
    
    INSERT foo SELECT id FROM filler;
    INSERT bar SELECT id, id FROM filler;
    
  2. ==============================

    2.= 대 NOT IN에 대해, 조인 대 그것은 하위 쿼리 a.k.a 내부 쿼리에 관하여, 개미 이유는 해당 게시물에서 설명합니다. MySQL의 버전 5.4은보다 효율적인 형태로 일부 하위 쿼리를 다시 작성할 수 있습니다 향상된 최적화를 소개 suppposed된다.

    = 대 NOT IN에 대해, 조인 대 그것은 하위 쿼리 a.k.a 내부 쿼리에 관하여, 개미 이유는 해당 게시물에서 설명합니다. MySQL의 버전 5.4은보다 효율적인 형태로 일부 하위 쿼리를 다시 작성할 수 있습니다 향상된 최적화를 소개 suppposed된다.

    당신이 할 수있는 최악의 일은, 소위 상관 하위 쿼리를 사용하는 것입니다 http://dev.mysql.com/doc/refman/5.1/en/correlated-subqueries.html

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

    3.SQL 최적화는 항상 당신이 그 (것)들을 할 기대하지 않습니다. 나는 확실히 그보다 더 좋은 대답은 거기에 있지 않다. 당신이 계획 출력을 EXPLAIN 검토해야하고, 시간이 소요되는 곳을 찾기 위해 쿼리를 프로파일하는 이유입니다.

    SQL 최적화는 항상 당신이 그 (것)들을 할 기대하지 않습니다. 나는 확실히 그보다 더 좋은 대답은 거기에 있지 않다. 당신이 계획 출력을 EXPLAIN 검토해야하고, 시간이 소요되는 곳을 찾기 위해 쿼리를 프로파일하는 이유입니다.

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

    4.그것은 흥미로운하지만 문제는 준비된 문으로 해결 될 수있다 (확실하지가 모두 적합한 경우), 예컨대 :

    그것은 흥미로운하지만 문제는 준비된 문으로 해결 될 수있다 (확실하지가 모두 적합한 경우), 예컨대 :

    mysql> EXPLAIN SELECT * FROM words WHERE word IN (SELECT word FROM phrase_words);
    +----+--------------------+--------------+...
    | id | select_type        | table        |...
    +----+--------------------+--------------+...
    |  1 | PRIMARY            | words        |...
    |  2 | DEPENDENT SUBQUERY | phrase_words |...
    +----+--------------------+--------------+...
    mysql> EXPLAIN SELECT * FROM words WHERE word IN ('twist','rollers');
    +----+-------------+-------+...
    | id | select_type | table |...
    +----+-------------+-------+...
    |  1 | SIMPLE      | words |...
    +----+-------------+-------+...
    

    그러니 그냥 다음을 실행, 저장 프로 시저의 문을 준비합니다. 여기에 아이디어는 :

    SET @words = (SELECT GROUP_CONCAT(word SEPARATOR '\',\'') FROM phrase_words);
    SET @words = CONCAT("'", @words, "'");
    SET @query = CONCAT("SELECT * FROM words WHERE word IN (", @words, ");";
    PREPARE q FROM @query;
    EXECUTE q;
    
  5. from https://stackoverflow.com/questions/3417074/why-would-an-in-condition-be-slower-than-in-sql by cc-by-sa and MIT license