面试题答案
一键面试索引优化
- 创建合适的索引:
- 对于写多读少的场景,写操作可能涉及插入、更新和删除。在插入操作中,如果表中有外键约束,为外键字段创建索引可以加快插入速度,因为MySQL在插入时需要检查外键约束。例如,假设有两个表
orders
和customers
,orders
表中有customer_id
作为外键关联到customers
表的id
字段,为orders
表的customer_id
字段创建索引,能减少插入时的锁等待时间。 - 对于更新操作,若经常更新某几个字段,并且更新条件涉及某些字段,为这些字段创建联合索引可以提高更新性能。比如,经常执行
UPDATE users SET status = 'active' WHERE age > 30 AND city = 'New York';
,可以为age
和city
字段创建联合索引(age, city)
。
- 对于写多读少的场景,写操作可能涉及插入、更新和删除。在插入操作中,如果表中有外键约束,为外键字段创建索引可以加快插入速度,因为MySQL在插入时需要检查外键约束。例如,假设有两个表
- 避免冗余索引:冗余索引会增加写操作的成本,因为每次写操作都需要更新索引。例如,如果已经有了索引
(a, b)
,再创建索引(a)
就是冗余的,因为索引(a, b)
已经可以满足对字段a
的查询需求。在写多读少场景下,减少冗余索引能显著提升写性能。
事务设计
- 减少事务粒度:
- 将大事务拆分成多个小事务。比如,在一个电商系统中,如果有一个事务涉及创建订单、更新库存、记录订单日志等多个操作,可以将创建订单和更新库存作为一个事务,记录订单日志作为另一个事务。这样,当更新库存事务完成后,锁就可以释放,其他事务可以继续操作库存相关数据,而记录订单日志的事务不会影响库存数据的并发访问,提高了系统的并发处理能力。
- 缩短事务时长:
- 尽量减少事务内的逻辑处理,特别是一些复杂的计算或外部系统调用。例如,如果在事务内需要调用第三方支付接口获取支付结果,应尽量将这部分逻辑移到事务外。因为在等待第三方接口响应时,事务一直持有锁,会阻塞其他事务。可以先提交事务,然后通过异步任务去调用第三方接口,并在得到结果后再进行后续处理。
锁的粒度控制
- 优化锁的获取顺序:
- 在多个事务需要获取多个锁的情况下,确保所有事务以相同的顺序获取锁。例如,假设有两个事务
T1
和T2
,都需要获取A
表和B
表的锁,如果T1
先获取A
表的锁再获取B
表的锁,那么T2
也应该按照这个顺序获取锁,这样可以避免死锁的发生,提高并发性能。
- 在多个事务需要获取多个锁的情况下,确保所有事务以相同的顺序获取锁。例如,假设有两个事务
- 合理使用意向锁:
- 意向锁分为意向共享锁(IS)和意向排他锁(IX)。当一个事务要对某一行加排他锁(X锁)时,首先要对包含该行的页加意向排他锁(IX锁)。合理使用意向锁可以减少锁等待时间。例如,在批量插入数据时,如果没有意向锁机制,每个插入操作都可能直接获取行级排他锁,导致锁竞争激烈。而通过意向锁,先获取页级的意向排他锁,再获取行级排他锁,能有效降低锁冲突的概率,提高并发插入的效率。