Mysql
 sql >> база данни >  >> RDS >> Mysql

Защо условието IN би било по-бавно от =в sql?

Резюме:Това е известен проблем в MySQL и беше фиксиран в MySQL 5.6.x. Проблемът се дължи на липсваща оптимизация, когато подзаявка, използваща IN, е неправилно идентифицирана като зависима подзаявка вместо независима подзаявка.

Когато стартирате 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'

Когато промените IN до = получавате това:

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' и 'bar', където първата съдържа само колона id, а втората съдържа както идентификатор, така и foo 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
);

Тази опростена заявка има същия проблем като преди - вътрешният избор се третира като зависима подзаявка и не се извършва оптимизация, което кара вътрешната заявка да се изпълнява веднъж на ред. Изпълнението на заявката отнема почти една секунда. Промяна на 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;


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Използване на mysql concat() в клауза WHERE?

  2. Как да получите всеки N-ти ред в MySQL

  3. Как да инсталирате MySQL на Debian 7

  4. Не мога да използвам MySQL връзка за структура на обект 6

  5. Как да конвертирате малки букви в главни в MySQL