战五渣系列之七(索引那点事)

当谈论数据库的时候我们一般指的就是mysql,so,我们谈索引的时候指的是innodb 的B+Tree,因为索引是在存储引擎层而不是服务层实现的,而大多数开发中都用的是默认引擎innodb。

参考链接:

MySQL索引背后的数据结构及算法原理

http://coding-geek.com/how-databases-work/

数据映射–B树

书籍:《高性能mysql》

1.我们优化的到底是什么

响应时间,我们通过考虑数据库 扫描行数和 返回行数来解决问题。如果我们需要返回一条记录,却要扫描成千上万条记录,就要考虑为什么会扫描这么多行数呢?!必须得扫描吗?例如没有任何优化能使 SELECT COUNT(*) 来降低扫描行数。

我们就会考虑使用索引降低扫描行数来优化查询 :例如 select * from user where id = 1 就可以通过索引直接找到数据所在的行。

2.索引的原理(就是映射)

反映在数据结构中:

根据id查询: select * from user where id = 1;
User user1 = userMap.get(pk=1);是不是就获取到了User ?

根据phone查询: select * from user where phone = 110;则:

int id= pkMap.getPk(phone=110);
User user1 = userMap.get(pk);

这个时候我们称phone为二级索引也叫做非聚集索引,我们把主键索引称之为聚集索引(因为数据聚集在主键的叶子节点,而二级索引的叶子节点保存的是主键)。

也就是所有的二级索引都会引用主索引,因此主键索引的长度会使二级索引变得庞大!

Innodb 要求所有表都必须有主键,如果没有主键,则会取该表的unique 列 作为主键列。如果没有则会隐式的创建一个6个字节类型为长整形的列作为主键!

3. 索引特性(B+Tree)

  1. 索引一定是有序的,所以无序的hash索引无法完成范围查询!
  2. 索引结构要保持有序和平衡。如果说我们使用UUID等非自增数值作为主键,那么索引结构不得不分裂合并以保持有序,会降低插入和删除的性能。如果使用自增则只是追加到索引结构,而无需重新分裂!
  3. 索引的长度。索引的长度要尽可能的小,数据库每次从磁盘读取一个page的索引,如果索引的长度很大,一个page只能读取的key就会减少,多次读取会增加磁盘IO的次数,也会增大索引文件的体积,并且降低索引比较的效率。
  4. 最左前缀。因为索引是有序的,就和字典一样,所有A开头的在一起,AB开头的在一起,接下来是AC开头的,然后是B开头的。所以就出现了最左前缀原理。在非复合索引中, LIKE “key%”可以用到索引而LIKE ‘%key’ 就不能。在复合索引中。
    例如 key: <col1,col2,col3>:
    col1 = 1 and col2 =2 and col3=3 全部匹配可以用到索引。
    col1 = 1 and col3 = 3 只有col1能用到索引
    col2 = 2 and col3 = 3 则无法用到索引。所以在查询中我们应该构造全列匹配或者避免符合索引不符合最左前缀
  5. 范围查询。范围查询后面的列皆无法用到索引。
    例如 key <col1,col2,col3> col1 = 1 and col2 <7 and col3=4则 col3无法用到索引。这个原理大家仔细的想象B+Tree就能理解了。

数据库的查询优化大概总结到一点:使用各种方法减少扫描行数(磁盘IO)!现实场景中优化的方法很多都只是听说过,业务场景不同,术业有专攻而已,

4. 渣渣程序员的一个问题

关联的时候为什么要求小的结果驱动大的结果?难道 o(log(N*M)) != o(log(M*N)) ?

你可能感兴趣的:(最左前缀,索引长度,mysql查询优化,mysql索引优化)