MySQL:系统表/货币数据类型/MyIsam和Innodb/insert性能优化/邻键锁的退化/MySQL的参数/CPU问题排查


最近参加了一场技术面试,涉及了不少 MySQL 相关的问题。面试结束后,我对问题进行了复盘,并整理了答案和思路,希望对大家有所帮助。以下是具体问题及解答:

1. MySQL中有哪些系统表,规定了哪些内容,能否把表格输出出来?

MySQL 中的系统表主要存储在 information_schema 数据库中,用于提供数据库的元数据信息。以下是一些常见的系统表及其作用:

系统表名 作用描述
TABLES 提供所有表的信息,如表名、引擎、行数等
COLUMNS 提供表中列的信息,如列名、数据类型、是否为空等
SCHEMATA 提供数据库信息,如数据库名、字符集等
STATISTICS 提供索引统计信息,如索引名、列名、基数等
PARTITIONS 提供表分区信息
KEY_COLUMN_USAGE 提供主键和外键约束的列信息
TRIGGERS 提供触发器的信息,如触发器名、触发事件等

这些系统表是只读的,主要用于查询数据库结构和状态。例如,可以通过 SELECT * FROM information_schema.TABLES 查看所有表的信息。

2. MySQL记录货币有什么数据类型好?

在 MySQL 中记录货币时,推荐使用 DECIMAL(或 NUMERIC)数据类型。原因如下:

  • 精度高DECIMAL(M, N) 可以精确指定总位数(M)和小数位数(N),避免浮点数(如 FLOATDOUBLE)的精度丢失问题。
  • 适合金融场景 :货币计算需要精确到分(例如 2 个小数位),DECIMAL(10, 2) 表示总共 10 位,其中 2 位是小数,足以满足大多数需求。

示例:

sql 复制代码
CREATE TABLE orders (
    id INT AUTO_INCREMENT PRIMARY KEY,
    price DECIMAL(10, 2) NOT NULL
);

不推荐

  • FLOATDOUBLE:浮点数可能导致舍入误差。
  • INT:需要手动换算单位(如存储为分),不够直观。

3. InnoDB 和 MyISAM 的区别?

InnoDB 和 MyISAM 是 MySQL 中两种常见的存储引擎,以下是它们的主要区别:

特性 InnoDB MyISAM
事务支持 支持(ACID 事务) 不支持
外键 支持 不支持
锁机制 行级锁 表级锁
崩溃恢复 支持(通过日志恢复) 不支持
全文索引 5.6 之后支持 原生支持
性能 写多读少时较优 读多写少时较优
存储结构 聚簇索引(数据和索引一起) 非聚簇索引(分开存储)

选择建议

  • 如果需要事务和数据一致性(如金融系统),选择 InnoDB。
  • 如果是只读或写少场景(如日志系统),MyISAM 可能更高效。

4. 如何提高 MySQL 的 INSERT 性能?

提升 INSERT 性能可以从以下几个方面入手:

  1. 批量插入 :使用 INSERT INTO table VALUES (), (), () 减少单次插入的开销。
  2. 关闭索引或延迟建索引 :插入数据前禁用索引(ALTER TABLE table_name DISABLE KEYS),完成后重建。
  3. 调整事务:将多次插入放入一个事务中,减少日志同步开销。
  4. 优化配置
    • 增大 innodb_buffer_pool_size,缓存更多数据。
    • 调整 innodb_log_file_size,减少日志切换。
  5. 使用 LOAD DATA INFILE :对于大批量数据导入,效率远超普通 INSERT
  6. 分区表:对大表进行分区,分散写压力。

示例(批量插入):

sql 复制代码
INSERT INTO users (name, age) VALUES ('Alice', 25), ('Bob', 30), ('Charlie', 35);

5. InnoDB 是行锁,合适会产生行锁,何时是表锁?最初的锁是邻键锁,什么时候会退化为间隙锁和记录锁?

行锁、表锁场景

InnoDB 默认使用行级锁 ,但在以下情况可能升级为表锁

  • 执行 LOCK TABLES 或 DDL 操作(如 ALTER TABLE)。
  • 查询没有命中索引,导致全表扫描(表锁或大量行锁)。
  • 锁冲突过多,InnoDB 可能主动升级为表锁。

