赞
踩
聚合查询
多表查询
表数据量过大查询
深度分页查询
方案一、开源工具
方案二、MySQL自带慢日志
在MySQL配置文件 /etc/my.conf
中配置:
- # 开启MySQL慢日志开关
- slow_query_log=ON
- # 设置慢日志时间2秒,超过2秒的SQL语句会被认为是慢查询,记录慢查询日志
- long_query_time=2
- # 慢日志记录文件
- slow_query_log_file =/var/lib/mysql/localhost-slow.log
重启MySQL服务器,后续可在对应日志文件中查看慢日志信息。
其中,聚合查询、多表查询、数据量过大的情况,均可以使用SQL执行计划分析,进行优化。使用MySQL自带命令 explain 或 desc :
EXPLAIN/DESC + 原SQL语句
字段含义
Q:某条SQL查询很慢,如何分析?
A:可以使用MySQL自带分析工具EXPLAIN。
- 通过key和key_len检查是否命中了索引(索引本身存在是否有失效的情况)
- 通过type字段查看sql是否有进一步的优化空间,是否存在全索引扫描或全盘扫描
- 通过extra建议判断,是否出现了回表的情况,如果出现了,可以尝试添加索引或修改返回字段来修复
存储引擎是存储数据、建立索引、更新/查询数据等技术的实现方式。存储引擎基于表,而非基于数据库。
# 特性 | MyISAM | InnoDB | MEMORY |
---|---|---|---|
事务 | × | ✔ | × |
锁机制 | 表锁 | 表锁、行锁 | 表锁 |
外键 | × | ✔ | × |
在mysql中提供了很多的存储引擎,比较常见有InnoDB、MyISAM、Memory
索引(index)是帮助MySQL高效获取数据的数据结构(有序)。在数据之外,数据库系统还维护着满足特定查找算法的数据结构(B+树),这些数据结构以某种方式指向数据, 这样就可以在这些数据结构上实现高级查找算法,这种数据结构就是索引。
MySQL的InnoDB引擎采用的B+树的数据结构来存储索引
B树与B+树对比:
①:磁盘读写代价B+树更低;②:查询效率B+树更加稳定;③:B+树便于扫库和区间查询
聚簇索引,数据存储和索引在一块,索引结构的叶子节点保存了行数据。聚簇索引在每张表中都有且仅有一个。
非聚簇索引(二级索引),将数据与索引分开存储,叶子节点关联的内容为对应的主键。一张表可以有多个二级索引。
聚集索引选取规则:
回表查询:通过二级索引找到对应的主键,然后根据主键值通过聚簇索引找到对应的行数据,这个查找的过程称为回表。
覆盖索引:指查询使用了索引,并且需要返回的列,在该索引中已经全部能够找到 。
# 超大分页问题处理,
数据量较大的情况,使用 limit 分页查询,查询越靠后,查询效率越低。
优化思路:一般分页查询时,通过创建 覆盖索引 能够比较好地提高性能,可以通过 覆盖索引 + 子查询 的形式进行优化。
- select * from tb_sku t,
- (select id from tb_sku order by id limit 90000,10) a
- where t.id = a.id;
Q:超大分页怎么处理?
A:超大分页一般在数据量较大时,使用了limit分页查询,且需要对数据进行排序。这种情况下查询的效率就会比较低,可以采用覆盖索引和子查询解决。
首先,分页查询数据的主键id字段,然后用子查询来过滤,只需要查询这个id列表中的数据即可。因为查询id的时候走的是覆盖索引,所以效率会提升。
依次考虑:主键索引、唯一索引、复合索引(根据业务情况创建);
原则:
explain 命令,例:
假设我们在student表中有一个联合索引“idx_age_name_grade (name,age, grade)”
- explain select * from student where name = "zhangsan" and age = 20 and grade = 3;
- explain select * from student where name = "zhangsan" grade = 3;
- explain select * from student where age = 20 and grade = 3;
可以通过对比上述语句的输出内容,key 、 key_len ...,查看索引的使用情况。
注意:联合索引的情况,如果只是查询条件里的查询顺序和索引定义的顺序不同,不影响走索引。索引优化器会对查询条件进行优化,即进行重新排序。
涉及方面:
主从复制的核心为二级制日志。二进制日志(BINLOG)记录了所有的 DDL(数据定义语言)语句和 DML(数据操纵语言)语句,但不包括数据查询(SELECT、SHOW)语句。
DDL,数据定义语言,表创建语句 create table ...
DML,数据操作语言,insert、update、delete
主从复制流程:
【分库分表的时机】:
垂直拆分:垂直分库,垂直分表;
水平拆分:水平分库,水平分表。
【垂直分库】
以表为依据,根据业务将表拆分到不同的库中。
例如,将用户信息相关的表和订单相关的表分别放到不同的库中。
特点:
【垂直分表】
以字段为依据,根据字段属性将不同字段拆分到不同表中。
例如,将商品的id、名称等放到一张表;详细描述信息等放到另外一张表。用户查看详情时,对应点击页面详情按钮,再查询详细描述等信息。
特点:
【水平分库】
将一个库的数据拆分到多个库中。
特点:
路由规则:
【水平分表】
将一个表的数据拆分到多个表中(可以在同一个库内)。
特点:
水平分库之后的问题:
分库分表中间件:
Q:项目用过分库分表吗
A:
业务介绍:
1,数据量较大业务(请求数多或业务累积大);
2,达到了什么样的量级(单表1000万或超过20GB)。
拆分策略介绍:
1,水平分库,将一个库的数据拆分到多个库中,解决海量数据存储和高并发的问题;
2,水平分表,解决单表存储和性能的问题;
3,垂直分库,根据业务进行拆分,高并发下提高磁盘IO和网络连接数;
4,垂直分表,冷热数据分离,多表互不影响。
注:水平分库 及 水平分表,涉及中间件 sharding-sphere、mycat
事务是一组操作的集合,它是一个不可分割的工作单位,事务会把所有的操作作为一个整体一起向系统提交或撤销操作请求,即这些操作要么同时成功,要么同时失败。
例:A向B操作转账100元,
原子性:A扣除100,B增加100,要么都成功要么都失败;
一致性:数据在事务执行前后一致(转账前后),A扣除了100,B必须增加100;
隔离性:A向B转账,不受其他事务的影响;
持久性:事务提价后,需要将数据持久化(落盘操作)。
脏读、不可重复读、幻读
解决并发事务问题的方案:对事务进行隔离。
1)READ UNCOMMITTED(读未提交)
事务中最低的级别,该级别下的事务可以读取到另一个事务中未提交的数据,也被称为脏读( Dirty Read)。
2)READ COMMITTED(读提交)
大多数数据库管理系统的默认隔离级别,例如Oracle。
该级别下,事务只能读其他事务已经提交的内容,可以避免脏读,但不能避免重复读、幻读的情况。
3)REPEATABLE READ(可重复读)
MySQL默认的事务隔离级别,可以避免脏读、不可重复读的问题,确保同一个事务的多个实例在开发并发读取数据时,会看到同样的数据行。该级别在理论上会出现幻读的情况,但MySQL的存储引擎通过多版本并发控制(MVCC)解决了该问题。
4)SERIALIZABLE(串行化)
事务的最高隔离级别,强制对事务进行排序,使事务之间不会发生冲突,从而解决脏读、幻读、重复读的问题。事务串行执行,效率较低,一般不采用。
事务的隔离级别越高,数据约安全,但同时性能也越低。
# 隔离级别 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|
未提交读 | ✔ | ✔ | ✔ |
读已提交 | / | ✔ | ✔ |
可重复读 | / | / | ✔ |
串行化 | / | / | / |
数据写入过程:
redo log 包括两个部分,一是内存中的重做日志缓冲(redo log buffer),这部分是易失性的;二是磁盘上的重做日志文件(redo log file),该部分日志是持久的。
当事务提交之后会把所有修改信息都存到该日志文件中,用于在刷新脏页到磁盘异常时,做数据恢复使用。从而实现数据的持久性(Durability)。
回滚日志,记录的内容为数据被修改前的信息(所需的操作),作用包括:提供回滚和MCC的功能支持。redo log 记录的为物理日志;undo log 记录的为逻辑日志,即,用来回滚记录到某个版本的日志。
例如,对某条数据执行了delete操作,undo log中就会记录恢复删除操作前的数据状态相对应的insert语句。
undo log 可以实现事务的一致性和原子性。
在 insert、update、delete 的时候会产生数据回滚的日志,
事务隔离性的保证:
排他锁 + MVCC(多版本并发控制)。
排他锁:如果一个事务获取了一个数据行的排他锁,其他事务就不能获取该行的其他锁(包括排他锁)。
MVCC多版本并发控制(Multi-Version Concurrency Control)
维护一个数据的多个版本,使得读写操作没有冲突。MVCC的具体实现,主要依赖于数据库记录中的隐式字段、undo log日志、readView。
示例假定,事务2 的ID为2,记录的undo log 日志版本号为 "0x00001";事务3、事务4、事务5 类似。开启事务,分别执行不同的操作,表格水平位置前后,代表执行时间的前后关系。
ReadView(读视图)是 快照读 SQL执行时MVCC提取数据的依据,记录并维护系统当前活跃的事务(未提交的)id。
当前读:读取的是记录的最新版本,读取时需要保证其他并发事务不能修改当前记录,会对读取的记录进行加锁。例如:select ... lock in share mode(共享锁),select ... for update、update、insert、delete(排他锁)都属于当前读。
快照读:
简单的select(不加锁)操作就是快照读,读取的是记录数据的可见版本,有可能是历史数据,不加锁,是非阻塞读。
【ReadView】的4个关键属性:
【版本链数据访问规则】:
trx_id,代表待判断是否可访问的事务的事务ID。
①. trx_id == creator_trx_id ? 可以访问该版本。对应为当前事务。
②. trx_id < min_trx_id ? 可以访问该版本。说明该事务在当前事务开启前已提交。
③. trx_id > max_trx_id ? 不可以访问该版本。说明该事务在当前事务【ReadView】生成后才开启。
④. min_trx_id <= trx_id <= max_trx_id ? 如果trx_id不在m_ids中,说明该事务已提交,是可以访问该版本的。否则,不可访问。
具体实现:Undo 版本链 + ReadView 机制
(1)当前事务只读的情况:
查询操作获取的为 undo 版本链上的一个快照版本,称为“快照读”或“一致性非锁定读”。
在可重复读(Repeatable Read)隔离级别下,只在第一次查询时生成了一个 ReadView,之后的查询都复用这个 ReadView。别的事务未提交、已提交、新插入的修改都读取不到,从而解决了脏读、不可重复读、幻读的可能问题。
(2)当前事务涉及修改的情况:
执行“Insert、Delete、Update”操作,能够读取到别的事务已经提交的修改,为“当前读”。
参考内容:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。