Mysql添加索引后的效果
时间:2014-03-06 07:03:48 作者:beebol 标签: 索引 rbo 分类: Mysql
最近线上数据库更新,就是删除一些记录,901条删除语句,每一条删除语句都关联了三个表,act_id_membership,apollo_erp_workerinfo ,apollo_erp_post。删除的语句如下:
DELETE a from act_id_membership a,apollo_erp_workerinfo b,apollo_erp_post c where a.GROUP_ID_=c.post_No and a.USER_ID_=b.workerinfo_No and c.post_type='job' and b.out_email='www@www.com';
问题来了,检查更新语句没有问题后,备份完毕后,直接执行了。回车一敲,就发现悲剧了。等了好几分钟还没有执行完毕。
由于执行了,没有办法只好等,最后完成花了30多分钟。(当时是在线删除数据的,库的数据量不是很大,在线备份在线操作)。
今天有空了,把更新之前的备份导入到了虚拟机,然后进行测试,检查索引。如下都是在虚拟机上操作:
重新恢复数据库到虚拟机,然后执行一条delete语句分析,结果如下:
Mysqladmin pr查看:
[root@Server3 update]# mysqladmin pr +----+------+-----------+----------+---------+------+--------------+------------------------------------------------------------------------------------------------------+ | Id | User | Host | db | Command | Time | State | Info | +----+------+-----------+----------+---------+------+--------------+------------------------------------------------------------------------------------------------------+ | 12 | root | localhost | apollodb | Query | 42 | Sending data | DELETE a from act_id_membership a,apollo_erp_workerinfo b,apollo_erp_post c where a.GROUP_ID_=c.post | | 30 | root | localhost | | Query | 0 | | show processlist |+----+------+-----------+----------+---------+------+--------------+----------------- +----+------+-----------+----------+---------+------+--------------+-----------------
这么简单的一条delete执行还这么慢,time都到42了,然后再看看slow日志:
Time Id Command Argument # Time: 140129 4:44:25 # User@Host: root[root] @ localhost [] # Query_time: 48.716238 Lock_time: 0.010976 Rows_sent: 0 Rows_examined: 48244969 use apollodb; SET timestamp=1390941865;DELETE a from act_id_membership a,apollo_erp_workerinfo b,apollo_erp_post c where a.GROUP_ID_=c.post_No and a.USER_ID_=b.workerinfo_No and c.post_type='job' and b.out_email=' www@www.com '; DELETE a from act_id_membership a,apollo_erp_workerinfo b,apollo_erp_post c where a.GROUP_ID_=c.post_No and a.USER_ID_=b.workerinfo_No and c.post_type='job' and b.out_email=' www@www.com ';
正常情况下,这个删除应该很快,为什么这么慢呢?因为out_email=' www@www.com '查询出来就一条记录,再到三个表中查询那不是很快吗?是吧。开始检查调用的各表中的字段是否都有了索引。
[root@localhost:Wed Jan 29 05:04:12 2014 {apollodb}]>show indexes from act_id_membership; +-------------------+------------+-------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ | Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | +-------------------+------------+-------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ | act_id_membership | 0 | PRIMARY | 1 | USER_ID_ | A | 7420 | NULL | NULL | | BTREE | | | | act_id_membership | 0 | PRIMARY | 2 | GROUP_ID_ | A | 7420 | NULL | NULL | | BTREE | | | | act_id_membership | 1 | ACT_FK_MEMB_GROUP | 1 | GROUP_ID_ | A | 7420 | NULL | NULL | | BTREE | | | +-------------------+------------+-------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ 3 rows in set (0.02 sec) [root@localhost:Wed Jan 29 05:14:13 2014 {apollodb}]>show indexes from apollo_erp_workerinfo; +-----------------------+------------+----------------------+--------------+---------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ | Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | +-----------------------+------------+----------------------+--------------+---------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ | apollo_erp_workerinfo | 0 | PRIMARY | 1 | workerinfo_id | A | 7397 | NULL | NULL | | BTREE | | | | apollo_erp_workerinfo | 0 | workerinfo_No_unique | 1 | workerinfo_No | A | 7397 | NULL | NULL | | BTREE | | | +-----------------------+------------+----------------------+--------------+---------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ 2 rows in set (0.01 sec) [root@localhost:Wed Jan 29 05:14:23 2014 {apollodb}]>show indexes from apollo_erp_post; +-----------------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ | Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | +-----------------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ | apollo_erp_post | 0 | PRIMARY | 1 | post_id | A | 2809 | NULL | NULL | | BTREE | | | | apollo_erp_post | 1 | post_no | 1 | post_No | A | 187 | NULL | NULL | YES | BTREE | | | +-----------------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+2 rows in set (0.00 sec) 2 rows in set (0.00 sec)
刚开始还没有注意到,后面仔细一看问题出来了。其它的些字段有了索引,如GROUPID、post_No、USERID、workerinfo_No。唯有最重新的一个字段没有添加索引apollo_erp_workerinfo 的out_email。
再看看这个表的数据行数:
[root@localhost:Wed Jan 29 05:14:32 2014 {apollodb}]>select count(*) from apollo_erp_workerinfo; +----------+ | count(*) | +----------+ | 7344 | +----------+1 row in set (0.00 sec) 1 row in set (0.00 sec)
虽然只有7344,但由于没有索引,每次查询都进行了全表扫描:
[root@localhost:Wed Jan 29 05:19:43 2014 {apollodb}]>explain select workerinfo_No from apollo_erp_workerinfo where out_email=' www@www.com '\G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: apollo_erp_workerinfo type: ALL possible_keys: NULL key: NULL key_len: NULL ref: NULL rows: 7397 Extra: Using where1 row in set (0.00 sec) 1 row in set (0.00 sec)
为out_email添加个索引。
[root@localhost:Wed Jan 29 04:46:23 2014 {apollodb}]>create index out_email_index on apollo_erp_workerinfo(`out_email`); Query OK, 0 rows affected (0.12 sec)Records: 0 Duplicates: 0 Warnings: 0 Records: 0 Duplicates: 0 Warnings: 0
然后再分析这条语句,走索引了,直接拿取数据,速度不是吹的。
[root@localhost:Wed Jan 29 04:47:00 2014 {apollodb}]>explain select workerinfo_No from apollo_erp_workerinfo where out_email=' www@www.com '\G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: apollo_erp_workerinfo type: ref possible_keys: out_email_index key: out_email_index key_len: 97 ref: const rows: 1 Extra: Using where1 row in set (0.00 sec) 1 row in set (0.00 sec)
从rows: 7397变成rows: 1,然后再试试删除语句:
[root@localhost:Wed Jan 29 04:47:07 2014 {apollodb}]>DELETE a from act_id_membership a,apollo_erp_workerinfo b,apollo_erp_post c where a.GROUP_ID_=c.post_No and a.USER_ID_=b.workerinfo_No and c.post_type='job' and b.out_email=' www22@www.com ';Query OK, 1 row affected (0.01 sec) Query OK, 1 row affected (0.01 sec)
最后以不到4秒的速度把901条数据删除:
[root@Server3 update]# time mysql -f apollodb <lxy-2.sql real 0m3.945s user 0m0.006ssys 0m0.084s sys 0m0.084s
果断瞬间秒杀。
总结:
把out_email放到最后面是对的,没有加索引就是悲剧的,mysql的sql的where条件解析顺序是从右到左开始的,最好把小的结果集发到最右边。注意mysql只有rbo,没有cbo哦。