MySQL8数据库高级特性
七、事务(Transaction)
特性
-
一组 SQL操作,要么全部成功,要么全部失败
-
用于保证数据的一致性和完整性
-
支持提交(COMMIT)和回滚(ROLLBACK)
ACID属性(必须背会)
-
原子性(Atomicity): 事务被视为最小的不可分割的工作单位,只有事务中所有操作都完成,事务才算成功。如果事务中的任一操作失败,那么整个事务也会失败并且系统会自动撤销或回滚事务的所有操作,保持数据的一致性。
-
一致性(Consistency): 事务必须保证它在不破坏数据库的完整性和约束的前提下执行。在事务开始之前和结束之后,数据库必须保持一致状态。
-
隔离性(Isolation): 事务在提交之前,对其它事务是不可见的。这是为了防止多个并发事务相互干扰。依赖于隔离级别,事务可能会"看到"其他并非提交的事务所做的改动,反之亦然。MySQL提供不同的隔离级别如READ UNCOMMITTED, READ COMMITTED, REPEATABLE READ (默认的隔离级别), 和SERIALIZABLE。
-
持久性(Durability): 一旦事务提交,其所做的改动就会被永久保存在数据库中,即使数据库系统发生故障也不会丢失这些改动。
开始事务
bash
START TRANSACTION;
执行事务中的操作例如插入、更新:
bash
INSERT INTO users (username) VALUES ('john_doe');
UPDATE orders SET user_id = LAST_INSERT_ID() WHERE order_id = 123;
提交事务
bash
COMMIT;
回滚事务
bash
ROLLBACK;
事务编写案例
银行账户转账
创建数据库
bash
CREATE DATABASE bank;
创建数据表
bash
CREATE TABLE accounts (
account_number INT PRIMARY KEY,
account_name VARCHAR(100),
balance DECIMAL(15, 2) -- 保留两位小数的余额
);
逻辑分析
-
首先,开始一个新的事务。
-
检查源账户的余额是否足够进行转账。
-
从源账户扣除转账金额。
-
向目的账户添加转账金额。
如果所有步骤都成功,则提交事务;如果有任何一步失败,则回滚事务以撤销所有更改。
编写脚本
bash
-- 修改结束符号
DELIMITER //
CREATE PROCEDURE TransferFunds()
BEGIN
START TRANSACTION;
-- 关闭自动提交
SET autocommit=0;
-- 源账户相关信息
SET @sourceAccountNumber = 1001;
SET @transferAmount = 101;
-- 目标账户相关信息
SET @destinationAccountNumber = 1002;
-- 检查源账户的余额是否充足
SELECT @sourceBalance := balance as 源账户余额 FROM accounts WHERE account_number = @sourceAccountNumber;
IF @sourceBalance < @transferAmount THEN
-- 余额不足,回滚事务
ROLLBACK;
-- 使用SIGNAL语句生成一个错误
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '余额不足';
-- 退出存储过程
else
-- 扣除源账户金额
UPDATE accounts SET balance = balance - @transferAmount WHERE account_number = @sourceAccountNumber;
-- 增加目的账户金额
UPDATE accounts SET balance = balance + @transferAmount WHERE account_number = @destinationAccountNumber;
select * from accounts where account_number = @sourceAccountNumber;
-- 提交事务
COMMIT;
END IF;
END //
-- 修改结束符号为;
DELIMITER ;
调用事务
bash
call TransferFunds();
事务的隔离级别
-
读未提交(READ UNCOMMITTED)
-
这是最低的隔离级别,在该级别下,一个事务可以读取到另一个未提交事务的数据,可能会导致脏读、不可重复读和幻读等问题。脏读是指一个事务读取到了另一个未提交事务修改的数据,而这些数据可能在后续被回滚,从而导致读取的数据不准确。
-
例如,事务 A 修改了一条数据但尚未提交,事务 B 在此时读取了该数据,之后事务 A 回滚了修改,那么事务 B 所读取的数据就是脏数据。
-
-
读已提交(READ COMMITTED)
-
在这个隔离级别下,一个事务只能读取到另一个已提交事务的数据,可以避免脏读问题,但仍可能出现不可重复读的情况。不可重复读是指在一个事务中,多次读取同一数据时,由于其他事务对该数据进行了修改并提交,导致每次读取的结果都不一样。
-
比如,事务 A 在第一次读取某数据后,事务 B 对该数据进行了修改并提交,事务 A 再次读取该数据时,就会得到不同的结果。
-
-
可重复读(REPEATABLE READ)
-
这是 MySQL 8 默认的隔离级别,它确保在同一个事务中,对同一数据的多次读取结果是相同的,可以避免脏读和不可重复读问题,但可能会出现幻读现象。幻读是指在一个事务中,按照某个条件进行数据查询时,多次查询的结果可能不同,因为其他事务可能插入了满足该条件的新数据。
-
例如,事务 A 按照某个条件查询数据时没有找到某条记录,而在事务 A 执行期间,事务 B 插入了一条满足该条件的新记录,当事务 A 再次按照相同条件查询时,就会发现多了一条之前没有的记录,就像出现了幻觉一样。
-
-
串行化(SERIALIZABLE)
-
这是最高的隔离级别,它通过强制事务串行执行,避免了脏读、不可重复读和幻读等所有并发问题,但会严重影响系统的性能,因为它限制了并发事务的执行。在这种隔离级别下,所有事务都按照顺序依次执行,就像排队一样,一个事务执行完了,下一个事务才能开始执行。
-
比如,有多个事务需要访问同一个数据库资源,在串行化隔离级别下,这些事务会依次排队等待执行,而不会出现并发执行的情况。
-
事务的应用场景
-
金融交易
-
如银行转账、股票交易等场景,必须保证资金的转移和交易操作的原子性、一致性、隔离性和持久性,以确保金融数据的准确无误和交易的安全可靠。
-
例如,在银行转账时,从一个账户转出资金和转入另一个账户的操作必须作为一个事务来处理,以防止出现资金丢失或错误转移的情况。
-
-
订单处理
-
在电商或其他涉及订单管理的系统中,订单的创建、商品库存的调整、客户支付等多个操作需要作为一个事务来统一处理,以保证订单数据的完整性和业务流程的正确性。
-
比如,当用户提交订单时,系统需要同时处理订单记录的创建、库存数量的减少以及支付信息的处理等操作,如果其中任何一个环节出现问题,整个订单处理事务就应该回滚,以避免出现数据不一致的情况。
-
-
数据更新与一致性维护
-
当需要对多个相关联的数据表进行更新操作时,为了保证数据的一致性和完整性,需要使用事务。
-
例如,在一个企业资源管理系统中,当修改员工所属部门时,不仅要更新员工表中的部门信息,还要同时更新与该部门相关的其他数据表,如部门预算表、部门人员统计表等,这些操作需要在一个事务中完成,以确保系统中各数据的一致性。
-
八、锁(Lock)(了解)
特性
在 MySQL 8 中,锁是用于控制多个并发事务对数据库资源访问的一种机制,它可以确保数据的一致性和完整性,防止数据被错误地修改或读取。
锁的类型
-
按锁的粒度划分
-
表锁(Table Lock)
-
表锁是对整个数据表加锁,它锁住的是整个表资源。当一个事务对表加了表锁后,其他事务对该表的读写操作都将被阻塞,直到锁被释放。
-
例如,在执行一些对整张表进行操作的语句,如
ALTER TABLE、DROP TABLE时,MySQL 会自动对表加上表锁。同时,也可以通过LOCK TABLES语句显式地对表加表锁,如LOCK TABLES my_table READ;表示对my_table表加读表锁,只允许对该表进行读操作;LOCK TABLES my_table WRITE;表示对my_table表加写表锁,不允许其他事务对该表进行读写操作。
-
-
行锁(Row Lock)
-
行锁是对表中的某一行数据加锁,它的粒度更细,只锁住被操作的行数据。这样可以在并发访问时,允许不同事务对同一表中的不同行进行并发操作,提高了数据库的并发性能。
-
例如,在使用
SELECT... FOR UPDATE或UPDATE、DELETE等语句操作数据时,MySQL 会自动对涉及的行加上行锁。假设在一个员工信息表中,事务 A 要更新某一行员工的工资信息,那么它会对该行加上行锁,此时其他事务如果也要更新该行数据或者对该行进行与锁类型不兼容的操作,就需要等待事务 A 释放行锁。
-
-
间隙锁(Gap Lock)
-
间隙锁是一种特殊的锁,它锁定的是索引记录之间的间隙,而不是具体的某一行数据。间隙锁主要用于防止在并发操作时,其他事务在锁定的间隙中插入新的数据,从而导致幻读问题。
-
例如,在一个有序的整数列索引的表中,如果事务 A 对某一区间的索引值加了间隙锁,那么其他事务就不能在这个区间内插入新的数据,即使这些新数据与已存在的数据行并不冲突,但由于它们处于被锁定的间隙中,也无法插入。
-
-
-
按锁的性质划分
-
共享锁(Shared Lock)
-
共享锁又称为读锁,多个事务可以同时对同一数据资源加上共享锁,以实现对数据的并发读操作。当一个数据资源上有共享锁时,其他事务可以继续对其加共享锁,但不能加排它锁,直到所有的共享锁都被释放。
-
例如,使用
SELECT... LOCK IN SHARE MODE语句对数据进行查询时,会对查询的结果集加上共享锁。这样可以保证多个事务在同一时间都能读取到相同的数据,而不会因为其他事务的写操作而导致数据不一致。
-
-
排它锁(Exclusive Lock)
-
排它锁又称为写锁,当一个事务对数据资源加上排它锁后,其他事务既不能对其加共享锁,也不能加排它锁,直到该排它锁被释放。排它锁用于对数据进行写操作时,保证只有一个事务能对数据进行修改。
-
例如,在执行
UPDATE、DELETE或SELECT... FOR UPDATE等语句时,会对涉及的数据加上排它锁。如果事务 A 对某一行数据加上了排它锁,那么事务 B 想要对同一行数据进行读或写操作时,就需要等待事务 A 释放排它锁。
-
-
锁的使用场景
-
并发控制
- 在多用户并发访问数据库的环境中,为了避免数据的不一致性和冲突,需要使用锁来控制并发访问。例如,在一个在线票务系统中,多个用户可能同时尝试预订同一航班的机票,通过对机票库存表的行锁,可以确保每个用户的预订操作是原子性的,不会出现超售的情况。
-
数据完整性维护
- 锁可以防止在对数据进行修改时,其他事务的干扰,从而保证数据的完整性。比如,在一个银行账户管理系统中,当对一个账户进行取款操作时,通过对该账户所在行加排它锁,可以确保在取款操作完成之前,其他事务不能对该账户进行修改,避免了数据错误和不一致的情况。
-
事务隔离实现
- 不同的事务隔离级别在一定程度上是通过锁来实现的。例如,在可重复读隔离级别下,MySQL 使用行锁和间隙锁的组合来防止幻读问题,确保在同一事务中对同一数据的多次读取结果是一致的。
锁的并发问题及解决方法
-
死锁
-
问题描述:死锁是指两个或多个事务在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。例如,事务 A 对资源 1 加了锁,同时需要获取资源 2;而事务 B 对资源 2 加了锁,同时需要获取资源 1,这样就导致了两个事务互相等待,形成死锁。
-
解决方法:MySQL 本身有一些机制来检测和处理死锁,当检测到死锁时,会自动选择一个事务进行回滚,以打破死锁状态。此外,在编写事务时,尽量按照相同的顺序获取锁,避免交叉加锁,也可以减少死锁的发生概率。
-
-
锁等待超时
-
问题描述:当一个事务等待获取锁的时间超过了系统设定的超时时间,就会出现锁等待超时的问题,事务会被自动回滚。这可能是由于并发事务过多,导致某些事务长时间等待获取锁而无法执行。
-
解决方法:可以通过调整系统参数来增加锁等待超时的时间,但这并不是根本的解决方法。更好的方式是优化事务的执行逻辑,尽量减少事务的执行时间和锁的持有时间,提高系统的并发性能。
-
九、数据库引擎
类型
-
InnoDB:支持事务处理和行级锁定,适用于高并发和多表关联查询的应用。
-
MyISAM:不支持事务处理,适用于读密集型应用。
-
Memory:将数据存储在内存中,适用于需要快速读写的临时数据和缓存。
-
NDB (Cluster):支持分布式存储和高可用性,适用于大规模的分布式系统。
-
Archive:只支持插入和压缩,适用于存储大量历史数据。
-
CSV:将数据存储为CSV文件,适用于导入导出数据。
-
Blackhole:从写入的数据中丢弃数据,适用于日志传输。
常用引擎概述
InnoDB
-
存储结构
-
InnoDB 采用表空间的形式来存储数据,它将数据存储在一个或多个表空间文件中。表空间可以包含多个表的数据和索引,这种存储方式有利于数据的管理和维护。
-
例如,一个数据库中的多个表可以共享同一个表空间,也可以为每个表指定单独的表空间,方便对不同表的数据进行独立的存储和管理。
-
-
事务支持
-
InnoDB 是 MySQL 8 中默认的事务型数据库引擎,它提供了完整的 ACID 事务支持。通过使用事务日志和锁机制,确保了数据的一致性和完整性。
-
比如,在银行转账业务中,从一个账户转出资金和转入另一个账户的操作可以放在一个 InnoDB 事务中,如果其中一个操作失败,整个事务可以回滚,保证资金数据的准确性。
-
-
并发控制
-
支持行级锁,通过对每行数据加锁,允许多个并发事务同时访问不同行的数据,提高了数据库的并发性能。同时,它还使用了多版本并发控制(MVCC)技术,减少了锁冲突,进一步提升了并发处理能力。
-
例如,在一个电商系统中,多个用户同时对不同商品进行下单操作,InnoDB 可以通过行级锁和 MVCC 技术,确保每个用户的操作都能并发执行,而不会相互干扰。
-
-
索引类型
-
支持多种索引类型,包括 B + 树索引、全文索引等。B + 树索引是最常用的索引类型,它具有高效的查找性能,适合用于各种查询场景。
-
例如,在一个包含大量文章的博客系统中,使用 B + 树索引可以快速地根据文章标题、作者等字段查找文章,提高系统的查询速度。
-
MyISAM
-
存储结构
-
MyISAM 把数据和索引分别存储在不同的文件中,数据文件的扩展名为
.MYD,索引文件的扩展名为.MYI。这种存储结构使得数据和索引的管理相对简单,但在某些情况下可能会导致性能问题。 -
比如,当数据量较大时,频繁的查询可能需要同时读取数据文件和索引文件,增加了磁盘 I/O 操作,从而影响查询速度。
-
-
事务支持
-
MyISAM 不支持事务,它不能保证数据的一致性和完整性在复杂的业务场景下。如果在执行一系列操作时中途出现错误,无法像 InnoDB 那样进行回滚操作。
-
例如,在一个订单处理系统中,如果使用 MyISAM 引擎,当订单创建和库存更新操作同时进行时,若库存更新失败,无法自动回滚订单创建操作,可能会导致数据不一致。
-
-
并发控制
-
只支持表级锁,当一个事务对表进行操作时,会锁住整个表,这在并发度较高的场景下可能会导致性能瓶颈,因为其他事务需要等待锁的释放才能对该表进行操作。
-
例如,在一个多用户的论坛系统中,如果使用 MyISAM 引擎,当一个用户在修改帖子时,其他用户对该帖子所在的表进行的任何操作都需要等待,降低了系统的并发性能。
-
-
索引类型
-
同样支持 B + 树索引,能够快速地根据索引字段查找数据。此外,还支持全文索引,适合用于对文本数据进行全文搜索的场景。
-
例如,在一个新闻网站中,使用全文索引可以快速地搜索到包含特定关键词的新闻文章,提高搜索效率。
-
Memory
-
存储结构
-
Memory 引擎把数据存储在内存中,数据的处理速度非常快,但由于内存的易失性,一旦服务器关闭或出现故障,数据就会丢失。
-
例如,在一些需要临时存储数据且对性能要求极高的场景中,如缓存系统,可以使用 Memory 引擎存储临时数据,以提高数据的访问速度。
-
-
事务支持
-
一般情况下不支持完整的事务处理,虽然可以通过一些特殊的设置和技巧实现有限的事务功能,但不具备 InnoDB 那样完善的事务支持。
-
比如,在一个简单的计数器应用中,使用 Memory 引擎存储计数数据,若不要求严格的事务处理,它可以快速地进行计数操作,但无法保证在复杂情况下数据的绝对准确。
-
-
并发控制
-
支持表级锁,并发性能相对较差,但由于数据存储在内存中,整体的读写速度较快,在一定程度上可以弥补并发性能的不足。
-
例如,在一个小型的在线游戏中,用于存储游戏中的一些临时状态数据,虽然使用表级锁,但由于数据量小且存储在内存中,对游戏的实时性影响不大。
-
-
索引类型
-
支持哈希索引和 B + 树索引,哈希索引在等值查询时具有非常高的效率,适合用于快速查找特定值的场景。
-
例如,在一个用户登录系统中,使用哈希索引可以快速地根据用户名查找用户密码,提高登录验证的速度。
-
查看
查看支持的引擎
bash
SHOW ENGINES;
查看某个具体表所使用的数据库引擎
bash
SHOW CREATE TABLE mytable;
########################
SELECT TABLE_SCHEMA AS Database,
TABLE_NAME AS Table,
ENGINE
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA = 'bank';
配置
在MySQL配置文件中(通常是my.cnf或my.ini),可以通过设置以下参数来配置引擎:
| 配置项 | 作用 |
|---|---|
| default-storage-engine | 指定默认的存储引擎。 |
| innodb_buffer_pool_size | 设置InnoDB的缓冲池大小。 |
| key_buffer_size | 设置MyISAM的索引缓冲区大小。 |
| innodb_file_per_table | 每个InnoDB表创建一个独立的表空间文件。 |
| innodb_flush_log_at_trx_commit | 设置InnoDB事务提交时的日志刷新策略。 |
常见配置字段:
缓冲池相关
-
innodb_buffer_pool_size :缓冲池大小,用于缓存表数据和索引,默认值根据服务器内存自动调整,通常是 128M 左右。合理设置可减少磁盘 I/O,提升性能,如可设置为服务器内存的 70%-80%(需根据实际情况调整),示例:
innodb_buffer_pool_size = 4G。 -
innodb_buffer_pool_instances :缓冲池实例数量,默认值是 8。将缓冲池划分为多个实例可以减少并发时的争用,提高性能,如设置为 16,
innodb_buffer_pool_instances = 16。
日志相关
-
innodb_log_file_size :重做日志文件大小,默认值通常是 48M ,增大可减少日志切换频率,适合写入频繁的数据库,如设置为
innodb_log_file_size = 512M。 -
innodb_log_files_in_group:重做日志文件组中的文件数量,默认值是 2。
-
innodb_log_buffer_size :重做日志缓冲区大小,默认值是 16M,用于临时存储重做日志,可根据写入负载调整,如设置为
innodb_log_buffer_size = 64M。 -
innodb_flush_log_at_trx_commit :控制重做日志写入磁盘的时机,默认值为 1,表示每次事务提交时都将日志缓冲区写入磁盘并刷新日志文件,以确保数据安全;若设为 0,表示每秒将日志缓冲区写入磁盘一次并刷新日志文件;设为 2,表示每次事务提交时将日志缓冲区写入磁盘,但不立即刷新,而是每秒刷新一次,示例:
innodb_flush_log_at_trx_commit = 2。
并发控制相关
-
innodb_thread_concurrency :限制并发线程数量,默认值为 0,表示不限制。可根据服务器 CPU 核心数设置,如设为 CPU 核心数的 1.5 至 2 倍,假设服务器有 8 个核心,可设置为
innodb_thread_concurrency = 12。 -
innodb_read_io_threads:InnoDB 读 I/O 线程数量,默认值是 4,可根据磁盘 I/O 性能调整。
-
innodb_write_io_threads:InnoDB 写 I/O 线程数量,默认值是 4,可根据磁盘 I/O 性能调整。
自增长列相关
- innodb_autoinc_lock_mode:控制自增长列的锁模式,默认值为 2。0 是传统模式,1 是连续模式,2 是交错模式,交错模式可提高并发插入性能。
数据存储相关
-
innodb_file_per_table:设为 ON 时,每个 InnoDB 表使用独立的表空间文件,便于管理和维护,默认值为 ON 。
-
innodb_data_file_path:定义 InnoDB 系统表空间的数据文件路径和大小,默认值是根据安装时的配置而定。
脏页控制相关
-
innodb_max_dirty_pages_pct:指定缓冲池中脏页的最大百分比,默认值为 75,达到该比例时,InnoDB 会将脏页写入磁盘。
-
innodb_max_dirty_pages_pct_lwm:脏页比例低水位线,默认值为 0,表示不启用低水位线设置。
其他
-
innodb_lock_wait_timeout:InnoDB 事务等待锁的超时时间,默认值是 50 秒,超时后事务会自动回滚。
-
innodb_rollback_on_timeout:设为 ON 时,事务超时会自动回滚,默认值为 ON 。
-
innodb_stats_on_metadata:设为 ON 时,访问表的元数据时会更新 InnoDB 统计信息,默认值为 ON ,可设为 OFF 以减少元数据访问时的性能开销。
-
innodb_fast_shutdown:控制 InnoDB 引擎关闭的速度,默认值是 1,表示正常关闭;若设为 0,表示缓慢关闭,执行完整的清理操作;设为 2,表示快速关闭,不执行完整的清理操作,下次启动时会进行恢复操作。
使用场景
-
网站博客:使用InnoDB作为默认引擎来存储用户数据、文章内容和评论。通过合理配置缓冲池大小和索引,提高读写性能和并发性。
-
电子商务平台:使用InnoDB存储产品信息、订单信息和用户数据。通过设置合适的事务隔离级别和优化查询,确保数据的一致性和可靠性。
-
数据分析平台:使用MyISAM或Memory引擎存储日志和临时数据,以提高查询和分析性能。通过合理的索引和分区策略,加速大规模数据的处理。
-
大规模分布式系统:使用NDB(Cluster)引擎作为存储引擎,以实现高可用性和容错性。通过水平分片和分布式查询,扩展数据库的存储和计算能力。
十、慢日志
慢日志是用于记录执行时间超过指定阈值的 SQL 语句的日志文件 ,它对于数据库性能优化非常有帮助。
慢日志的作用
-
性能分析与优化 :通过慢日志,可以轻松找出执行时间较长的 SQL 语句,进而分析语句的执行计划,找出性能瓶颈,采取针对性的优化措施,如添加索引、优化查询语句结构、调整数据库参数等,以提高数据库的整体性能。
-
资源监控与调整:帮助数据库管理员了解哪些 SQL 语句消耗了过多的系统资源,如 CPU 时间、I/O 等待等,从而合理分配系统资源,优化数据库服务器的配置。
-
问题排查与追踪:当数据库出现性能问题时,慢日志可以作为重要的排查工具,协助定位问题的根源,判断是由于个别 SQL 语句执行缓慢导致的,还是整体系统负载过高引起的。
慢日志的配置参数
-
slow_query_log :用于开启或关闭慢日志功能。取值为
ON表示开启,OFF表示关闭,默认值为OFF。可以在 MySQL 配置文件my.cnf或my.ini中设置,也可以通过SET GLOBAL slow_query_log = ON;语句动态开启。 -
slow_query_log_file :指定慢日志文件的存储路径和文件名。默认值因操作系统而异,例如在 Linux 上可能是
/var/lib/mysql/hostname-slow.log,在 Windows 上可能是MySQL安装目录\Data\hostname-slow.log。可以在配置文件中通过slow_query_log_file = /path/to/slow.log来设置具体路径。 -
long_query_time :定义了 SQL 语句执行时间的阈值,单位是秒。当 SQL 语句的执行时间超过该阈值时,就会被记录到慢日志中。默认值是
10.000000,即 10 秒,可以根据实际需求在配置文件中进行调整,如long_query_time = 2,表示将阈值设置为 2 秒。 -
log_queries_not_using_indexes :取值为
ON时,不仅会记录执行时间超过阈值的 SQL 语句,还会记录没有使用索引的 SQL 语句,无论其执行时间是否超过阈值。默认值为OFF,可在配置文件中设置开启。 -
min_examined_row_count :指定了 SQL 语句至少需要检查的行数,只有当检查的行数超过该值且执行时间超过
long_query_time时,才会被记录到慢日志中。默认值为0,即不考虑检查行数。
查看
bash
SHOW VARIABLES LIKE '%slow_query%';
配置案例
使用配置文件设置
bash
# 开启慢日志功能
slow_query_log = ON
# 设置慢日志文件路径和名称
slow_query_log_file = /var/log/mysql/mysql-slow.log
# 设置慢查询时间阈值为2秒
long_query_time = 2
# 记录没有使用索引的SQL语句
log_queries_not_using_indexes = ON
# 设置至少需要检查的行数为1000,5.7
min_examined_row_count = 1000
-- 8.0
min_examined_row_limit = 1000
使用SQL语句动态设置
动态设置方式在 MySQL 服务重启后会恢复为默认值。
bash
-- 开启慢日志功能
SET GLOBAL slow_query_log = ON;
-- 设置慢日志文件路径和名称
SET GLOBAL slow_query_log_file = '/var/log/mysql/mysql-slow.log';
-- 设置慢查询时间阈值为2秒
SET GLOBAL long_query_time = 2;
-- 记录没有使用索引的SQL语句
SET GLOBAL log_queries_not_using_indexes = ON;
-- 设置至少需要检查的行数为1000,mysql5.7
SET GLOBAL min_examined_row_count = 1000;
---mysql8.0.42
SET GLOBAL min_examined_row_limit = 1000;
慢日志的查看与分析
-
查看慢日志内容 :可以直接打开慢日志文件查看其中记录的 SQL 语句。在 MySQL 命令行中,也可以使用
SHOW SLOW LOGS;命令查看慢日志的相关信息,如文件位置、是否开启等。 -
分析慢日志工具 :MySQL 提供了一些工具来帮助分析慢日志,如
mysqldumpslow工具。它可以对慢日志进行排序、统计等操作,方便找出执行最频繁、执行时间最长的 SQL 语句。例如,mysqldumpslow -s t /path/to/slow.log可以按照执行时间对慢日志中的 SQL 语句进行排序并显示。
十一、重做日志(了解)
在 MySQL 8 中,重做日志(Redo Log)是事务日志的一种重要类型,用于在数据库发生故障时确保数据的持久性和一致性。以下为你详细介绍重做日志及其相关案例:
重做日志的基本概念
-
记录内容 :重做日志记录了数据库中所有对数据页的修改操作,包括插入、更新、删除等操作。例如,当执行一条
UPDATE语句修改了某条记录时,该操作的细节就会被记录到重做日志中。 -
工作原理:在事务执行过程中,MySQL 会先将对数据的修改操作记录到重做日志缓冲区,当事务提交时,再将缓冲区中的重做日志写入到磁盘上的重做日志文件。在数据库发生故障需要恢复时,MySQL 会根据重做日志中的记录重新执行这些修改操作,从而将数据库恢复到故障前的状态。
-
主要作用
-
数据持久性保障:即使在数据库系统崩溃或意外关机的情况下,只要重做日志已经写入磁盘,就可以在重启后根据重做日志恢复未完成的事务,确保已提交事务的数据修改不会丢失。
-
提高系统性能:通过将事务的修改操作先记录到重做日志缓冲区,然后批量写入磁盘,减少了磁盘 I/O 次数,提高了数据库的整体性能。
-
重做日志的配置参数
-
innodb_log_file_size:指定每个重做日志文件的大小。默认值是 48MB,取值范围是 4MB 到 512GB。合理设置该参数可以平衡重做日志文件的切换频率和恢复时间。例如,如果设置得较小,重做日志文件切换会比较频繁,但恢复时需要处理的日志量相对较少;反之,如果设置得较大,切换频率降低,但恢复时可能需要处理较多的日志数据。
-
innodb_log_files_in_group:表示重做日志文件组中文件的数量,默认值是 2 。MySQL 以循环方式使用这些文件,当一个文件写满后,会自动切换到下一个文件继续写入。
-
innodb_log_buffer_size:定义了重做日志缓冲区的大小,默认值是 16MB,取值范围是 1MB 到 4GB。较大的缓冲区可以减少写入磁盘的次数,但也会占用更多的内存。
相关案例
案例一:设置合适的重做日志文件大小
假设一个业务繁忙的电商数据库,每天有大量的订单数据插入和更新操作。如果innodb_log_file_size设置得过小,比如默认的 48MB,可能会导致重做日志文件频繁切换,增加系统的 I/O 负担和性能开销。
为了优化性能,可以根据数据库的写入负载情况适当增大innodb_log_file_size的值。经过评估,将其设置为 512MB。这样可以减少重做日志文件的切换频率,提高系统的整体性能。在 MySQL 配置文件my.cnf中进行如下设置:
bash
[mysqld]
innodb_log_file_size = 512M
案例二:调整重做日志缓冲区大小
对于一个数据分析应用,需要频繁地对大量数据进行批量更新操作。在这种情况下,如果innodb_log_buffer_size设置得过小,会导致重做日志频繁写入磁盘,影响性能。
通过监控发现,在数据批量更新时,重做日志缓冲区经常被写满。于是将innodb_log_buffer_size从默认的 16MB 增大到 64MB。在my.cnf文件中添加如下配置:
bash
[mysqld]
innodb_log_buffer_size = 64M
增大缓冲区大小后,减少了重做日志写入磁盘的次数,显著提高了批量更新操作的性能 。
十二、常见问题(了解)
在数据库中,特别是在多用户环境下,常常需要处理由于并发事务引起的各种问题
更新丢失(Lost Update)
更新丢失指的是当两个或多个事务读取同一条记录,并基于此独立修改它时,最后一个写操作可能覆盖其他事务所做的修改,导致一些更新效果丢失。
案例
假设事务1和事务2都读取了账户123的余额(比如100)。
事务1将余额更新为150。
事务2不知道事务1的更新,也将余额更新为120。
如果事务2在事务1提交后提交,则事务1所做的更新将会丢失。
脏读(Dirty Read)
脏读发生在一个事务读取了另一个事务尚未提交的数据。如果这个数据被回滚了,那么读取到的数据就是无效的。
案例
事务1从账户123中扣除了100。
事务2读取账户123的余额,包括了未提交的更改。
若事务1回滚更改,则事务2读到的数据是"脏"的,因为它包含了不应该读到的、未提交的数据。
不可重复读(Nonrepeatable Read)
不可重复读是指在一个事务内部,多次读取同一数据集合时,由于其他事务的提交,后续读取的结果可能与前次不一致,即数据集合中的一些行被其他事务更新了。
案例
事务1读取账户123的余额。
事务2更新账户123的余额并提交。
事务1再次读取同一个账户的余额,发现数据发生了变化。
幻读(Phantom Read)
幻读跟不可重复读类似,但它指的是在事务中执行相同的查询时,新增或删除的记录导致读取到不同的行。它通常发生在范围查询中,当其它事务插入或者删除了符合该范围的行。
案例
事务1根据条件查询出了一批订单记录。
事务2插入了一条新的符合事务1查询条件的订单记录,并提交。
当事务1再次执行相同的查询时,会发现一个"幻影"记录------就是新插入的那条订单记录。
解决方法
为了处理这些并发问题,MySQL提供了不同的事务隔离级别
1.READ UNCOMMITTED(读未提交): 允许脏读,也就是可以读取尚未提交的事务数据。
bash
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
2.READ COMMITTED(读已提交): 保证一个事务不可以读取其他未提交事务的数据,从而防止脏读。但是不保证不可重复读。
bash
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
3.REPEATABLE READ(可重复读): 防止脏读和不可重复读现象的发生,但可能出现幻读。这是MySQL的默认事务隔离级别。
bash
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
4.SERIALIZABLE(可串行化): 最严格的隔离级别,事务依次顺序执行,可以看作没有并发。
bash
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;