Bug #74078 | join of large table to small table is slow if small table has less than 7 rows | ||
---|---|---|---|
Submitted: | 25 Sep 2014 16:15 | Modified: | 16 Oct 2014 19:49 |
Reporter: | Jeroen van den Hoed | Email Updates: | |
Status: | Verified | Impact on me: | |
Category: | MySQL Server: Optimizer | Severity: | S5 (Performance) |
Version: | 5.6.19/5.5/5.7 | OS: | Linux (Ubuntu 14) |
Assigned to: | CPU Architecture: | Any |
[25 Sep 2014 16:15]
Jeroen van den Hoed
[7 Oct 2014 21:49]
MySQL Verification Team
C:\dbs>c:\dbs\5.6\bin\mysql -uroot --port=3560 --debug-info --prompt="mysql 5.6 > " Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 1 Server version: 5.6.22 Source distribution Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql 5.6 > CREATE DATABASE h; Query OK, 1 row affected (0.01 sec) mysql 5.6 > use h Database changed mysql 5.6 > CREATE TABLE t1 (id int(11) NOT NULL AUTO_INCREMENT, name varchar(255) NOT NULL, t2_id int(11) NOT NULL, PRIMARY KEY (id)) ENGINE=InnoDB DEFAULT CHARSET=utf8; Query OK, 0 rows affected (0.27 sec) mysql 5.6 > CREATE TABLE t2 (id int(11) NOT NULL AUTO_INCREMENT, name varchar(255) NOT NULL, PRIMARY KEY (id)) ENGINE=InnoDB DEFAULT CHARSET=utf8; Query OK, 0 rows affected (0.23 sec) mysql 5.6 > INSERT INTO t2 (name) VALUES ('small table'); Query OK, 1 row affected (0.03 sec) mysql 5.6 > INSERT INTO t1 (name, t2_id) VALUES ('large table', 1); Query OK, 1 row affected (0.02 sec) mysql 5.6 > INSERT INTO t1 (name, t2_id) (SELECT name, t2_id FROM t1); Query OK, 1 row affected (0.02 sec) Records: 1 Duplicates: 0 Warnings: 0 mysql 5.6 > INSERT INTO t1 (name, t2_id) (SELECT name, t2_id FROM t1); Query OK, 2 rows affected (0.05 sec) Records: 2 Duplicates: 0 Warnings: 0 mysql 5.6 > INSERT INTO t1 (name, t2_id) (SELECT name, t2_id FROM t1); Query OK, 4 rows affected (0.03 sec) Records: 4 Duplicates: 0 Warnings: 0 mysql 5.6 > INSERT INTO t1 (name, t2_id) (SELECT name, t2_id FROM t1); Query OK, 8 rows affected (0.02 sec) Records: 8 Duplicates: 0 Warnings: 0 mysql 5.6 > INSERT INTO t1 (name, t2_id) (SELECT name, t2_id FROM t1); Query OK, 16 rows affected (0.03 sec) Records: 16 Duplicates: 0 Warnings: 0 mysql 5.6 > INSERT INTO t1 (name, t2_id) (SELECT name, t2_id FROM t1); Query OK, 32 rows affected (0.02 sec) Records: 32 Duplicates: 0 Warnings: 0 mysql 5.6 > INSERT INTO t1 (name, t2_id) (SELECT name, t2_id FROM t1); Query OK, 64 rows affected (0.06 sec) Records: 64 Duplicates: 0 Warnings: 0 mysql 5.6 > INSERT INTO t1 (name, t2_id) (SELECT name, t2_id FROM t1); Query OK, 128 rows affected (0.03 sec) Records: 128 Duplicates: 0 Warnings: 0 mysql 5.6 > INSERT INTO t1 (name, t2_id) (SELECT name, t2_id FROM t1); Query OK, 256 rows affected (0.06 sec) Records: 256 Duplicates: 0 Warnings: 0 mysql 5.6 > INSERT INTO t1 (name, t2_id) (SELECT name, t2_id FROM t1); Query OK, 512 rows affected (0.17 sec) Records: 512 Duplicates: 0 Warnings: 0 mysql 5.6 > INSERT INTO t1 (name, t2_id) (SELECT name, t2_id FROM t1); Query OK, 1024 rows affected (0.16 sec) Records: 1024 Duplicates: 0 Warnings: 0 mysql 5.6 > INSERT INTO t1 (name, t2_id) (SELECT name, t2_id FROM t1); Query OK, 2048 rows affected (0.23 sec) Records: 2048 Duplicates: 0 Warnings: 0 mysql 5.6 > INSERT INTO t1 (name, t2_id) (SELECT name, t2_id FROM t1); Query OK, 4096 rows affected (0.45 sec) Records: 4096 Duplicates: 0 Warnings: 0 mysql 5.6 > INSERT INTO t1 (name, t2_id) (SELECT name, t2_id FROM t1); Query OK, 8192 rows affected (0.91 sec) Records: 8192 Duplicates: 0 Warnings: 0 mysql 5.6 > INSERT INTO t1 (name, t2_id) (SELECT name, t2_id FROM t1); Query OK, 16384 rows affected (0.28 sec) Records: 16384 Duplicates: 0 Warnings: 0 mysql 5.6 > INSERT INTO t1 (name, t2_id) (SELECT name, t2_id FROM t1); Query OK, 32768 rows affected (0.80 sec) Records: 32768 Duplicates: 0 Warnings: 0 mysql 5.6 > INSERT INTO t1 (name, t2_id) (SELECT name, t2_id FROM t1); Query OK, 65536 rows affected (1.33 sec) Records: 65536 Duplicates: 0 Warnings: 0 mysql 5.6 > INSERT INTO t1 (name, t2_id) (SELECT name, t2_id FROM t1); Query OK, 131072 rows affected (2.33 sec) Records: 131072 Duplicates: 0 Warnings: 0 mysql 5.6 > SELECT t1.id, t1.name, t2.id, t2.name FROM t1, t2 WHERE t1.t2_id=t2.id ORDER BY t1.id LIMIT 0,10; +----+-------------+----+-------------+ | id | name | id | name | +----+-------------+----+-------------+ | 1 | large table | 1 | small table | | 2 | large table | 1 | small table | | 3 | large table | 1 | small table | | 4 | large table | 1 | small table | | 6 | large table | 1 | small table | | 7 | large table | 1 | small table | | 8 | large table | 1 | small table | | 9 | large table | 1 | small table | | 13 | large table | 1 | small table | | 14 | large table | 1 | small table | +----+-------------+----+-------------+ 10 rows in set (0.53 sec) mysql 5.6 > INSERT INTO t2 (name) VALUES ('small table'); Query OK, 1 row affected (0.03 sec) mysql 5.6 > INSERT INTO t2 (name) VALUES ('small table'); Query OK, 1 row affected (0.05 sec) mysql 5.6 > INSERT INTO t2 (name) VALUES ('small table'); Query OK, 1 row affected (0.05 sec) mysql 5.6 > INSERT INTO t2 (name) VALUES ('small table'); Query OK, 1 row affected (0.03 sec) mysql 5.6 > INSERT INTO t2 (name) VALUES ('small table'); Query OK, 1 row affected (0.05 sec) mysql 5.6 > INSERT INTO t2 (name) VALUES ('small table'); Query OK, 1 row affected (0.03 sec) mysql 5.6 > SELECT t1.id, t1.name, t2.id, t2.name FROM t1, t2 WHERE t1.t2_id=t2.id ORDER BY t1.id LIMIT 0,10; +----+-------------+----+-------------+ | id | name | id | name | +----+-------------+----+-------------+ | 1 | large table | 1 | small table | | 2 | large table | 1 | small table | | 3 | large table | 1 | small table | | 4 | large table | 1 | small table | | 6 | large table | 1 | small table | | 7 | large table | 1 | small table | | 8 | large table | 1 | small table | | 9 | large table | 1 | small table | | 13 | large table | 1 | small table | | 14 | large table | 1 | small table | +----+-------------+----+-------------+ 10 rows in set (0.00 sec)
[7 Oct 2014 22:01]
MySQL Verification Team
C:\dbs>c:\dbs\5.6\bin\mysql -uroot --port=3560 --debug-info --prompt="mysql 5.6 > " Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 1 Server version: 5.6.22 Source distribution Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql 5.6 > CREATE DATABASE q; Query OK, 1 row affected (0.00 sec) mysql 5.6 > USE q Database changed mysql 5.6 > CREATE TABLE t1 (id int(11) NOT NULL AUTO_INCREMENT, name varchar(255) NOT NULL, t2_id int(11) NOT NULL, PRIMARY KEY (id)) ENGINE=InnoDB DEFAULT CHARSET=utf8; Query OK, 0 rows affected (0.37 sec) mysql 5.6 > CREATE TABLE t2 (id int(11) NOT NULL AUTO_INCREMENT, name varchar(255) NOT NULL, PRIMARY KEY (id)) ENGINE=InnoDB DEFAULT CHARSET=utf8; Query OK, 0 rows affected (0.34 sec) mysql 5.6 > INSERT INTO t2 (name) VALUES ('small table'); Query OK, 1 row affected (0.04 sec) mysql 5.6 > INSERT INTO t2 (name) VALUES ('small table'); Query OK, 1 row affected (0.03 sec) mysql 5.6 > INSERT INTO t2 (name) VALUES ('small table'); Query OK, 1 row affected (0.03 sec) mysql 5.6 > INSERT INTO t2 (name) VALUES ('small table'); Query OK, 1 row affected (0.05 sec) mysql 5.6 > INSERT INTO t2 (name) VALUES ('small table'); Query OK, 1 row affected (0.03 sec) mysql 5.6 > INSERT INTO t2 (name) VALUES ('small table'); Query OK, 1 row affected (0.03 sec) mysql 5.6 > INSERT INTO t2 (name) VALUES ('small table'); Query OK, 1 row affected (0.03 sec) mysql 5.6 > INSERT INTO t1 (name, t2_id) VALUES ('large table', 1); Query OK, 1 row affected (0.03 sec) mysql 5.6 > INSERT INTO t1 (name, t2_id) (SELECT name, t2_id FROM t1); Query OK, 1 row affected (0.02 sec) Records: 1 Duplicates: 0 Warnings: 0 mysql 5.6 > INSERT INTO t1 (name, t2_id) (SELECT name, t2_id FROM t1); Query OK, 2 rows affected (0.08 sec) Records: 2 Duplicates: 0 Warnings: 0 mysql 5.6 > INSERT INTO t1 (name, t2_id) (SELECT name, t2_id FROM t1); Query OK, 4 rows affected (0.04 sec) Records: 4 Duplicates: 0 Warnings: 0 mysql 5.6 > INSERT INTO t1 (name, t2_id) (SELECT name, t2_id FROM t1); Query OK, 8 rows affected (0.03 sec) Records: 8 Duplicates: 0 Warnings: 0 mysql 5.6 > INSERT INTO t1 (name, t2_id) (SELECT name, t2_id FROM t1); Query OK, 16 rows affected (0.03 sec) Records: 16 Duplicates: 0 Warnings: 0 mysql 5.6 > INSERT INTO t1 (name, t2_id) (SELECT name, t2_id FROM t1); Query OK, 32 rows affected (0.02 sec) Records: 32 Duplicates: 0 Warnings: 0 mysql 5.6 > INSERT INTO t1 (name, t2_id) (SELECT name, t2_id FROM t1); Query OK, 64 rows affected (0.02 sec) Records: 64 Duplicates: 0 Warnings: 0 mysql 5.6 > INSERT INTO t1 (name, t2_id) (SELECT name, t2_id FROM t1); Query OK, 128 rows affected (0.04 sec) Records: 128 Duplicates: 0 Warnings: 0 mysql 5.6 > INSERT INTO t1 (name, t2_id) (SELECT name, t2_id FROM t1); Query OK, 256 rows affected (0.06 sec) Records: 256 Duplicates: 0 Warnings: 0 mysql 5.6 > INSERT INTO t1 (name, t2_id) (SELECT name, t2_id FROM t1); Query OK, 512 rows affected (0.15 sec) Records: 512 Duplicates: 0 Warnings: 0 mysql 5.6 > INSERT INTO t1 (name, t2_id) (SELECT name, t2_id FROM t1); Query OK, 1024 rows affected (0.13 sec) Records: 1024 Duplicates: 0 Warnings: 0 mysql 5.6 > INSERT INTO t1 (name, t2_id) (SELECT name, t2_id FROM t1); Query OK, 2048 rows affected (0.21 sec) Records: 2048 Duplicates: 0 Warnings: 0 mysql 5.6 > INSERT INTO t1 (name, t2_id) (SELECT name, t2_id FROM t1); Query OK, 4096 rows affected (0.37 sec) Records: 4096 Duplicates: 0 Warnings: 0 mysql 5.6 > INSERT INTO t1 (name, t2_id) (SELECT name, t2_id FROM t1); Query OK, 8192 rows affected (1.05 sec) Records: 8192 Duplicates: 0 Warnings: 0 mysql 5.6 > INSERT INTO t1 (name, t2_id) (SELECT name, t2_id FROM t1); Query OK, 16384 rows affected (0.25 sec) Records: 16384 Duplicates: 0 Warnings: 0 mysql 5.6 > INSERT INTO t1 (name, t2_id) (SELECT name, t2_id FROM t1); Query OK, 32768 rows affected (0.97 sec) Records: 32768 Duplicates: 0 Warnings: 0 mysql 5.6 > INSERT INTO t1 (name, t2_id) (SELECT name, t2_id FROM t1); Query OK, 65536 rows affected (1.15 sec) Records: 65536 Duplicates: 0 Warnings: 0 mysql 5.6 > INSERT INTO t1 (name, t2_id) (SELECT name, t2_id FROM t1); Query OK, 131072 rows affected (2.51 sec) Records: 131072 Duplicates: 0 Warnings: 0 mysql 5.6 > SELECT t1.id, t1.name, t2.id, t2.name FROM t1, t2 WHERE t1.t2_id=t2.id ORDER BY t1.id LIMIT 0,10; +----+-------------+----+-------------+ | id | name | id | name | +----+-------------+----+-------------+ | 1 | large table | 1 | small table | | 2 | large table | 1 | small table | | 3 | large table | 1 | small table | | 4 | large table | 1 | small table | | 6 | large table | 1 | small table | | 7 | large table | 1 | small table | | 8 | large table | 1 | small table | | 9 | large table | 1 | small table | | 13 | large table | 1 | small table | | 14 | large table | 1 | small table | +----+-------------+----+-------------+ 10 rows in set (0.00 sec) mysql 5.6 > delete from t2 where id >= 2; Query OK, 6 rows affected (0.02 sec) mysql 5.6 > SELECT t1.id, t1.name, t2.id, t2.name FROM t1, t2 WHERE t1.t2_id=t2.id ORDER BY t1.id LIMIT 0,10; +----+-------------+----+-------------+ | id | name | id | name | +----+-------------+----+-------------+ | 1 | large table | 1 | small table | | 2 | large table | 1 | small table | | 3 | large table | 1 | small table | | 4 | large table | 1 | small table | | 6 | large table | 1 | small table | | 7 | large table | 1 | small table | | 8 | large table | 1 | small table | | 9 | large table | 1 | small table | | 13 | large table | 1 | small table | | 14 | large table | 1 | small table | +----+-------------+----+-------------+ 10 rows in set (0.55 sec)
[7 Oct 2014 22:07]
MySQL Verification Team
Same behavior since 5.1: mysql 5.1 > SELECT t1.id, t1.name, t2.id, t2.name FROM t1, t2 WHERE t1.t2_id=t2.id ORDER BY t1.id LIMIT 0,10; +----+-------------+----+-------------+ | id | name | id | name | +----+-------------+----+-------------+ | 1 | large table | 1 | small table | | 2 | large table | 1 | small table | | 3 | large table | 1 | small table | | 4 | large table | 1 | small table | | 6 | large table | 1 | small table | | 7 | large table | 1 | small table | | 8 | large table | 1 | small table | | 9 | large table | 1 | small table | | 13 | large table | 1 | small table | | 14 | large table | 1 | small table | +----+-------------+----+-------------+ 10 rows in set (1.65 sec) mysql 5.1 > INSERT INTO t2 (name) VALUES ('small table'); Query OK, 1 row affected (0.05 sec) mysql 5.1 > INSERT INTO t2 (name) VALUES ('small table'); Query OK, 1 row affected (0.03 sec) mysql 5.1 > INSERT INTO t2 (name) VALUES ('small table'); Query OK, 1 row affected (0.03 sec) mysql 5.1 > INSERT INTO t2 (name) VALUES ('small table'); Query OK, 1 row affected (0.02 sec) mysql 5.1 > INSERT INTO t2 (name) VALUES ('small table'); Query OK, 1 row affected (0.01 sec) mysql 5.1 > INSERT INTO t2 (name) VALUES ('small table'); Query OK, 1 row affected (0.03 sec) mysql 5.1 > SELECT t1.id, t1.name, t2.id, t2.name FROM t1, t2 WHERE t1.t2_id=t2.id ORDER BY t1.id LIMIT 0,10; +----+-------------+----+-------------+ | id | name | id | name | +----+-------------+----+-------------+ | 1 | large table | 1 | small table | | 2 | large table | 1 | small table | | 3 | large table | 1 | small table | | 4 | large table | 1 | small table | | 6 | large table | 1 | small table | | 7 | large table | 1 | small table | | 8 | large table | 1 | small table | | 9 | large table | 1 | small table | | 13 | large table | 1 | small table | | 14 | large table | 1 | small table | +----+-------------+----+-------------+ 10 rows in set (0.01 sec) mysql 5.1 > SHOW VARIABLES LIKE "%VERSION%"; +-------------------------+---------------------+ | Variable_name | Value | +-------------------------+---------------------+ | protocol_version | 10 | | version | 5.1.74-Win X64 | | version_comment | Source distribution | | version_compile_machine | unknown | | version_compile_os | Win64 | +-------------------------+---------------------+ 5 rows in set (0.00 sec) Thank you for the bug report.
[8 Oct 2014 7:45]
Øystein Grøvlen
The reason the optimizer chooses a non-optimal plan is that it does not take into account that choosing join buffering will require sorting the entire result. A work-around is to turn of join buffering. In 5.6 you can do this with set optimizer_switch="block_nested_loop=off' In 5.5, I do not think there is any way to turn off join buffering, but you can use an optimizer hint to get the optimal plan: "... FROM t1 FORCE INDEX(PRIMARY), t2 ..."
[16 Oct 2014 19:49]
Jeroen van den Hoed
Hi Miguel & Øystein, thank you for your comments. I know I could use optimizer hints, but I do not like to put that kind of logic in my applications. I will look into block_nested_loop. Are there any negative consequences to turning this variable off? Could the behaviour of this choosen plan be changed in a coming version of mysql (without the use of hints and optimizer switches)? Thank you, Jeroen