Skip to content

问:MySql的存储引擎

mysql 常用引擎包括:

  • InnoDB(默认引擎,生产系统首选):支持事务。行级锁,大幅提升高并发场景性能。适合高并发读写,需要事务保证的业务。
  • MyISAM(已逐渐淘汰,慎用!):不支持事务。全表锁,适合读多写少,数据量不大的业务。
  • Memory(内存引擎,高风险慎用):内存引擎,不支持事务,数据全内存存储,读写极快。可以用更合适的 redis 替代。
  • Archive(归档引擎):高压缩比(可达10:1),适合日志类数据。 仅支持INSERT/SELECT,不支持UPDATE/DELETE。

问:Mysql的InnoDB隔离级别

  • READ UNCOMMITTED(读取未提交): 最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读。
  • READ COMMITTED(读取已提交): 允许读取并发事务已经提交的数据,可以阻止重读,但是幻读或不可重复读仍有可能发生。
  • REPEATABLE READ(可重复读): 对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止重读和不可重复读,但幻读仍有可能发生。
  • SERIALIZABLE(可串行化): 最高的隔离级别,完全服从ACID的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止空读、不可重复读以及幻读。

MySQL InnoDB 存储引擎的默认支持的隔离级别是 REPEATABLE READ(可重复读)。

问:什么是脏读、幻读、不可重复读?

  • 脏读 (Dirty Read):事务A读取了事务B未提交的修改数据,若事务B回滚,事务A读到的就是无效的“脏数据”。
  • 不可重复读 (Non-repeatable Read):事务A内多次读取同一行数据,结果不一致(因事务B在此期间提交了更新)。
  • 幻读 (Phantom Read):事务A内多次执行相同查询,返回的结果集行数不同(因事务B在此期间提交了新增或删除)。

问:什么是死锁?怎么避免?怎么排查?

  • 死锁本质:多个事务互相等待对方释放锁,导致永久阻塞。

  • 死锁避免策略(设计层面核心原则):

    1. 统一数据访问顺序,强制所有事务按相同顺序操作资源(如先更新订单再更新库存)。
    2. 减小事务粒度,拆分大事务为小事务(如:扣库存成功后立即提交,再更新订单状态)。避免事务内包含网络调用等耗时操作。
    3. 使用乐观锁(CAS机制),对冲突概率低的场景(如用户余额更新),用版本号替代悲观锁。
    4. 合理设置锁超时,配置innodb_lock_wait_timeout(默认50秒),超时自动回滚(避免无限等待)。
    5. 索引优化,唯一索引:让Next-Key Lock退化为行锁(Record Lock),减少锁范围。避免全表扫描:未命中索引的更新会锁表。
    6. 业务层熔断,高并发时对核心操作(如库存扣减)做限流,避免瞬时资源竞争。
  • 死锁排查实战(MySQL InnoDB):

    1. 业务层面,我们可以通过数据库超时的异常日志来排查,这也是最直接最快速的方式。
    2. 数据库层面,配置innodb_print_all_deadlocks = ON,死锁日志将输出到错误日志文件。
    3. 阿里的rds后台可以直接导出死锁日志。

问:索引的结构类型有哪些?B+树索引和哈希索引的区别是什么?

  • B+树索引:InnoDB引擎默认使用,是磁盘友好型数据结构,其“矮胖”特性减少磁盘寻道次数(机械硬盘随机I/O比顺序I/O慢10万倍)。
  • 哈希索引:基于哈希表实现,适用于等值查询,查询效率极高,但不支持范围查询和排序。
  • 全文索引:用于对文本类型数据进行全文本搜索,能够处理复杂的查询条件,如包含某个词语或者短语、近似匹配词干提取等。

问:索引的功能分类有哪些?

  • 主键索引:是一种特殊的唯一索引,不允许有空值,每个表只能有一个主键索引。
  • 唯一索引:保证索引列的值唯一,但允许有空值。
  • 普通索引:最基本的索引类型,无特殊约束,允许在定义索引的列中插入重复值和空值。
  • 组合索引:在多个列上创建的索引,可以提高涉及多个列的查询效率。

问:什么是索引覆盖?

确保索引包含查询所需的所有列,这样查询可以直接从索引中获取数据,无需回表查询。

问:如何通过索引优化查询性能?

  • 优先使用覆盖索引:确保索引包含查询所需的所有列,这样查询可以直接从索引中获取数据,无需回表查询。
  • 遵循最左匹配原则:在创建复合索引时,将最常用的列放在最前面,以确保查询时能够充分利用索引。
  • 避免过度索引:虽然索引可以提高查询性能,但过多的索引会增加写操作的负担和维护成本。只创建必要的索引。
  • 定期维护和优化索引:随着数据的变化,索引可能会变得不再高效。定期重建索引,清理无效的索引,可以提高查询性能。
  • 使用EXPLAIN分析查询计划:使用EXPLAIN命令分析查询计划,了解查询是如何使用索引的,从而优化索引策略。
  • 平衡查询和更新性能:虽然索引可以提高查询性能,但会增加更新操作的负担。因此,需要考虑字段的更新频率,避免在频繁更新的字段上创建过多的索引。

问:如何选择联合索引的字段顺序?

  • 遵循最左前缀原则:联合索引的查询必须从最左边的列开始,且不能跳过中间的列。因此,将最常用的查询条件放在最左边,可以提高索引的使用率。
  • 考虑排序和分组字段:如果查询经常需要对某些字段进行排序或分组,将这些字段加入到联合索引中,可以提高排序和分组的效率。

