事务

事务是逻辑上的一组操作,要么都执行,要么都不执行。

数据库的事务特性 ACID :

  1. 原子性:事务是最小的执行单位,不允许分割。事务的原子性确保动作要么全部完成,要么完全不起作用;
  2. 一致性:执行事务前后,数据保持一致,例如转账业务中,无论事务是否成功,转账者和收款人的总额应该是不变的;
  3. 隔离性:并发访问数据库时,一个用户的事务不被其他事务所干扰,各并发事务之间的数据库是独立的;
  4. 持久性:一个事务被提交之后,它对数据库中的数据的改变是持久的,也就是说数据库发生故障也不该对其有任何影响。

并发事务导致的问题

  • 脏读:一个事物读取到另外一个事物还未提交的数据。
  • 不可重复读:一个事物先后读取同一条记录,但两次读取的数据不同,称之为不可重复读。
  • 幻读:一个事物按照条件查询数据时,没有对应的数据行,但是在插入数据时又发现这行数据已经存在了,好像出现了”幻影“,称之为幻读。

事务的隔离级别:

  • READ-UNCOMMITTED(读取未提交):最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读和不可重复读
  • READ-COMMITTED(读取已提交):允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读和不可重复读仍有可能发生
  • REPEATABLE-READ(可重复读):对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生这是InnoDB引擎默认的隔离级别
  • SERIALIZABLE(可串行化):最高的隔离级别,完全服从 ACID 的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读、幻读
  • MySql InnoDB引擎通过 redo log(重做日志)保证事务的持久性,使用 undo log(回滚日志) 来保证事务的原子性
  • MySql InnoDB 引擎通过锁机制、MVCC 等手段来保证事务的隔离性(默认支持的隔离级别是 REPEATABLE-READ 可重复读)。
  • 保证了事务的持久性、原子性、隔离性之后,一致性才能得到保障。

锁级别和机制

  • InnoDB 支持行级锁和表级锁,默认为行级锁

行级锁和表级锁的对比:

  • 表级锁: MySql 中锁定粒度最大的一种锁,对当前操作的整张表加锁,实现简单,资源消耗也比较少,加锁快,不会出现死锁。其锁定粒度最大,触发锁冲突的概率最高,并发度最低,MyISAM 和 InnoDB 引擎都支持表级锁。
  • 行级锁: MySql 中锁定 粒度最小 的一种锁,只针对当前操作的行进行加锁。行级锁能大大减少数据库操作的冲突。其加锁粒度最小,并发度高,但加锁的开销也最大,加锁慢,会出现死锁。

数据库设计的三大范式

  • 第一范式:确保每列保持原子性,每列都不可以再分
  • 第二范式:确保表中每列都和主键相关
  • 第三范式:确保每列都和主键列直接相关,而不是间接相关

索引

什么是索引

  • 索引是帮助MySQL高效获取数据的数据结构(有序)
  • 提高数据检索的效率,降低数据库的IO成本(不需要全表扫描)
  • 通过索引列对数据进行排序,降低数据排序的成本,降低了CPU的消耗

在mysql的默认存储引擎InnoDB中,使用的B+树来实现索引的,B+树类似B树,也是一个多阶的树,不过它的非叶子结点不存储数据,只存储指针,叶子结点才存储数据,并且叶子结点之间还有双向循环链表。这些特点使得B+树相比于B树:1、查询效率更加稳定、2、B+树便于扫库和区间查询。

image.png

聚簇索引和非聚簇索引

  • 聚簇索引(聚集索引):数据和索引放到一块,B+树的叶子结点保存了整行数据,有且只有一个,一般是主健索引
  • 非聚簇索引(二级索引):数据和索引分开存储,B+树的叶子结点保存对应的主键,可以有多个

回表查询

通过二级索引找到对应的主键值,再到聚集索引中查找整行数据,这个过程就是回表

覆盖索引

覆盖索引是指查询使用了索引,并且需要返回到列,在该索引中已经全部能够找到。也就是说只需要查询一次,不需要去回表查询。

慢SQL

如何定位慢查询?

我们当时经常碰到这种满查询的情况,因为我们的系统是发展了20多年,里面的数据量很大,比如有几十个模块,每个模块下都有几十上百个元数据以及对应的应用。每个应用里面可能都有几十个字段。系统内有个录制spr的功能,它会录制你在某段时间内所有发出的请求、执行的sql、报错的堆栈,这里面执行的sql后面就有时间,可以很直观的看到这条sql所用的时间,接着就可以把这条sql复制下来看看是哪方面的问题了。

如果没有这个spr工具的话,也可以通过部署Arthas(阿尔萨斯)Prometheus(普罗米修斯)Skywalking这些工具来查看。

还可以通过mysql的慢日志工具查询,以及数据库连接池比如Druid(德鲁伊) 这种,也都有慢sql的记录

如何分析慢查询sql语句?

在我之前工作中有一套规范,比如不要用select *、不要在in后面加太多,如果太多就用一个子句、不要在代码的循环中查sql。通过遵守这些规范就可以避免部分sql层面带来的性能问题。

其次就是使用好explain工具。里面的key可以判断出该语句有没有命中索引,还有extra字段,额外的优化建议,type是sql的连接类型,避免是index(全索引扫描)和all(全盘扫描)

最后修改:2024 年 04 月 08 日
如果觉得我的文章对你有用,请随意赞赏