面试题答案
一键面试表结构设计
- 合理分区:
- 依据时间、ID范围等对表进行分区。比如对于日志表,按时间(如按月、按周)分区,当高并发写入时,不同分区的写入可以并行处理,减少锁争用。例如,使用RANGE分区按时间范围划分:
CREATE TABLE log_table ( id INT, log_time TIMESTAMP, log_content VARCHAR(255) ) PARTITION BY RANGE (YEAR(log_time)) ( PARTITION p0 VALUES LESS THAN (2020), PARTITION p1 VALUES LESS THAN (2021), PARTITION p2 VALUES LESS THAN (2022) );
- 优化字段类型:
- 尽量使用固定长度的数据类型,如
INT
代替VARCHAR
存储数字,减少行长度的动态变化,从而减少页分裂的概率,提升写入性能。 - 对于非必要的大字段(如大文本、大二进制),考虑单独存储在其他表中,通过外键关联,避免在高并发写入时大字段更新导致的锁争用。
- 尽量使用固定长度的数据类型,如
- 索引优化:
- 避免创建过多索引,因为每个索引都会增加写入时的维护成本。只保留必要的索引,例如针对查询频繁的字段创建索引。
- 对于联合索引,注意索引字段的顺序,将选择性高的字段放在前面,提高索引的利用率,减少锁的范围。例如,
CREATE INDEX idx_name ON your_table (col1, col2);
,如果col1
选择性更高,这样的顺序更合理。
事务管理
- 减少事务粒度:
- 将大事务拆分成多个小事务。例如,原本一个事务中要插入1000条记录,可以拆分成10个小事务,每次插入100条记录。这样锁的持有时间会大大缩短,减少锁争用的机会。
- 确保事务内的操作尽量简单和快速,避免在事务内进行复杂的计算或长时间的I/O操作。
- 优化事务隔离级别:
- 如果业务场景允许,降低事务隔离级别。例如从
SERIALIZABLE
(可串行化)降低到READ COMMITTED
(读已提交)。SERIALIZABLE
隔离级别会对读取的记录加锁,防止并发修改,而READ COMMITTED
只在读取时保证读取到已提交的数据,锁的范围和时间相对较小。可以通过以下语句设置事务隔离级别:
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
- 如果业务场景允许,降低事务隔离级别。例如从
- 使用乐观锁:
- 在应用层实现乐观锁机制。例如,在更新数据前先读取数据的版本号,更新时带上版本号,只有版本号匹配才进行更新操作。可以在表中增加一个
version
字段,每次更新时version
加1。在应用代码中类似如下操作(以Java为例):
// 读取数据及版本号 ResultSet rs = statement.executeQuery("SELECT data, version FROM your_table WHERE id = " + id); rs.next(); String data = rs.getString("data"); int version = rs.getInt("version"); // 模拟业务操作 data = data + " updated"; // 更新数据并验证版本号 int updatedRows = statement.executeUpdate("UPDATE your_table SET data = '" + data + "', version = version + 1 WHERE id = " + id + " AND version = " + version); if (updatedRows == 0) { // 版本号不匹配,更新失败,可重试 }
- 在应用层实现乐观锁机制。例如,在更新数据前先读取数据的版本号,更新时带上版本号,只有版本号匹配才进行更新操作。可以在表中增加一个
存储引擎参数调整
- 调整InnoDB缓冲池大小:
- 增大
innodb_buffer_pool_size
参数值,让更多的数据和索引可以缓存在内存中,减少磁盘I/O。例如,对于有大量内存可用的服务器,可以将其设置为物理内存的70% - 80%。可以在my.cnf
配置文件中设置:
[mysqld] innodb_buffer_pool_size = 8G
- 增大
- 调整日志相关参数:
innodb_flush_log_at_trx_commit
参数控制日志刷盘策略。默认值是1,表示每次事务提交时都将日志写入磁盘,这虽然保证了数据的持久性,但在高并发写入时会增加I/O开销。如果可以接受在系统崩溃时丢失少量未刷盘的事务数据,可以将其设置为2,即每秒将日志写入磁盘一次,或者设置为0,由操作系统决定何时刷盘。在my.cnf
中设置:
[mysqld] innodb_flush_log_at_trx_commit = 2
- 调整锁相关参数:
innodb_lock_wait_timeout
参数设置等待获取锁的超时时间。在高并发场景下,如果锁争用严重,可以适当增大该值,避免事务因等待锁超时频繁回滚。例如设置为60秒:
[mysqld] innodb_lock_wait_timeout = 60
innodb_autoinc_lock_mode
参数控制自增锁的模式。可以设置为2(交错模式),在一定程度上减少自增锁的争用,特别是在高并发插入场景下。在my.cnf
中设置:
[mysqld] innodb_autoinc_lock_mode = 2