索引概述
索引是一种能帮助MySQL高效获取数据的有序数据结构。
- 优点:提高数据检索的效率,降低数据库的IO成本;通过索引列对数据进行排序,降低数据排序的成本,降低CPU的消耗。
这里加个面试问题:磁盘IO为什么慢。www.modb.pro/db/385070
- 缺点:索引大大提高了查询效率,同时也降低更新表的速度,如对表进行增删改,效率降低
索引结构
为什么不用Hash、倒排索引要用B+Tree
hash所以不适用的场景
- 不支持范围查询(经过hash算法后,就变得不连续了)
- 不支持利用索引完成排序、以及模糊查询
- 不支持联合索引的最左前缀匹配规则(后面有)
在MySQL中,支持hash索引的是Memory引擎,而InnoDB中具有自适应hash功能,hash索引是存储引擎根据B+Tree索引在指定条件下自动构建的。
B-Tree
二叉树缺点:顺序插入时,会形成一个链表,查询性能大大降低。大数据量情况下,层级较深,检索速度慢。
红黑树:大数据量情况下,层级较深,检索速度慢。(因为二叉树不是连续内存,所以每读一个节点就需要进行一次磁盘IO。而B-Tree一个节点有多个值,这些值是连续的,所以每次读取也只要进行一次IO,但是他的高度比较低,IO少,所以效率比较高)
数据结构的演变:
参考博客:blog.csdn.net/dl962454/ar…
- 链表:查询过程只能一个一个遍历然后比较值,时间复杂度为O(n)
- 二叉树:其实也无法满足查询需求
- 二叉排序树:该树是有序的,所以在查的时候折半查询(二分查询)时间复杂度为O(logn), 但可能出现退化成链表的情况,所以结构也未达到要求
- 平衡二叉树:要求左右高度相差不能超过2,否则进行自旋;比较理想的数据结构,但是有可能一次插入的自旋次数是不可预知的。插入效率非常低。
- 红黑树:
红黑树的性质:
(1)每个节点是黑/红色
(2)根节点是黑色
(3)每个叶子节点(NIL)是黑色。【注意:这里叶子节点,是指空(NIL或NULL)的叶子节点!】
(4)如果一个节点是红色的,则它的子节点必须是黑色的
(5)从一个节点到该节点的子孙节点的所有路径上包含相同数目的黑节点。
有了上面的几个性质作为限制,即可避免二叉查找树退化成单链表的情况。但是,仅仅避免这种情况还不够,这里还要考虑某个节点到其每个叶子节点路径长度的问题。如果某些路径长度过长,那么,在对这些路径上的节点进行增删改查操作时,效率也会大大降低。这个时候性质4、性质5的用途就凸显了,有了这两个性质作为约束,即可保证任意节点到其每个叶节点路径最长不会超过最短路径的2倍。原因如下:
当某条路径最短时,这条路径必然都是由黑色节点构成。当某路径长度最长时,这条路径必然是红色和黑色节点相间构成(性质4限定了不能出现两个连续的红色节点)。而性质5又限定了从任一节点到其每个叶子节点的所有路径必须包含相同的黑色节点。
平衡二叉树和红黑树区别:
然而,红黑树毕竟还是二叉树,一个结点点最多拥有两个直接子结点,当我们插入大量数据的时候,会导致 的树的高度过高,I/O渐进复杂度为O(h)。如果要查找14,就需要查询5次,所以还是没有有效的减少查找过 程中磁盘I/O的存取次数。
- B树:
1、定义任意非叶子结点最多只有M个儿子,且M>2;
2、根结点的儿子数为[2, M];
3、除根结点以外的非叶子结点的儿子数为[M/2, M];
4、每个结点存放至少M/2-1(取上整)和至多M-1个关键字;(至少2个关键字)
5、非叶子结点的关键字个数=指向儿子的指针个数-1;
6、非叶子结点的关键字:K[1], K[2], …, K[M-1];且K[i] < K[i+1];
7、非叶子结点的指针:P[1], P[2], …, P[M];其中P[1]指向关键字小于K[1]的子树,P[M]指向关键字大于K[M-1]的子树,其它P[i]指向关键字属于(K[i-1], K[i])的子树;
8、所有叶子结点位于同一层;
- B+树
1、非叶子节点的子树指针与关键字个数相同;
2、非叶子节点的子树指针p[i],指向关键字值属于[k[i],k[i+1]]的子树。
索引的分类
- 主键索引:针对表中主键创建的索引,默认创建,只能有一个
- 唯一索引:返回同一个表中某数据列中的值重复
- 常规索引:快速定位特定数据
- 全文索引:全文索引查找的是文本中的关键字,而不是比较索引中的值
在InnoDB存储引擎中,根据索引的存储形式,又可以分为以下两种:
- 聚集索引:将数据存储与索引放在了一块,索引结构的子节点保存了行数据
- 二级索引:将数据与索引分开存储,索引结构的叶子节点关联的是对应的主键
聚集索引选取规则:
- 默认是主键作为聚集索引
- 如果没有主键则以第一个唯一(UNIQUE)索引作为聚集索引
- 如果表没有主键,或没有合适的唯一索引,则InnoDB会自动生成一个rowid作为隐藏的聚集索引
使用二级索引查询会走回表查询
索引语法
创建索引
CREATE [UNIQUE|FULLTEXT] INDEX index_name ON table_name (index_col_name,...);
查看索引
SHOW INDEX FROM table_name;
删除索引
DROP INDEx index_name ON table_name
SQL性能分析
- 可以通过如下命令查看当前数据库的增删改查的访问频次 (如果发现查询多,就要做相应的sql优化)
SHOW GLOBAL STATUS LIKE 'Com_';
- 慢查询日志
慢查询日志记录了所有执行时间超过指定参数(long_query_time,单位:秒,默认10秒)的所有SQL语句的日志
MySQL的慢查询日志默认没有开启,需要在MySQL的配置文件(/etc/my.cnf)中配置如下信息:
//慢查询日志是否开启
show variables like 'slow_query_log';
//开启MySQL慢日志查询开关
show_query_log = 1;
#设置慢查询的时间为2s,sql执行时间超过2s,就会视为慢查询,记录慢查询日志
long_query_time = 2;
配置完毕之后,通过以下指令重新启动MySQL服务器进行测试,查看慢查询日志文件中记录的信息 /var/lib/mysql/localhost-slow.log
- profile详情
展示每条sql的执行时长
// 查询是否支持
select @@have_profiling;
// 默认porfiling是关闭,可以通过set语句在session/global级别开启profiling
SET profiling = 1;
- explain执行计划
EXPLAIN SELECT 字段列表 FROM
比较难,后面在慢慢看
索引的使用
最左前缀法则
在多列建立索引之后,要遵循最左前缀法则。最左前缀法制指的是索引的最左边开始,并且不跳过索引中的列。
如果跳过某一列,索引将部分失效(后面的字段索引失效)
范围查询
联合索引中,出现范围查询(>,<),范围查询右侧的列索引失效
索引列的运算操作
- 字符串不加引号:字符串字段类型使用时,不加引号,索引将失效
- 模糊查询:尾部模糊不是失效,头部模糊匹配,索引失效
- or连接的条件:用or分割开的条件,如果or前的条件中的列有索引,而后面的列中没有索引,那么涉及的索引都不会用到。
SQL提示
//使用哪个索引
use indeex:
explain select * from tb_user use index(idx_user_pro) where ...
//不使用哪个索引
ignore index:
explain select * from tb_user ignore index(idx_user_pro) where ...
//必须使用的索引
force index:
explain select * from tb_user force index(idx_user_pro) where ...
覆盖索引
什么是覆盖索引:覆盖索引是通过聚集索引或者二级索引一次就能找到查询需要的数据,但是如果如果查询的字段不是从索引中没找到那么就要走回表查询(非覆盖索引)
前缀索引
将截取字段中的前n个元素作为索引,主要是为了节省空间,查询和一般索引差不多
单列索引和联合索引
多个字段建议使用联合索引,MySQL会通过联合的字段建立索引(按照最左前缀法制,一个个比较),