不少时候,咱们在mysql中建立了索引,可是某些查询仍是很慢,根本就没有使用到索引!html
通常来讲,多是某些字段没有建立索引,或者是组合索引中字段的顺序与查询语句中字段的顺序不符。mysql
看下面的例子:sql
假设有一张订单表(orders),包含order_id和product_id二个字段。性能
一共有31条数据。符合下面语句的数据有5条。优化
执行下面的sql语句:ui
select product_id spa
from ordershtm
where order_id in (123, 312, 223, 132, 224);blog
这条语句要mysql去根据order_id进行搜索,而后返回匹配记录中的product_id。索引
因此组合索引应该按照如下的顺序建立:
create index orderid_productid on orders(order_id, product_id)
mysql> explain select product_id from orders where order_id in (123, 312, 223, 132, 224) \G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: orders
type: range
possible_keys: orderid_productid
key: orderid_productid
key_len: 5
ref: NULL
rows: 5
Extra: Using where; Using index
1 row in set (0.00 sec)
能够看到,这个组合索引被用到了,扫描的范围也很小,只有5行。
若是把组合索引的顺序换成product_id, order_id的话,
mysql就会去索引中搜索 *123 *312 *223 *132 *224,必然会有些慢了。
mysql> create index orderid_productid on orders(product_id, order_id);
Query OK, 31 rows affected (0.01 sec)
Records: 31 Duplicates: 0 Warnings: 0
mysql> explain select product_id from orders where order_id in (123, 312, 223, 132, 224) \G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: orders
type: index
possible_keys: NULL
key: orderid_productid
key_len: 10
ref: NULL
rows: 31
Extra: Using where; Using index
1 row in set (0.00 sec)
此次索引搜索的性能显然不能和上次相比了。
rows:31,个人表中一共就31条数据。
索引被使用部分的长度:key_len:10,比上一次的key_len:5多了一倍。
不知道是这样在索引里面查找速度快,仍是直接去全表扫描更快呢?
mysql> alter table orders add modify_a char(255) default 'aaa';
Query OK, 31 rows affected (0.01 sec)
Records: 31 Duplicates: 0 Warnings: 0
mysql>
mysql>
mysql> explain select modify_a from orders where order_id in (123, 312, 223, 132, 224) \G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: orders
type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 31
Extra: Using where
1 row in set (0.00 sec)
这样就不会用到索引了。 刚才是由于select的product_id与where中的order_id都在索引里面的。
为何要建立组合索引呢?这么简单的状况直接建立一个order_id的索引不就好了吗?
若是只有一个order_id索引,没什么问题,会用到这个索引,而后mysql要去磁盘上的表里面取到product_id。
若是有组合索引的话,mysql能够彻底从索引中取到product_id,速度天然会快。
再多说几句组合索引的最左优先原则:
组合索引的第一个字段必须出如今查询组句中,这个索引才会被用到。
若是有一个组合索引(col_a,col_b,col_c)
下面的状况都会用到这个索引:
col_a = "some value";
col_a = "some value" and col_b = "some value";
col_a = "some value" and col_b = "some value" and col_c = "some value";
col_b = "some value" and col_a = "some value" and col_c = "some value";
对于最后一条语句,mysql会自动优化成第三条的样子~~。
下面的状况就不会用到索引:
col_b = "aaaaaa";
col_b = "aaaa" and col_c = "cccccc";
下列转自:http://hi.baidu.com/liuzhiqun/blog/item/4957bcb1aed1b5590823023c.html
经过实例理解单列索引、多列索引以及最左前缀原则
实例:如今咱们想查出知足如下条件的用户id:
mysql>SELECT `uid` FROM people WHERE lname`='Liu' AND `fname`='Zhiqun' AND `age`=26
由于咱们不想扫描整表,故考虑用索引。
单列索引:
ALTER TABLE people ADD INDEX lname (lname);
将lname列建索引,这样就把范围限制在lname='Liu'的结果集1上,以后扫描结果集1,产生知足fname='Zhiqun'的结果集2,再扫描结果集2,找到 age=26的结果集3,即最终结果。
由 于创建了lname列的索引,与执行表的彻底扫描相比,效率提升了不少,但咱们要求扫描的记录数量仍旧远远超过了实际所需 要的。虽然咱们能够删除lname列上的索引,再建立fname或者age 列的索引,可是,不论在哪一个列上建立索引搜索效率仍旧类似。
2.多列索引:
ALTER TABLE people ADD INDEX lname_fname_age (lame,fname,age);
为了提升搜索效率,咱们须要考虑运用多列索引,因为索引文件以B-Tree格式保存,因此咱们不用扫描任何记录,便可获得最终结果。
注:在mysql中执行查询时,只能使用一个索引,若是咱们在lname,fname,age上分别建索引,执行查询时,只能使用一个索引,mysql会选择一个最严格(得到结果集记录数最少)的索引。
3.最左前缀:顾名思义,就是最左优先,上例中咱们建立了lname_fname_age多列索引,至关于建立了(lname)单列索引,(lname,fname)组合索引以及(lname,fname,age)组合索引。
注:在建立多列索引时,要根据业务需求,where子句中使用最频繁的一列放在最左边。