创建高性能mysql索引

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/liouyi250/article/details/81174946

1 索引基础

1.1 索引类型

B-tree索引(具体性质参见B-tree数据结构):所有值按照顺序存储,每一个叶子页到根的距离相同,索引的顺序很重要。有索引key(last_name,first_name,dob)。可查询如下类型:

  • 全值匹配:如Cuba Allen,1960-01-01

  • 匹配最左前缀:如Allen,即只使用索引的第一列。

  • 匹配列前缀:查找所有以J开头的姓的人,使用索引第一列

  • 匹配范围值:姓在Allen和BarryMore之间的人,使用索引第一列。

  • 精确匹配某一列并范围匹配另外一列:第一列全匹配,第二列范围匹配。

  • 只访问索引的查询

B-tree索引的限制:

  • 如果不是按照索引的最左列开始查找,则无法使用索引。如索引无法查找名字为bill的人,也无法查找特定生日的人,也无法查找姓氏以某个字母结尾的人。

  • 不能跳过索引中的列。索引无法用于查找姓为smith并且在某个特定日期出生的人,如不指定名(first_name),则mysql只能使用索引第一列。

  • 如果查询中有某个列的范围查询,则其右边所有列都无法使用索引优化查找。如有查询WHERE last_name=’Smith’ AND frist_name LIKE ‘J%’ AND dob=’1976-01-01’。这个查询只能使用索引的前两列。

哈希索引

基于哈希表实现,只有精确匹配索引所有列的查询才有效。在mysql中,只有momery引擎显示支持哈希索引。

空间数据索引(R-Tree)

MyISAM表支持空间索引,可以用作地理数据索引,这类索引无需前缀查询。

全文索引

是一种特殊的索引,它查找的时文本中的关键词,而不是直接比较索引中的值。

2 索引优点

  • 大大减少了服务器需要扫描的数据量

  • 帮助服务器避免排序和临时表

  • 可以将随机io变为顺序io。

非常小的表,大部分情况下简单的全表扫描更高效。中到大型表,索引非常有效。特大型表需要使用分区技术。

3 高性能的索引策略

3.1 独立的列

始终将索引列单独放在比较符号的一侧。

3.2 前缀索引和索引选择性

当索引很长的字符列,会让索引变的大且慢。一个策略是模拟哈希索引,还可以索引开始的部分字符,这样可以大大节约索引空间,提高索引效率。一般当前缀长度达到7的时候,再增加前缀长度,选择性提升的幅度已经很小了。

创建前缀索引:alter table sakila.city_demo add key(city(7))

前缀索引的缺点:无法使用前缀索引做order by和group by,也无法使用前缀索引做覆盖扫描。

3.3 多列索引

如索引:key(last_name,first_name,dob)

3.4 选择合适的索引列顺序

正确的顺序依赖于使用该索引的查询,并且同时需要考虑如何更好地满足排序和分组的需要。在一个多列btree索引中,索引列的顺序意味着索引首先按照最左列进行排序,其次是第二列,等等。多列索引的列顺序至关重要。经验做法:将选择性最高的列放在索引最前列。或者使用pt-query-digest工具进行分析。

3.5 聚簇索引

聚簇索引并不是一种单独的索引类型,而是一种数据存储方式,一个表只能有一个聚簇索引。InnoDB将通过逐渐聚集数据,如果没有定义主键,InnoDB会选择一个唯一的非空索引代替。如果没有这样的索引,InnoDB会隐式定义一个主键来作为聚簇索引。使用InnoDB时应该尽可能地按主键顺序插入数据,并且尽可能地使用单调增加的聚簇键的值来插入新行。

在InnoDB中,聚簇索引就是表,InnoDB的二级索引和聚簇索引很不同。InnoDB二级索引的页子节点中存储的不是“行指针”,而是主键值,并以此作为指向行的“指针”。

主索引:创建表激活后由系统自动创建的,不能修改

二级索引:自己创建的索引

3.6 覆盖索引

如果一个索引包含所有需要查询的字段的值,我么就称之为覆盖索引。覆盖索引能够极大提高性能,只需要扫描索引而无须回表。覆盖索引必须要存储索引列的值,所以mysql只能使用btree索引做覆盖索引。

错误示例:select * from products where actor=’sean carrey’ and title like ‘%apollo%’\G

这里索引无法覆盖该查询:1查询从表中选择了所有得咧,而没有任何索引覆盖了所有得列。2 mysql不能在索引中执行like操作,只能在索引中做最左匹配前缀匹配。

优化:select * from products join (select prod_id from products where actor=’sean carrey’ and title like ‘%apollo%’) as t1 on (t1.prod_id=products.prod_id)\G

3.7 使用索引扫描来做排序

如果explain出来的type列值为’index’,则说明mysql使用了索引扫描来做排序。

只有当索引的列顺序和order by子句的顺序完全一致,并且所有列的排序方向都一样,mysql才能够使用索引来对结果做排序。如果查询需要关联多张表,则只有当order by子句引用的字段全部为第一个表时,才能使用索引做排序。order by子句需要满足索引最左前缀的要求,如果不满足,前导列为常量的时候,可以利用索引排序。

Key rental_date(rental_date,inventory_id,customer_id)

select rental_id,staff_id from sakila.rental where rental_date=’2005-05-05’ order by inventory_id,customer_id\G

order by子句不满足索引最左前缀要求,也可以用于查询排序,因为索引第一列被指定为一个常数。

下列示例不能使用索引做排序查询

查询使用了两个不同的排序方向

..where rental_data=’2005-05-05’ order by inventory_id desc,customer_id asc;

order by使用了一个不在索引中的列

..where rental_date=’2005-05-05’ order by inventory_id,staff_id;

where和order by中的列无法组合成索引的最左前缀。

..where rental_date=’2005-05-05’ order by customer_id;

查询在索引的第一列上时范围条件,mysql无法使用索引的其余列

..where rental_date>’2005-05-05’ order by inventory_id,customer_id;

某一列上有多个等于条件,对于排序来说,这也是一种范围查询

..where rental_date=’2005-05-05’ and inventory_id in(1,2) order by customer_id;

3.8 压缩(前缀)索引

可以在create table语句中指定pack_keys参数来控制索引压缩方式。

3.9 冗余索引和重复索引

删除,工具common_shema或pt-duplicate-key-checker

3.10 未使用的索引

删除,工具pt-index-usage

3.11 索引和锁

InnoDB在访问行的时候会对其加锁,索引能够减少InnoDB访问的行数,从而减少锁的数量。如果索引无法过滤掉无效的行,那么在InnoDB检索到数据并返回给服务层后,mysql服务器才能应用where子句。

猜你喜欢

转载自blog.csdn.net/liouyi250/article/details/81174946
今日推荐