锁类型

InnoDB 的锁包括:

  1. 记录锁(Record Lock):锁定具体一行记录。
  2. 间隙锁(Gap Lock):锁定某个范围内的间隙,防止插入。
  3. 邻键锁(Next-Key Lock):记录锁 + 间隙锁的组合,默认用于范围查询。

锁退化

  • 邻键锁退化为间隙锁:当查询范围中没有具体记录命中时,只需防止插入,退化为间隙锁。
  • 邻键锁退化为记录锁:当查询条件精确匹配唯一索引(如主键),只需锁住单行,退化为记录锁。

示例:

sql 复制代码
SELECT * FROM users WHERE id = 10 FOR UPDATE; -- 记录锁(主键精确匹配)
SELECT * FROM users WHERE id > 5 AND id < 10 FOR UPDATE; -- 邻键锁(范围查询)

6. 新创建的 MySQL 数据库要调整哪些参数?

新数据库上线前,建议调整以下参数(根据硬件和业务需求):

  1. innodb_buffer_pool_size:缓冲池大小,建议设置为物理内存的 60%-80%,用于缓存数据和索引。
  2. innodb_log_file_size:日志文件大小,建议 128M-512M,提升写性能。
  3. max_connections:最大连接数,默认 151,视并发量调整。
  4. tmp_table_sizemax_heap_table_size:临时表和内存表大小,建议 64M 起。
  5. innodb_flush_log_at_trx_commit
    • 设为 1(默认):每次事务提交刷盘,安全性高。
    • 设为 2:提升性能,但可能丢失 1 秒数据。
  6. character_set_servercollation_server :设置字符集(如 utf8mb4)和排序规则。

调整示例(my.cnf):

ini 复制代码
[mysqld]
innodb_buffer_pool_size = 2G
innodb_log_file_size = 256M
max_connections = 500

7. MySQL 发现 CPU 或者 IO 压力非常大,你会怎么定位问题?

CPU 压力大

  1. 检查慢查询 :开启 slow_query_log,分析耗时 SQL(EXPLAIN 查看执行计划)。
  2. 查看连接数SHOW PROCESSLIST 检查是否有大量活跃线程。
  3. 分析锁冲突SHOW ENGINE INNODB STATUS 查看死锁或锁等待。
  4. 系统工具 :用 tophtop 确认 MySQL 进程 CPU 占用。

IO 压力大

  1. 检查磁盘 IO :用 iostatvmstat 查看磁盘读写情况。
  2. 分析日志写入 :检查 innodb_flush_log_at_trx_commit 设置,频繁刷盘可能导致 IO 高。
  3. 优化查询:未命中索引的查询会导致大量物理读。
  4. 调整缓冲池innodb_buffer_pool_size 过小会导致频繁换页。

定位流程

  • 先用 SHOW FULL PROCESSLIST 查看当前执行的 SQL。
  • EXPLAIN 优化低效查询,添加索引。
  • 检查服务器资源瓶颈,调整参数或升级硬件。
相关推荐
远游客0713几秒前
使用go实现下载导入Excel模板
开发语言·后端·golang
qwy7152292581632 分钟前
12-scala样例类(Case Classes)
开发语言·后端·scala
加瓦点灯17 分钟前
JDK废弃了观察者模式,我们还能用它吗?
后端
调试人生的显微镜17 分钟前
从零基础到精通:Flutter开发的完整指南
后端
小华同学ai18 分钟前
企业级开源CMS新标杆,三分钟搭建多语言官网!
后端·github
bobz96520 分钟前
kubeovn tunnel 网卡:不同 node 可以指定不同网卡名么?
后端
aimmon24 分钟前
Rust从入门到精通之进阶篇:17.宏编程基础
开发语言·后端·rust
天草二十六_简村人44 分钟前
Rabbitmq消息被消费时抛异常,进入Unacked 状态,进而导致消费者不断尝试消费(上)
java·spring boot·分布式·后端·rabbitmq
aimmon1 小时前
Rust从入门到精通之精通篇:25.过程宏高级应用
开发语言·后端·rust
金融数据出海1 小时前
使用Java对接印度股票数据源
后端