Bug #69887 | about explain of update | ||
---|---|---|---|
Submitted: | 1 Aug 2013 2:58 | Modified: | 5 Aug 2013 16:03 |
Reporter: | kazushige uratani | Email Updates: | |
Status: | Verified | Impact on me: | |
Category: | MySQL Server: Optimizer | Severity: | S4 (Feature request) |
Version: | 5.6.12, 5.6.13 | OS: | Linux |
Assigned to: | CPU Architecture: | Any |
[1 Aug 2013 2:58]
kazushige uratani
[1 Aug 2013 6:11]
MySQL Verification Team
Hello! Thank you for the bug report. Verified as described on recent 5.6.13 version. Thanks, Umesh
[1 Aug 2013 6:16]
MySQL Verification Team
How to repeat: use test; DROP TABLE IF EXISTS `keyvalue`; CREATE TABLE `keyvalue` ( `id` smallint unsigned NOT NULL DEFAULT '0', `name` varchar(50) DEFAULT NULL, `cnt` smallint unsigned NOT NULL DEFAULT '0', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; set @id:=0; insert into `keyvalue` values (@id:=@id+1,md5(rand()*1000000),@id:=@id+1),(@id:=@id+1,md5(rand()*1000000),@id:=@id+1),(@id:=@id+1,md5(rand()*1000000),@id:=@id+1),(@id:=@id+1,md5(rand()*1000000),@id:=@id+1); insert into `keyvalue`(`id`,`name`,`cnt`) select @id:=@id+1,md5(rand()*1000000),@id:=@id+1 from `keyvalue` k1, `keyvalue` k2, `keyvalue` k3, `keyvalue` k4,`keyvalue` k5,`keyvalue` k6, `keyvalue` k7, `keyvalue` k8, `keyvalue` k9, `keyvalue` k0,`keyvalue` ka, `keyvalue` kb, `keyvalue` kc, `keyvalue` kd limit 10000; // EXPLAIN PLAN changes for SELECT and UPDATE /// 5.6.13 mysql> select version(); +------------+ | version() | +------------+ | 5.6.13-log | +------------+ 1 row in set (0.00 sec) mysql> explain select * from keyvalue where id = 1\G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: keyvalue type: const <-------------------- possible_keys: PRIMARY key: PRIMARY key_len: 2 ref: const rows: 1 Extra: NULL 1 row in set (0.02 sec) mysql> explain update keyvalue set cnt = 1 where id = 1\G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: keyvalue type: range <-------------------- possible_keys: PRIMARY key: PRIMARY key_len: 2 ref: const rows: 1 Extra: Using where 1 row in set (0.01 sec) Imho - "const" is used when you compare all parts of a PRIMARY KEY or UNIQUE index to constant values..
[2 Aug 2013 1:04]
kazushige uratani
Hi Umesh Thank you for your reply as soon as possible. I am looking forward that the bug is fixed Thanks, kazushige uratani
[2 Aug 2013 1:12]
kazushige uratani
Hi Umesh I confirm the following information. The optimizer trace could print ranges for key parts that were not usable for range access. (Bug #14615536) Thanks, kazushige uratani
[5 Aug 2013 1:23]
kazushige uratani
Hi Umesh How can you verify that it is correct then you will need to download the "mysql5.6.13", Had not been fixed. How do you think have been fixed in this "mysql5.6.13" bug, Is it not been fixed yet? kazushige uratani The following procedure will be mysql> \s -------------- /var/lib/mysql5613/bin/mysql Ver 14.14 Distrib 5.6.13, for Linux (x86_64) using EditLine wrapper Connection id: 7 Current database: sqa_knight Current user: root@localhost SSL: Not in use Current pager: stdout Using outfile: '' Using delimiter: ; Server version: 5.6.13 Source distribution Protocol version: 10 Connection: Localhost via UNIX socket Server characterset: utf8 Db characterset: utf8 Client characterset: utf8 Conn. characterset: utf8 UNIX socket: /var/lib/mysql5613/mysql5613.sock Uptime: 4 hours 52 min 36 sec Threads: 1 Questions: 4369 Slow queries: 0 Opens: 78 Flush tables: 1 Open tables: 71 Queries per second avg: 0.248 -------------- mysql> CREATE TABLE `tbl_sample` ( -> `id` smallint(5) unsigned NOT NULL DEFAULT '0', -> `name` varchar(30) DEFAULT NULL, -> `cnt` tinyint(3) unsigned NOT NULL DEFAULT '0', -> PRIMARY KEY (`id`) -> ) ENGINE=InnoDB DEFAULT CHARSET=utf8; Query OK, 0 rows affected (0.02 sec) mysql> desc tbl_sample; +-------+----------------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+----------------------+------+-----+---------+-------+ | id | smallint(5) unsigned | NO | PRI | 0 | | | name | varchar(30) | YES | | NULL | | | cnt | tinyint(3) unsigned | NO | | 0 | | +-------+----------------------+------+-----+---------+-------+ 3 rows in set (0.00 sec) mysql> show index from tbl_sample; +------------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ | Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | +------------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ | tbl_sample | 0 | PRIMARY | 1 | id | A | 0 | NULL | NULL | | BTREE | | | +------------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ 1 row in set (0.00 sec) mysql> explain update tbl_sample set cnt = 1 where id = 1\G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: tbl_sample type: range possible_keys: PRIMARY key: PRIMARY key_len: 2 ref: const rows: 1 Extra: Using where 1 row in set (0.00 sec)
[5 Aug 2013 1:40]
kazushige uratani
Hi Umesh Is additional information. If you look at the "SELECT" It becomes the "const" "type" is. mysql> explain select * from tbl_sample where id = 1\G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: tbl_sample type: const possible_keys: PRIMARY key: PRIMARY key_len: 2 ref: const rows: 1 Extra: NULL 1 row in set (0.00 sec) kazushige uratani
[5 Aug 2013 8:02]
Jørgen Løland
Thank you for the bug report. EXPLAIN is actually correct here - execution of the statement uses 'range' access, not 'ref' or 'const'. The reason is that single-table UPDATE/DELETE statements go through only a subset of the optimizations that SELECT and multi-table UPDATE/DELETE statements go through. One of the optimizations not performed is detection of 'const' tables in the case of constant equality predicates applied to unique indexes. MySQL has always behaved this way, it's just that it became more apparent now that EXPLAIN can handle UPDATE and DELETE statements. Fixing it is non-trivial, but we'll definitely keep it on the todo-list. I'm changing this bug report to feature request.
[5 Aug 2013 16:03]
kazushige uratani
Hi. If the current "update", I understand that "range" is correct. Thank you for your answers more quickly. kazushige uratani.
[10 Mar 2016 9:02]
Valeriy Kravchuk
There is an interesting case of the same bug with multiple-column index involved, like this: mysql> show create table tr\G *************************** 1. row *************************** Table: tr Create Table: CREATE TABLE `tr` ( `id` int(11) NOT NULL DEFAULT '0', `c1` int(11) DEFAULT NULL, `c2` int(11) DEFAULT NULL, `val` int(11) DEFAULT NULL, KEY `k` (`id`,`c1`,`c2`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 1 row in set (0.00 sec) mysql> explain select val from tr where id = 1 and c1 = 1 and c2 = 1; +----+-------------+-------+------+---------------+------+---------+------------ -------+------+-------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+------+---------------+------+---------+------------ -------+------+-------+ | 1 | SIMPLE | tr | ref | k | k | 14 | const,const ,const | 1 | NULL | +----+-------------+-------+------+---------------+------+---------+------------ -------+------+-------+ 1 row in set (0.00 sec) mysql> explain update tr set val=1 where id = 1 and c1 = 1 and c2 = 1; +----+-------------+-------+-------+---------------+------+---------+----------- --------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+-------+---------------+------+---------+----------- --------+------+-------------+ | 1 | SIMPLE | tr | range | k | k | 14 | const,cons t,const | 1 | Using where | +----+-------------+-------+-------+---------------+------+---------+----------- --------+------+-------------+ 1 row in set (0.01 sec) So, "ref' access for SELECT, but "range" access for UPDATE. Moreover, it seems in case of InnoDB table range access leads to extra row locked (like row with (1,1,2) locked when we ask for (1,1,1)).
[10 Mar 2016 12:41]
Valeriy Kravchuk
We have extra gap lock before the next key as a result: mysql> show create table tr\G *************************** 1. row *************************** Table: tr Create Table: CREATE TABLE `tr` ( `id` int(11) NOT NULL DEFAULT '0', `c1` int(11) DEFAULT NULL, `c2` int(11) DEFAULT NULL, `val` int(11) DEFAULT NULL, KEY `k` (`id`,`c1`,`c2`), KEY `k2` (`c2`,`id`,`c1`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 1 row in set (0.00 sec) mysql> alter table tr drop key k2; Query OK, 0 rows affected (0.02 sec) Records: 0 Duplicates: 0 Warnings: 0 mysql> start transaction; Query OK, 0 rows affected (0.00 sec) mysql> select * from tr; +----+------+------+------+ | id | c1 | c2 | val | +----+------+------+------+ | 1 | 1 | 1 | 0 | | 1 | 1 | 2 | 0 | | 1 | 1 | 3 | 0 | +----+------+------+------+ 3 rows in set (0.00 sec) mysql> update tr set val=1 where id = 1 and c1 = 1 and c2 = 1; Query OK, 1 row affected (0.00 sec) Rows matched: 1 Changed: 1 Warnings: 0 mysql> show engine innodb status\G ... ------------ TRANSACTIONS ------------ Trx id counter 163215 Purge done for trx's n:o < 163214 undo n:o < 0 state: running but idle History list length 72 LIST OF TRANSACTIONS FOR EACH SESSION: ---TRANSACTION 163206, not started MySQL thread id 4, OS thread handle 0xac0, query id 86 localhost 127.0.0.1 root cleaning up ---TRANSACTION 163214, ACTIVE 18 sec 4 lock struct(s), heap size 1184, 3 row lock(s), undo log entries 1 MySQL thread id 3, OS thread handle 0xbc4, query id 93 localhost 127.0.0.1 root init show engine innodb status Trx read view will not see trx with id >= 163215, sees < 163215 TABLE LOCK table `test`.`tr` trx id 163214 lock mode IX RECORD LOCKS space id 504 page no 4 n bits 72 index `k` of table `test`.`tr` trx id 163214 lock_mode X Record lock, heap no 2 PHYSICAL RECORD: n_fields 4; compact format; info bits 0 0: len 4; hex 80000001; asc ;; 1: len 4; hex 80000001; asc ;; 2: len 4; hex 80000001; asc ;; 3: len 6; hex 000000001000; asc ;; RECORD LOCKS space id 504 page no 3 n bits 72 index `GEN_CLUST_INDEX` of table ` test`.`tr` trx id 163214 lock_mode X locks rec but not gap Record lock, heap no 2 PHYSICAL RECORD: n_fields 7; compact format; info bits 0 0: len 6; hex 000000001000; asc ;; 1: len 6; hex 000000027d8e; asc } ;; 2: len 7; hex 7f000002660110; asc f ;; 3: len 4; hex 80000001; asc ;; 4: len 4; hex 80000001; asc ;; 5: len 4; hex 80000001; asc ;; 6: len 4; hex 80000001; asc ;; RECORD LOCKS space id 504 page no 4 n bits 72 index `k` of table `test`.`tr` trx id 163214 lock_mode X locks gap before rec Record lock, heap no 3 PHYSICAL RECORD: n_fields 4; compact format; info bits 0 0: len 4; hex 80000001; asc ;; 1: len 4; hex 80000001; asc ;; 2: len 4; hex 80000002; asc ;; 3: len 6; hex 000000001001; asc ;; ...
[11 Mar 2016 15:48]
Matthew Boehm
I discovered this issue myself yesterday on TokuDB, indicating, as noted above, this isn't engine specific and is an issue optimizing the query. Tacking this on for documentation: [PlatformDev]> explain UPDATE Cookies SET last_active = NULL WHERE id = 39161496; +------+-------------+---------+-------+---------------+---------+---------+------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +------+-------------+---------+-------+---------------+---------+---------+------+------+-------------+ | 1 | SIMPLE | Cookies | range | PRIMARY | PRIMARY | 4 | NULL | 1 | Using where | +------+-------------+---------+-------+---------------+---------+---------+------+------+-------------+ 1 row in set (0.07 sec) [PlatformDev]> SHOW CREATE TABLE `EmaticPlatformDev`.`Cookies`\G *************************** 1. row *************************** Table: Cookies Create Table: CREATE TABLE `Cookies` ( `id` int(11) NOT NULL AUTO_INCREMENT, `apikey_id` int(11) DEFAULT NULL, `uuid` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL, `email` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL, `last_active` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`), UNIQUE KEY `cookies_account_id_uuid` (`apikey_id`,`uuid`), KEY `cookies_email` (`email`) USING BTREE ) ENGINE=TokuDB AUTO_INCREMENT=39277383 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci 1 row in set (0.00 sec) [PlatformDev]> explain format=json UPDATE Cookies SET last_active = NULL WHERE id = 39161496; | EXPLAIN | { "query_block": { "select_id": 1, "table": { "update": 1, "table_name": "Cookies", "access_type": "range", "possible_keys": ["PRIMARY"], "key": "PRIMARY", "key_length": "4", "used_key_parts": ["id"], "rows": 1, "attached_condition": "(Cookies.`id` = 39161496)" } } }