1.什么是索引
索引就相当于目录。为了方便查找书中的内容,通过对内容建立索引形成目录。索引是一个文件,它是要占据物理空间的。
2.索引的优缺点
索引的优点: 通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性 可以大大加快数据的检索速度,这也是创建索引的最主要的原因 可以加速表和表之间的连接 索引的缺点: 时间方面:创建索引和维护索引要耗费时间,当对表中的数据进行增加、删除和修改的时候,索引也要动态的维护,会降低增/改/删的执行效率 空间方面:索引需要占物理空间
3.索引的类型
主键索引: 数据列不允许重复,不允许为NULL,一个表只能有一个主键。
唯一索引: 数据列不允许重复,允许为NULL值,一个表允许多个列创建唯一索引。
可以通过 ALTER TABLE table_name ADD UNIQUE (column); 创建唯一索引
可以通过 ALTER TABLE table_name ADD UNIQUE (column1,column2); 创建唯一组合索引
普通索引: 基本的索引类型,没有唯一性的限制,允许为NULL值。
可以通过ALTER TABLE table_name ADD INDEX index_name (column);创建普通单列索引
可以通过ALTER TABLE table_name ADD INDEX index_name(column1, column2, column3);创建组合索引
全文索引: 适用于大量的文本数据检索(只有字段的数据类型为 char、varchar、text 及其系列才可以建全文索引)
4.创建索引的原则
适合创建索引条件: 1).主键自动建立唯一索引 2).频繁作为查询条件的字段应该建立索引 3).查询中与其他表关联的字段,外键关系建立索引 4).单键/组合索引的选择问题,组合索引性价比更高 5).查询中排序的字段,排序字段若通过索引去访问将大大提高排序效率 6).查询中统计或者分组字段
不适合创建索引条件: 1).表记录少的 2).经常增删改的表或者字段 3).where条件里用不到的字段不创建索引 4).过滤性不好的不适合建索引
5.什么是最左前缀原则
1).顾名思义,就是最左优先,以最左边的为起点任何连续的索引都能匹配上.
2).最左前缀匹配原则,非常重要的原则,mysql会一直向右匹配直到遇到范围查询(>、<、between、like)就停止匹配,
比如a = 1 and b = 2 and c > 3 and d = 4 如果建立(a,b,c,d)顺序的索引,d是用不到索引的,如果建立(a,b,d,c)的索引则都可以用到,a,b,d的顺序可以任意调整。
3).=和in可以乱序,比如a = 1 and b = 2 and c = 3 建立(a,b,c)索引可以任意顺序,mysql的查询优化器会帮你优化成索引可以识别的形式
这里说下组合索引的本质:
当创建(a,b,c)联合索引时,相当于创建了(a)单列索引,(a,b)联合索引以及(a,b,c)联合索引.
多个单列索引在多条件查询时只会生效第一个索引!所以多条件联合查询时最好建联合索引!
6.索引失效的场景
1).where子句中进行的null值判断
2).对索引列使用了函数或者进行了运算符操作(+ - * / != <> %)
3).like模糊查询以%开头(like ‘%xxx’)
4).or条件查询,只有给or条件关联的每个列都加上单列索引,索引才会生效,否则都不生效
5).NOT IN 条件判断
6).如果列类型是字符串,那一定要在条件中将数据使用引号引用起来,否则不使用索引
7).组合索引不满足最左匹配原则
8).如果查询的数据量很大,mysql底层会估算使用全表扫描是否比使用索引快,如果快的话则不走索引
7.平衡二叉树, B树和B+树的特点
1)平衡二叉树 每个节点一个元素,每个节点下最多左右两个子节点,左子树和右子树高度相差不超多1 支持范围查询,但回表查询效率低 2)B树 通过增加节点的元素个数来降低树的高度,从而减少了IO操作次数 比平衡二叉树查询效率高,也支持范围查询,但同样回表查询效率低 3)B+树 比B树多了一层叶子结点. 非叶子节点存关键字,叶子节点存key-value;
所有关键字都出现在叶子结点的链表中(稠密索引),且链表中的关键字恰好是有序的;
不可能在非叶子结点命中;
非叶子结点相当于是叶子结点的索引(稀疏索引),叶子结点相当于是存储(关键字)数据的数据层; 支持范围查询,效率高(因为叶子结点指针顺序连接在一起,类似链表)
这里说下B+树的叶子结点存的value值:
myisam存的是数据地址
innodb(主键索引存的是数据记录,非主键索引存的主键值)
8.B树和B+树的区别
1)B树只适合随机检索,而B+树同时支持随机检索和顺序检索;
2)B+树空间利用率更高,可减少I/O次数,磁盘读写代价更低。一般来说,索引本身也很大,不可能全部存储在内存中,因此索引往往以索引文件的形式存储的磁盘上。这样的话,索引查找过程中就要产生磁盘I/O消耗。
B+树的内部结点并没有指向关键字具体信息的指针,只是作为索引使用,其内部结点比B树小,盘块能容纳的结点中关键字数量更多,一次性读入内存中可以查找的关键字也就越多,相对的,IO读写次数也就降低了。而IO读写次数是影响索引检索效率的最大因素;
3)B+树的查询效率更加稳定。B树搜索有可能会在非叶子结点结束,越靠近根节点的记录查找时间越短,只要找到关键字即可确定记录的存在,其性能等价于在关键字全集内做一次二分查找。
而在B+树中,顺序检索比较明显,随机检索时,任何关键字的查找都必须走一条从根节点到叶节点的路,所有关键字的查找路径长度相同,导致每一个关键字的查询效率相当。
4)B树在提高了磁盘IO性能的同时并没有解决元素遍历的效率低下的问题。B+树的叶子节点使用指针顺序连接在一起,只要遍历叶子节点就可以实现整棵树的遍历。而且在数据库中基于范围的查询是非常频繁的,而B树不支持这样的操作。
5)增删文件(节点)时,效率更高。因为B+树的叶子节点包含所有关键字,并以有序的链表结构存储,这样可很好提高增删效率。
6)在B树中,你可以将键和值存放在内部节点和叶子节点;但在B+树中,内部节点都是键,没有值,叶子节点同时存放键和值。
7)B+树的叶子节点有一条链相连,而B树的叶子节点各自独立。
使用B树的好处
B树可以在内部节点同时存储键和值,因此,把频繁访问的数据放在靠近根节点的地方将会大大提高热点数据的查询效率。这种特性使得B树在特定数据重复多次查询的场景中更加高效。
使用B+树的好处
由于B+树的内部节点只存放键,不存放值,因此,一次读取,可以在内存页中获取更多的键,有利于更快地缩小查找范围。
B+树的叶节点由一条链相连,因此,当需要进行一次全数据遍历的时候,B+树只需要使用O(logN)时间找到最小的一个节点,然后通过链进行O(N)的顺序遍历即可。
而B树则需要对树的每一层进行遍历,这会需要更多的内存置换次数,因此也就需要花费更多的时间
9.Hash索引和B+树区别
hash索引底层就是hash表,进行查找时,调用一次hash函数就可以获取到相应的键值,之后进行回表查询获得实际数据。B+树底层实现是多路平衡查找树。对于每一次的查询都是从根节点出发,查找到叶子节点方可以获得所查键值,然后根据查询判断是否需要回表查询数据。 不同点: 1)hash索引进行等值查询更快(一般情况下),但是却无法进行范围查询。因为在hash索引中经过hash函数建立索引之后,索引的顺序与原顺序无法保持一致,不能支持范围查询。而B+树的的所有节点皆遵循(左节点小于父节点,右节点大于父节点,多叉树也类似),天然支持范围。 2)hash索引不支持使用索引进行排序,原理同上。hash索引不支持模糊查询以及多列索引的最左前缀匹配。原理也是因为hash函数的不可预测。AAAA和AAAAB的索引没有相关性。 3)hash索引任何时候都避免不了回表查询数据,而B+树在符合某些条件(聚簇索引,覆盖索引等)的时候可以只通过索引完成查询。 4)hash索引虽然在等值查询上较快,但是不稳定。性能不可预测,当某个键值存在大量重复的时候,发生hash碰撞,此时效率可能极差。而B+树的查询效率比较稳定,对于所有的查询都是从根节点到叶子节点,且树的高度较低。
因此,在大多数情况下,直接选择B+树索引可以获得稳定且较好的查询速度。而不需要使用hash索引。
10.聚簇索引和非聚簇索引
聚簇索引:将数据存储与索引放到了一块,找到索引也就找到了数据 非聚簇索引:将数据存储与索引分开结构,索引结构的叶子节点指向了数据行的地址或者是指向主键值,
澄清一个概念:
innodb中,在聚簇索引之外创建的索引称之为辅助索引(二级索引),辅助索引访问数据总是需要二次查找,像复合索引、前缀索引、唯一索引,辅助索引叶子节点存储的不再是行的物理位置,而是主键值
innodb引擎:
InnoDB使用的是聚簇索引,将主键组织到一棵B+树中,而行数据就储存在叶子节点上,若使用"where id = 14"这样的条件查找主键,则按照B+树的检索算法即可查找到对应的叶节点,之后获得行数据。
若对Name列进行条件搜索,则需要两个步骤:第一步在辅助索引B+树中检索Name,到达其叶子节点获取对应的主键。第二步使用主键在主索引B+树种再执行一次B+树检索操作,最终到达叶子节点即可获取整行数据。(重点在于通过其他键需要建立辅助索引)
myisam引擎:
MyISM使用的是非聚簇索引,非聚簇索引的两棵B+树看上去没什么不同,节点的结构完全一致只是存储的内容不同而已,
主键索引B+树的节点存储了主键,辅助键索引B+树存储了辅助键。表数据存储在独立的地方,这两颗B+树的叶子节点都使用一个地址指向真正的表数据,对于表数据来说,这两个键没有任何差别。由于索引树是独立的,通过辅助键检索无需访问主键的索引树。
11.聚簇索引的设定
聚簇索引默认是主键,如果表中没有定义主键,InnoDB 会选择一个唯一的非空索引代替。如果没有这样的索引,InnoDB 会隐式定义一个主键来作为聚簇索引。
12.innodb为什么建议使用自增id作为主键?
聚簇索引的数据的物理存放顺序与索引顺序是一致的, 即:只要索引是相邻的,那么对应的数据一定也是相邻地存放在磁盘上的
如果主键不是自增id,它会不断地调整数据的物理地址、分页,
如果主键是自增id, 那它每次插入新的记录,记录就会顺序添加到当前索引节点的后续位置,当一页写满,就会自动开辟一个新的页,索引结构相对紧凑,磁盘碎片少,效率也高
13.什么是前缀索引
前缀索引
对于列的值较长,比如BLOB、TEXT、VARCHAR,就必须建立前缀索引,即将值的前一部分作为索引。这样既可以节约空间,又可以提高查询效率。但无法使用前缀索引做 ORDER BY 和 GROUP BY,也无法使用前缀索引做覆盖扫描。
# 语法
ALTER TABLE table_name ADD KEY(column_name(prefix_length));
# 示例
ALTER TABLE city ADD KEY(cityname(7))
14.什么是回表
在普通索引查到主键后,再去主键索引定位记录.等于非主键索引多走了一个主键索引树.
如何避免回表:
索引覆盖被查询的字段
15.什么是覆盖索引
如果一个索引包含了(或覆盖了)满足查询语句中字段与条件的数据就叫 做覆盖索引。
这种解释更明了:
覆盖索引就是从辅助索引中就能直接得到查询结果,而不需要回表到聚簇索引中进行再次查询,所以可以减少搜索次数(不需要从辅助索引树回表到聚簇索引树),或者说减少IO操作(通过辅助索引树可以一次性从磁盘载入更多节点),从而提升性能。
16.explain执行计划
Explain包含字段信息 Explain包含字段信息如下:分别是 id、select_type、table、partitions、type、possible_keys、key、key_len、ref、rows、Extra 10个字段。 Explain各个字段含义 id id表示执行顺序,id值越大,越先执行; 子查询,id的序号会递增; id值相同的情况,可以理解为一组,执行顺序是从上向下。
select_type SIMPLE:简单的select语句,不包含子查询或者union PRIMARY:查询中包含复杂查询(比如子查询),最外层查询被标记为PRIMARY SUBQUERY:当select或where包含了子查询,该子查询被标记为SUBQUERY DERIVED:表示包含在from子句中的子查询的select UNION:union中第二个或后面的select语句 UNION RESULT:代表从union的临时表中读取数据
table 表名,也有可能是别名或者临时表 partitions 当查询的是分区表时,partitions显示分区表命中的分区情况 type 它在 SQL优化中是一个非常重要的指标,以下性能从好到坏依次是:system > const > eq_ref > ref > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL system:当表仅有一行记录时(系统表),数据量很少,往往不需要进行磁盘IO,速度非常快 const:当命中的是主键或者唯一索引且为常量 eq_ref:查询命中的是主键或者唯一索引 ref:非唯一性索引,会找到超过一条符合条件的行 ref_or_null:与ref类似,只是会额外搜索包含null值的行 index_merge:同时使用了两个或两个以上的索引 unique_subquery:子查询返回不重复的集合 index_subquery:区别于unique_subquery,用于非唯一索引,可以返回重复值 range:对有索引的字段,给定范围检索,bettween...and、<、>、<=、in 等 index:遍历索引树读取,而all是从硬盘读取 ALL:将遍历全表以找到匹配的行,性能最差
需要记忆的
system>const>eq_ref>ref>range>index>ALL
一般来说,得保证查询至少达到range级别,最好能达到ref
possible_keys
mysql可能通过某个索引检索到数据,但不一定最终查询会用到
key key是查询中实际使用到的索引,若没有使用索引,显示为NULL key_len 表示查询用到的索引长度(字节数),原则上长度越短越好 单列索引,那么需要将整个索引长度算进去; 多列索引,不是所有列都能用到,需要计算查询中实际用到的列。 注:key_len只计算where条件中用到的索引长度,而排序和分组即便是用到了索引,也不会计算到key_len中。
ref const:当使用常量等值查询 当关联查询时,会显示相应关联表的关联字段 func:如果查询条件使用了表达式、函数,或者条件列发生内部隐式转换 其他情况null
rows rows:以表的统计信息和索引使用情况,估算要找到我们所需的记录,需要读取的行数。 filtered filtered 这个是一个百分比的值,表里符合条件的记录数的百分比。简单点说,这个字段表示存储引擎返回的数据在经过过滤后,剩下满足条件的记录数量的比例。 Extra 额外的信息会在 Extra 字段显示 1.Using index 查询到的列被索引覆盖,实际上就是覆盖索引的使用 2.Using where 查询未用到可用的索引,通过where条件过滤数据 3.Using where,Using index 通过where条件过滤数据,并且查询用到了覆盖索引 4.Using index condition 查询使用到了索引,但是需要回表查询,5.6及其以上版本才有,之前是Using where 5.Using temporary 查询后结果需要使用临时表来存储,一般在排序或者分组查询时用到 6.Using filesort 无法利用索引完成的排序操作,也就是ORDER BY的字段没有索引 7.Using join buffer 在我们联表查询的时候,如果表的连接条件没有用到索引,需要有一个连接缓冲区来存储中间结果 8.Impossible where 在我们用不太正确的where语句,导致没有符合条件的行 9.No tables used 我们的查询语句中没有FROM子句,或者有FROM DUAL子句