mysql索引原理及优化思路

索引的本质

索引(Index)是帮助MySQL高效获取数据的数据结构
所以索引是一种数据结构
便于二分法,二叉树查找法等优秀的查找算法的数据结构

B-tree和B+tree

B-tree特性:

  1. 关键字集合分布在整颗树中;
  2. 任何一个关键字出现且只出现在一个结点中;
  3. 搜索有可能在非叶子结点结束;
  4. 其搜索性能等价于在关键字全集内做一次二分查找;
  5. 自动层次控制;

与B-Tree相比,B+Tree有以下不同点:

每个节点的指针上限为2d而不是2d+1。

内节点不存储data,只存储key;叶子节点不存储指针。

mysql的myisam引擎索引

同样也是一颗B+Tree,data域保存数据记录的地址。因此,MyISAM中索引检索的算法为首先按照B+Tree搜索算法搜索索引,如果指定的Key存在,则取出其data域的值,然后以data域的值为地址,读取相应数据记录。
MyISAM的索引方式也叫做“非聚集”的,之所以这么称呼是为了与InnoDB的聚集索引区分。

mysql的innodb引擎索引

第一个重大区别是InnoDB的数据文件本身就是索引文件。从上文知道,MyISAM索引文件和数据文件是分离的,索引文件仅保存数据记录的地址。而在InnoDB中,表数据文件本身就是按B+Tree组织的一个索引结构,这棵树的叶节点data域保存了完整的数据记录。这个索引的key是数据表的主键,因此InnoDB表数据文件本身就是主索引。

这种索引叫做聚集索引。因为InnoDB的数据文件本身要按主键聚集,所以InnoDB要求表必须有主键(MyISAM可以没有)
如果没有显式指定,则MySQL系统会自动选择一个可以唯一标识数据记录的列作为主键,如果不存在这种列,则MySQL自动为InnoDB表生成一个隐含字段作为主键,这个字段长度为6个字节,类型为长整形。

第二个与MyISAM索引的不同是InnoDB的辅助索引data域存储相应记录主键的值而不是地址。换句话说,InnoDB的所有辅助索引都引用主键作为data域。

使用策略及优化

SHOW PROFILES; --查看性能
EXPLAIN SELECT * FROM employees.titles; --查看执行过程
  1. 当按照索引中所有列进行精确匹配(这里精确匹配指“=”或“IN”匹配)时,索引可以被用到
  2. 由于MySQL的查询优化器会自动调整where子句的条件顺序以使用适合的索引
  3. 当查询条件精确匹配索引的左边连续一个或几个列时,如或,所以可以被用到,但是只能用到一部分,即条件所组成的最左前缀
  4. 在这种成为“坑”的列值比较少的情况下,可以考虑用“IN”来填补这个“坑”从而形成最左前缀:
  5. 如果坑”的列值很多,用填坑就不合适了,必须建立辅助索引。
  6. 如果通配符%不出现在开头,则可以用到索引,但根据具体情况不同可能只会用其中一个前缀
  7. 范围列可以用到索引(必须是最左前缀),但是范围列后面的列无法用到索引。
  8. 仅用explain可能无法区分范围索引和多值匹配,
  9. 作用于emp_no上的“BETWEEN”实际上相当于“IN”,也就是说emp_no实际是多值精确匹配。
  10. 如果查询条件中含有函数或表达式,则MySQL不会为这列使用索引

主键选择和优化

索引
优点:为索引虽然加快了查询速度
缺点:索引文件本身要消耗存储空间,同时索引会加重插入、删除和修改记录时的负担,另外,MySQL在运行时也要消耗资源维护索引,因此索引并不是越多越好。

不用索引的几种情况:

  • 表数据很少(一般2000条为界限)
  • 索引的选择性较低

选择性–>是指不重复的索引值(也叫基数,Cardinality)与表记录数(#T)的比值:

SELECT count(DISTINCT(title))/count(*) AS Selectivity FROM employees.titles; +-------------+
| Selectivity | +-------------+
| 0.0000 | +-------------+

前缀索引

SELECT count(DISTINCT(first_name))/count(*) AS Selectivity FROM employees.employees; +-------------+
| Selectivity | +-------------+
| 0.0042 | +-------------+
SELECT count(DISTINCT(concat(first_name, last_name)))/count(*) AS Selectivity FROM employees.employees; +-------------+
| Selectivity | +-------------+
| 0.9313 | +-------------+

但是索引太长30个字符,维护消耗高

SELECT count(DISTINCT(concat(first_name, left(last_name, 4))))/count(*) AS Selectivity FROM employees.employees; +-------------+
| Selectivity | +-------------+
| 0.9007 | +-------------+

所以这样建比较好,只有18个字符

ALTER TABLE employees.employees ADD INDEX `first_name_last_name4` (first_name, last_name(4));

前缀索引兼顾索引大小和查询速度,但是其缺点是不能用于ORDER BY和GROUP BY操作,也不能用于Covering index(即当索引本身包含查询所需全部数据时,不再访问数据文件本身)。

在使用InnoDB存储引擎时,如果没有特别的需要,请永远使用一个与业务无关的自增字段作为主键。

参考文献
[1] Baron Scbwartz等 著,王小东等 译;高性能MySQL(High Performance MySQL);电子工业出版社,2010

[2] Michael Kofler 著,杨晓云等 译;MySQL5权威指南(The Definitive Guide to MySQL5);人民邮电出版社,2006

[3] 姜承尧 著;MySQL技术内幕-InnoDB存储引擎;机械工业出版社,2011

[4] D Comer, Ubiquitous B-tree; ACM Computing Surveys (CSUR), 1979

[5] Codd, E. F. (1970). “A relational model of data for large shared data banks”. Communications of the ACM, , Vol. 13, No. 6, pp. 377-387

[6] MySQL5.1参考手册 - http://dev.mysql.com/doc/refman/5.1/zh/index.html

你可能感兴趣的:(mysql)