问:什么情况下索引会失效?如何避免?

索引会失效场景:

  1. 不符合最左前缀原则:联合索引中,查询条件未包含最左侧的列,索引会失效。
  2. 对索引列使用函数或运算:对索引列进行函数操作(如 YEAR(date_column))或数学运算(如 id + 1 = 10)会导致索引失效。
  3. 隐式类型转换:查询条件与索引列数据类型不一致(如字符串与数值比较),MySQL会放弃索引。
  4. 使用 LIKE 以通配符开头:LIKE 条件以 % 开头(如 '%abc')无法使用索引。
  5. 使用 OR 连接非索引列:OR 连接的字段中有一个未建索引,整个查询会全表扫描134。
  6. IS NULL 或 IS NOT NULL:索引不存储 NULL 值,IS NULL 可能导致全表扫描。
  7. 不等于操作(!= 或 <> ):!= 或 <> 操作通常无法利用索引。
  8. 数据量过小或选择性差:当表数据量极少或索引列重复值过多(如性别字段),优化器可能放弃索引134。
  9. 使用 ORDER BY 非索引列:排序字段无索引时,MySQL需额外排序操作。

为了避免索引失效,可以采取以下措施:

  • 避免在查询中使用函数、表达式和类型转换操作,尽量保持查询条件与索引列的类型一致。
  • 将通配符放在查询模式的末尾,避免以通配符开头的LIKE语句,以利用索引的前缀匹配能力。
  • 满足索引最左前缀原则,设计复合索引时,将最常用的查询条件放在索引的最左侧。
  • 优化查询语句,避免使用复杂的操作符和子查询,尽量简化查询语句,以提高索引的有效性。

问:慢sql的优化与排查

排查慢SQL:

  • 开启慢查询日志,记录执行时间超过指定阈值的SQL语句。以MySQL为例,需要修改配置文件my.cnf或在运行时使用SET GLOBAL命令设置long_query_time参数,并开启slow_query_log。
  • 使用SHOW PROCESSLIST或数据库工具实时监控活跃线程,关注Time和State字段,识别执行时间过长和可能的数据传输瓶颈的查询。

分析慢SQL:

  • 使用EXPLAIN命令查看SQL语句的执行计划,了解数据库是如何执行SQL语句的,包括使用了哪些索引、表连接方式等。分析执行计划中的type参数,确保其效率在range及以上,效率从低到高依次为ALL,index,range,ref,eq_ref,const。

优化慢SQL:

  • 索引优化:添加索引、使用复合索引、覆盖索引,删除无用索引,防止索引失效。
  • SQL语句优化:避免使用SELECT *,避免在WHERE子句中使用函数,使用JOIN代替子查询,优化LIKE查询,使用批量操作代替单条操作,避免在循环中执行SQL语句。

问:如何优化一条包含多表JOIN的复杂SQL?

优化JOIN操作:

  • 优化连接顺序:优先连接过滤后数据量最小的表,减少中间结果集的大小。
  • 使用索引:确保JOIN条件中的字段有索引,减少全表扫描。
  • 避免不必要的JOIN:减少不必要的表关联,只连接必需的表。

优化WHERE条件:

  • 简化条件:尽量减少WHERE条件的复杂性,使用IN语句替代多个=条件。
  • 使用EXISTS或NOT EXISTS:在某些情况下,使用EXISTS或NOT EXISTS比IN或NOT IN更高效。

问:什么是N+1查询问题?如何解决?

N+1查询问题是指通过1次主查询获取N个主表对象后,再循环发起N次关联查询获取子数据的低效操作。

解决方案:

  • JOIN(一次查询):在SQL层面,使用JOIN语句一次性获取主对象和关联数据。适用:关联数据量少(避免笛卡尔积爆炸)
  • 批量预加载(1+1查询):通过批量查询减少数据库访问次数。例如,使用IN子句一次性查询多个关联对象。
  • 缓存机制:首次请求:查DB并缓存。后续请求:直接读缓存。适合例如sku和sku规格这种主档数据。
  • 精准控制字段:只查询需要的字段。结合JOIN或者预加载等方案,减少数据膨胀。

问:MySQL和Oracle的区别是什么?为什么选择MySQL?

问:如何设计一个支持高并发的电商库存表?

问:在重构库存模块时,如何保证数据库迁移过程中业务不受影响?

问:如果让你设计一个分布式数据库,你会考虑哪些核心问题?

问:是否使用过NoSQL数据库(如MongoDB)?适用哪些场景?

问:解释ACID特性。如何在项目中保证事务的隔离性?

问:乐观锁与悲观锁的区别?你在库存扣减中如何应用?

问:是否使用过ShardingSphere或MyCat?

问:MySQL主从复制的原理是什么?如何解决主从延迟问题?

问:如何设计数据库的备份策略?是否做过全量备份和增量备份?

问:什么是读写分离?如何通过中间件实现?

问:MySQL和Oracle在分库分表方案上的差异?

问:什么情况下需要分库分表?如何选择分片键?

问:分库分表后如何实现跨分片查询(如订单列表按时间排序)?

问:你在项目中如何设计MySQL和Oracle的表结构?是否遇到过分库分表的需求?

问:分库分表的设计思路及ShardingSphere的实现原理?

页脚:版权前显示的信息