MySQL的基本存储结构是页(记录都存在页里边): html
因此说,若是咱们写select * from user where indexname = 'xxx'这样没有进行任何优化的sql语句,默认会这样作:面试
- 定位到记录所在的页:须要遍历双向链表,找到所在的页
- 从所在的页内中查找相应的记录:因为不是根据主键查询,只能遍历所在页的单链表了
将无序的数据变成有序的数据(就像查目录同样)。 算法
要找到id为8的记录简要步骤: ![]()
![]()
很明显的是:没有用索引咱们是须要遍历双向链表来定位对应的页,如今经过 “目录” 就能够很快地定位到对应的页上了!(二分查找,时间复杂度近似为O(logn))sql
其实底层结构就是B+树,B+树做为树的一种实现,可以让咱们很快地查找出对应的记录。数据库
对于哈希索引来讲,底层的数据结构就是哈希表,所以在绝大多数需求为单条记录查询的时候,能够选择哈希索引,查询性能最快;其他大部分场景,建议选择BTree索引。bash
MySQL的BTree索引使用的是B树中的B+Tree。但对于主要的两种存储引擎(MyIsam和InnoDB)的实现方式是不同的。服务器
ps:联合索引的特色:遵循最左前缀的规则数据结构
MySQL中的索引能够以必定顺序引用多列,这种索引叫做联合索引。如User表的name和city加联合索引就是(name,city),而最左前缀原则指的是,若是查询的时候查询条件精确匹配索引的左边连续一列或几列,则此列就能够被用到。以下:函数
select * from user where name=xx and city=xx ; //能够命中索引
select * from user where name=xx ; // 能够命中索引
select * from user where city=xx ; // 没法命中索引
复制代码
这里须要注意的是,查询的时候若是两个条件都用上了,可是顺序不一样,如 city= xx and name =xx,那么如今的查询引擎会自动优化为匹配联合索引的顺序,这样是可以命中索引的。post
因为最左前缀原则,在建立联合索引时,索引字段的顺序须要考虑字段值去重以后的个数,较多的放前面。ORDER BY子句也遵循此规则。
B+Tree叶子节点的data域存放的是数据记录的地址。在索引检索的时候,首先按照B+Tree搜索算法搜索索引,若是指定的Key存在,则取出其data域的值,而后data域的值为地址读取响应的数据记录。这被称为“非聚簇索引”。
其数据文件自己就是索引文件。MyIsam中,索引文件和数据文件是分离的,而InnoDB中,其表数据文件自己就是按B+Tree组织的一个索引结构,树的叶节点data域保存了完整的数据记录。这个索引的key是数据表的主键,所以InnoDB表数据文件自己就是主索引。这被称为“聚簇索引(或汇集索引)”,而其他的索引都做为辅助索引,辅助索引的data域存储相应记录主键的值而不是地址,这也是和MyIsam不一样的地方。在根据主索引搜索时,直接找到key所在的节点便可取出数据;在根据辅助索引搜索时,则须要先取出主键的值,再走一遍主索引。所以,在设计表的时候,不建议使用过长的字段做为主键,也不建议使用非单调的字段做为主键,这会形成主索引频繁分裂。
【注】更详细的请出门左转: MySQL索引和SQL调优
若是一个索引包含(或者说覆盖)全部须要查询的字段的值,咱们就称之为“覆盖索引”。咱们知道在InnoDB存储引擎中,若是不是主键索引,叶子节点存储的是主键+列值。最终仍是要“回表”,也就是要经过主键再查找一次,这样就会比较慢。覆盖索引就是要查询的列和索引是对应的,不作回表操做。
加入建立了索引(username,age),在查询数据的时候:
select username,age from user where username = ‘Java’ and age = 22;
要查询成的列在叶子节点都存在,因此不用回表。
select * from tb1 where name like '%cn';
复制代码
以'%'开头:索引失效。
以'%'结尾:索引能够用。
select * from tb1 where reverse(name) = 'wupeiqi';
复制代码
select * from tb1 where nid = 1 or email = 'seven@live.com';
复制代码
特别地:当or条件中有未创建因此的列才失效,如下会走索引
select * from tb1 where nid = 1 or name = 'seven';
select * from tb1 where nid = 1 or email = 'seven@live.com' and name = 'alex'
复制代码
若是条件中有or,即便其中有条件带索引也不会使用(这也是为何尽可能少于or的缘由)
注意:要想使用or,又想让索引生效,只能将or条件中的每一个列中都加上索引.
类型不一致 若是列类型是字符串,那必定要在条件中将数据使用引号引用起来,不然不使用索引
含有'!=' 或者'>'
select * from tb1 where name != 'alex'
复制代码
【特别地】:若是是主键或索引整数类型,则仍是会走索引
select * from tb1 where nid > 123
select * from tb1 where num > 123
复制代码
select email from tb1 order by name desc;
复制代码
当根据索引排序时,选择的映射若是不是索引,则不走索引
【特别地】:若是对主键排序,则仍是会走索引:
select * from tb1 order by nid desc;
复制代码
若是组合索引为:(name, email)
- name and email # 使用索引
- name # 使用索引
- email # 不使用索引
复制代码
注:以上内容整理自: