mysql常用存储引擎
常用的有两种:innodb,myisam
innerdb支持64tb的存储,myisam支持256tb
myisam不支持外键和事务
innodb:支持行锁和表锁,仅对修改的数据行加锁,适用于事务,高并发写入
myisam:支持表级锁,读写锁整张表,适用于只读
mysql的索引
索引的底层结构:常用的是B+树,还有hash和跳表
B+树:叶子节点(聚簇索引:存储完整数据innnodb)/(非聚簇索引:存储数据地址myisam)
叶子节点通过双向链表连接,支持范围查找(通过叶子节点快速遍历),支持排序(索引本身有序)
hash:支持等值查询
跳表:支持范围查找和排序,效率高于b+树
索引:主要用来优化查询,减少磁盘i/o,
单表:主键(非空唯一),唯一,普通(无特定要求),全文索引(作用域char,vachar,text)
组合:遵循最左前缀原则
聚簇索引(通过索引直接找到对应的数据行,无需回表), 主键
一张表只能有一个聚簇索引,一般是主键,因为物理存储顺序唯一,
非聚簇索引(通过索引找到的是对应数据的地址)唯一,普通,联合
B树 存储的完整数据,树比较高,在数据比较少的情况下,不需要回表,但是数据量大的话,io开销比较大
什么是回表查询,什么是覆盖索引
- 回表查询:需要通过二级索引找到主键后,再查主键索引获取完整数据,性能相对较低。
- 覆盖索引:查询字段都在索引中,无需回表,性能更优。(目录中包含了所需要查找的内容,就是目录中包含部分信息,非聚簇索引是只有目录),实际上覆盖索引就是非聚簇索引,仍然会通过覆盖索引查找到聚簇索引,再查询到需要的数据行,因此覆盖索引不需要添加聚簇索引(降低效率)例如:id name age(三个字段) 变成联合索引只需要name和age ,id就不用加入了
- 举例子
- sql
SELECT order_no, amount FROM orders WHERE user_id = 10086;
不使用覆盖索引的情况:
- 数据库会先通过
idx_user_id
索引找到所有user_id=10086
的记录,得到这些记录的主键id
- 然后需要回表到主键索引中,才能获取
order_no
和amount
字段的值 - 这会产生两次索引查找,性能相对较低
使用覆盖索引的优化:
创建包含查询所需所有字段的复合索引:
CREATE INDEX idx_user_order_info ON orders (user_id, order_no, amount);
此时再执行相同查询:
- 数据库直接在
idx_user_order_info
索引中就能找到user_id=10086
对应的order_no
和amount
- 索引本身已经包含了查询需要的所有字段(筛选条件
user_id
和查询结果order_no
、amount
) - 不需要回表操作,一次索引查询就能完成,大大提升查询效率
三个共同构建索引
业务先行,索引后到(根据优化情况来创建,比如慢sql等等。。)
什么是左前缀原则
联合索引在 B+ 树中按列顺序排序:先按 a 排序, a 相同的记录再按 b 排序, a 和 b 都相同的再按 c 排序(即 a 是第一排序键, b 是第二排序键, c 是第三排序键)。
本质上就是一层层排序,因此只有按顺序才能是索引成功,增强查找效率,如果不按照顺序的话,就要全表查询(因为索引的本质是B+树相对有序的,因此构建联合索引就相当于进行一次排序,)
什么情况下索引会失效[重点]
违反左前缀原则
进行函数的处理或者加减乘除运算count(索引列)avg索引列不算substr截取会导致失效
隐式转换
使用!=本质上也属于一种范围式查找号
范围查询
模糊查询前用%
or链接的列存在非索引列
可以通过explain命令分析查看type列是否为all来判断是否失效,查看key的命中率
mysql的性能优化[重点]
表设计的优化,根据实际情况选择合适的类型参考阿里规范(比如设置数据库字段对应的类型,采用tinyint还是int还是bigint,对应的char和vachar的大小,设定等等)
sql优化:
比如使用select时尽量指明字段避免使用select*,
注意避免索引失效
联合查询尽量使用union all 代替union, union会多一次过滤,去除重复行,效率低
如果表关联的话,尽量使用 innerjoin 不要使用left 或者rigt必须使用则尽量要以小表为驱动,因为驱动表是全量遍历,被驱动表是根据条件筛选的
主从复制,读写分离,不让数据的写入影响读操作
分库分表,水平拆分(解决数据量问题),和垂直拆分(数据库字段过多的问题)
如何定位慢查询[重点]
调试工具:skywalking arthas
mysql的自带慢日志,默认未开启
一个SQL语句执行很慢, 如何分析 [重点]
在查询语句前添加explain,通过key和keylen来判断索引命中情况
或通过type的值是all来判断是否是全表扫描通过
extra判断是否出现回表
同时sql语句很慢一般分为
暂时慢:需监控运行时状态,排查并发、锁、后台任务等临时干扰因素,减少环境波动影响
一直慢:优化sql语句