文章目录
一、索引
1、为何要有索引
知识回顾:数据都是存在硬盘上的,那查询数据不可避免的需要进行IO操作
索引在MySQL中也叫做“键”,是存储引擎用于快速找到记录的一种数据结构。
primary key
unique key
index key
注意foreign key不是用来加速查询用的,不在我们研究范围之内,上面三种key前两种除了有加速查询的效果之外还有额外的约束条件(primary key:非空且唯一,unique key:唯一),而index key没有任何约束功能只会帮你加速查询
索引就是一种数据结构,类似于书的目录
。意味着以后再查数据应该先找目录再找数据,而不是用翻页的方式查询数据
2、什么是索引
通过不断地缩小想要获取数据的范围来筛选出最终想要的结果,同时把随机的事件变成顺序的事件,有点类似于二分法查找的机理
也就是说,有了这种索引机制,我们可以总是用同一种查找方式来锁定数据
3、索引的影响
- 在表中有大量数据的前提下,创建索引速度会很慢
- 在索引创建完毕后,对表的查询性能会大幅度提升,但是写的性能会降低
为什么说表中有大量数据,创建索引会很慢?
答:假设你现在表中数据已经很多,如果你执行增、删、改任何一个操作,都会造成索引重新创建。
# 也即是你写好的已经创建目录的一本书,如果你想要添加一页内容,那么会造成目录全部丢失,需要重头一页一页创建索引,因此表数据很大,会造成创建索引很慢。
目前我所知道的解决方法:分库分表
4、索引的数据结构
只有叶子结点存放真实数据,根和树枝节点存的仅仅是虚拟数据.这里采用多级索引,索引是牺牲空间,加快速度!
磁盘块索引详解:https://blog.csdn.net/weixin_44571270/article/details/105899656
查询次数由树的层级决定,层级越低次数越少
一个磁盘块儿的大小是一定的,那也就意味着能存的数据量是一定的。如何保证树的层级最低呢?一个磁盘块应该尽量用来存储数据,而不是索引,因此添加索引的字段名应该尽量的小!
5、聚集索引、辅助索引
(1)聚集索引(primary key)
聚集索引其实指的就是表的主键
,innodb引擎规定一张表中必须要有主键。先来回顾一下存储引擎。
myisam在建表的时候对应到硬盘有几个文件(三个)?
innodb在建表的时候对应到硬盘有几个文件(两个)?frm文件只存放表结构,不可能放索引,也就意味着innodb的索引跟数据都放在idb表数据文件中。
建表文件对比:https://blog.csdn.net/weixin_44571270/article/details/106710860
特点:叶子结点放的一条条完整的记录
# 聚集索引好处
1、它对主键的排序查找和范围查找速度非常快,叶子节点的数据就是用户所要查询的数据。
2、范围查询(range query),即如果要查找主键某一范围内的数据,通过叶子节点的上层中间节点就可以得到页的范围,之后直接读取数据页即可
(2)辅助索引(unique,index)
辅助索引:查询数据的时候不可能都是用id作为筛选条件,也可能会用name,password等字段信息,那么这个时候就无法利用到聚集索引的加速查询效果。就需要给其他字段建立索引,这些索引就叫辅助索引
特点:辅助索引的叶子结点存放的是辅助索引建立的字段所在的那张表的主键的聚集索引数据块的地址
。
查找流程:当通过辅助索引查找时,先通过辅助索引,获取聚集索引,再通过聚集索引查找到相应的数据。
辅助索引又分为覆盖索引和非覆盖索引:
- 覆盖索引
下面语句叫覆盖索引:只在辅助索引的叶子节点中就已经找到了所有我们想要的数据
select name from user where name='jason';
- 非覆盖索引
下面语句叫非覆盖索引,虽然查询的时候命中了索引字段name,但是要查的是age字段,所以还需要利用聚集索引去查找!
select age from user where name='jason';
二、慢查询优化
1、查询优化神器
关于explain命令相信大家并不陌生,具体用法和字段含义可以参考官网explain-output,这里需要强调rows是核心指标,绝大部分rows小的语句执行一定很快(有例外,下面会讲到)。所以优化语句基本上都是在优化rows。
执行计划:让mysql预估执行操作(一般正确)
all < index < range < index_merge < ref_or_null < ref < eq_ref < system/const
id,email
慢:
select * from userinfo3 where name='alex'
explain select * from userinfo3 where name='alex'
type: ALL(全表扫描)
select * from userinfo3 limit 1;
快:
select * from userinfo3 where email='alex'
type: const(走索引)
2、慢查询优化的基本步骤
0.先运行看看是否真的很慢,注意设置SQL_NO_CACHE
1.where条件单表查,锁定最小返回记录表。这句话的意思是把查询语句的where都应用到表中返回的记录数最小的表开始查起,单表每个字段分别查询,看哪个字段的区分度最高
2.explain查看执行计划,是否与1预期一致(从锁定记录较少的表开始查询)
3.order by limit 形式的sql语句让排序的表优先查
4.了解业务方使用场景
5.加索引时参照建索引的几大原则
6.观察结果,不符合预期继续从0分析
3、慢日志管理
慢日志
- 执行时间 > 10
- 未命中索引
- 日志文件路径
配置:
- 内存
show variables like '%query%';
show variables like '%queries%';
set global 变量名 = 值
- 配置文件
mysqld --defaults-file='E:\wupeiqi\mysql-5.7.16-winx64\mysql-5.7.16-winx64\my-default.ini'
my.conf内容:
slow_query_log = ON
slow_query_log_file = D:/....
注意:修改配置文件之后,需要重启服务
MySQL日志管理
========================================================
错误日志: 记录 MySQL 服务器启动、关闭及运行错误等信息
二进制日志: 又称binlog日志,以二进制文件的方式记录数据库中除 SELECT 以外的操作
查询日志: 记录查询的信息
慢查询日志: 记录执行时间超过指定时间的操作
中继日志: 备库将主库的二进制日志复制到自己的中继日志中,从而在本地进行重放
通用日志: 审计哪个账号、在哪个时段、做了哪些事件
事务日志或称redo日志: 记录Innodb事务相关的如事务执行时间、检查点等
========================================================
============================ bin-log日志管理 ============================
1. 启用
# vim /etc/my.cnf
[mysqld]
log-bin[=dir\[filename]]
# service mysqld restart
2. 暂停
//仅当前会话
SET SQL_LOG_BIN=0;
SET SQL_LOG_BIN=1;
3. 查看
查看全部:
# mysqlbinlog mysql.000002
按时间:
# mysqlbinlog mysql.000002 --start-datetime="2012-12-05 10:02:56"
# mysqlbinlog mysql.000002 --stop-datetime="2012-12-05 11:02:54"
# mysqlbinlog mysql.000002 --start-datetime="2012-12-05 10:02:56" --stop-datetime="2012-12-05 11:02:54"
按字节数:
# mysqlbinlog mysql.000002 --start-position=260
# mysqlbinlog mysql.000002 --stop-position=260
# mysqlbinlog mysql.000002 --start-position=260 --stop-position=930
4. 截断bin-log(产生新的bin-log文件)
a. 重启mysql服务器
b. # mysql -uroot -p123 -e 'flush logs'
5. 删除bin-log文件
# mysql -uroot -p123 -e 'reset master'
============================ 查询日志管理 =============================
启用通用查询日志
# vim /etc/my.cnf
[mysqld]
log[=dir\[filename]]
# service mysqld restart
============================ 慢查询日志管理 ===========================
启用慢查询日志
# vim /etc/my.cnf
[mysqld]
log-slow-queries[=dir\[filename]]
long_query_time=n
# service mysqld restart
MySQL 5.6:
slow-query-log=1
slow-query-log-file=slow.log
long_query_time=3
查看慢查询日志
测试:BENCHMARK(count,expr)
SELECT BENCHMARK(50000000,2*3);