面试题答案
一键面试行锁与表锁在高并发场景下的性能表现
- 锁争用
- 行锁:由于锁定粒度细,多个事务可以同时对不同行进行操作,锁争用的概率相对较低。但如果多个事务频繁操作同一行数据,依然会产生锁争用,影响性能。
- 表锁:锁定粒度粗,一旦对表加锁,其他事务对该表的任何操作都要等待锁释放,锁争用概率高,在高并发场景下性能可能会急剧下降。
- 锁定粒度对性能的影响
- 行锁:锁定粒度为行,并发度高,适合OLTP(在线事务处理)类型的业务,如电商的订单处理、银行转账等,可提高系统并发处理能力。但行锁的管理开销较大,加锁和解锁操作相对复杂,会消耗一定性能。
- 表锁:锁定粒度为整个表,管理开销小,加锁和解锁操作简单。但由于锁定范围大,在高并发写操作时,其他事务等待时间长,适合以读为主、写操作频率低的业务场景,如一些数据仓库的查询操作。
选择行锁或表锁的依据
- 业务并发读写情况
- 行锁:适合读操作和写操作都比较频繁且并发度高的场景。例如电商平台中,大量用户同时下单购买不同商品,此时行锁可以保证每个订单操作的独立性,减少锁争用。
- 表锁:适合读多写少的场景。例如网站的统计数据展示,主要是大量的读操作,偶尔有写操作更新统计数据,表锁可以满足这种需求且管理开销小。
- 数据一致性要求
- 行锁:在需要保证单行数据一致性的场景下使用。比如银行账户余额的修改,只需要保证单个账户数据的一致性,行锁可以满足要求,同时不影响其他账户操作。
- 表锁:如果业务要求对整个表的数据在某一时刻保持一致性,如数据的批量导入或删除,表锁更为合适,可避免部分数据更新不一致的情况。
对使用这两种锁导致性能问题的优化
- 行锁性能问题优化
- 优化事务设计:尽量缩短事务的执行时间,减少行锁的持有时间。例如,将大事务拆分成多个小事务,尽快提交事务释放行锁。
- 合理设计索引:确保在需要加行锁的操作上有合适的索引,避免全表扫描导致行锁失效,增加锁争用。因为没有索引时,MySQL可能会使用表锁来保证数据一致性。
- 调整事务隔离级别:根据业务需求适当调整事务隔离级别。例如,将默认的可重复读(RR)调整为读已提交(RC),在一定程度上降低锁的粒度和持有时间,但要注意可能引发的幻读等问题。
- 表锁性能问题优化
- 读写分离:采用读写分离架构,将读操作和写操作分布到不同的服务器上。读操作由从库处理,写操作由主库处理,减少读操作对写操作的锁等待,提高整体性能。
- 批量操作:将多个小的写操作合并为一个批量操作,减少加锁和解锁的次数,降低锁争用的概率。例如,在插入数据时使用批量插入语句,而不是单个插入。
- 缓存机制:对于读多写少的场景,引入缓存(如Redis),将经常读取的数据缓存在内存中,减少对数据库的读操作,从而降低表锁争用。