前一段时间修改数据表时,给一个表添加一个datetime字段,当时遇到了一个问题:我是否需要给该datetime字段上加索引呢?如果不给该字段加索引,当where语句中使用该字段时,会不会扫全表呢?如果给其加了索引,那么势必会带来一些开销,假如这个索引用不到的话,给其加了索引岂不是画蛇添足了呢?
为了弄清楚上述问题的原因,以及当where条件很多时,Mysql如何选择索引进行查找,查阅了Mysql官方文档第8章optimization的相关内容。
首先,想要知道你的一条复杂的SQL语句到底是如何执行的,第一步我们可以执行
show index from table_name
来查看你的表中都有哪些索引,例如:
+------------+------------+-------------------+--------------+----------------+-----------+-------------+----------+--------+------+------------+---------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment |
+------------+------------+-------------------+--------------+----------------+-----------+-------------+----------+--------+------+------------+---------+
| acct_order | 0 | PRIMARY | 1 | id | A | 2287 | NULL | NULL | | BTREE | |
| acct_order | 1 | game_id | 1 | game_id | A | 51 | NULL | NULL | | BTREE | |
| acct_order | 1 | user_id | 1 | user_id | A | 114 | NULL | NULL | YES | BTREE | |
| acct_order | 1 | game_work_id | 1 | game_work_id | A | 78 | NULL | NULL | | BTREE | |
| acct_order | 1 | weixin_user_id | 1 | weixin_user_id | A | 2 | NULL | NULL | YES | BTREE | |
+------------+------------+-------------------+--------------+----------------+-----------+-------------+----------+--------+------+------------+---------+
字段很多,其中比较重要的几个:
索引那么多,Mysql使用索引的目的是什么呢?
在了解了自己表结构以及索引结构之后,通常可以使用explain语句来查看Mysql的查询执行计划,例如下所示:
mysql> explain select * from acct_order where user_id=39 and weixin_user_id=61 and add_time > "2014-10-01";G;
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: acct_order
type: index_merge
possible_keys: user_id,weixin_user_id
key: weixin_user_id,user_id
key_len: 5,5
ref: NULL
rows: 4
Extra: Using intersect(weixin_user_id,user_id); Using where
explain的结果就是该次查询的执行计划,几个比较重要的字段为:
- SIMPLE(简单select查询,不包含union或子查询等)
- PRIMARY(主键查询)
- SUBQUERY
- UNION
- UNION RESULT
在执行查询语句时,Mysql对select语句进行了很多优化,例如:
这里不得不提的是range optimization和index merge Optimization,我在写SQL语句时,所用到的select语句大多数情况下,Mysql进行的都是这两种优化:
该种优化是基于三种算法来进行的:The Index Merge Intersection Access Algorithm、The Index Merge Union Access Algorithm以及The Index Merge Sort-Union Access Algorithm
首先我们说说 The Index Merge Intersection Access Algorithm,上述SQL语句的执行就是使用了该种算法,该算法执行的前提条件为:
例如:
SELECT * FROM innodb_table WHERE primary_key < 10 AND key_col1=20;
SELECT * FROM tbl_name WHERE (key1_part1=1 AND key1_part2=2) AND key2=2;
该算法操作流程如下:
那么针对我们上述SQL语句的案例,执行过程就是:
同理:The Index Merge Union Access Algorithm和Intersection相似,区别在于把AND条件换成了OR。
对于range optimization,TNT存储引擎大神总结过一篇blog
所有SQL的where条件均可归纳为3大类:
那么其实我们再回头来看之前那条SQL语句的执行时,已经很清晰的知道其进行查询时的一个大概过程:
因为我们的查询基本上都不是只有add_time一个条件,一般都会带有其他索引,所以这里我们不需要给add_time添加一个索引,当select语句中有该condition时,其作为table filter也不会对查询速度又什么影响。
不过具体问题具体分析,例如在某些场景下,例如:论坛中会存在查找某一个时间段的所有问题等场景,此时由于查询条件仅仅是add_time一个维度,显然给其加上索引能够大大加速查找。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。