面试题答案
一键面试确保查询性能并保证事务一致性的方法
- 索引维护与事务隔离级别关系处理
- 理解隔离级别影响:不同的事务隔离级别(如读未提交、读已提交、可重复读、串行化)对索引维护有不同影响。例如在可重复读隔离级别下,可能会存在幻读问题,对于索引维护,新插入符合查询条件的文档可能不会及时在当前事务内被感知到,直到事务提交。为应对此,需要明确业务场景对数据一致性的严格程度,合理选择隔离级别。如果业务允许一定程度的幻读,可选择读已提交或可重复读;若对数据一致性要求极高,选择串行化隔离级别,但要注意其对性能的影响。
- 索引更新策略:在事务中,尽量减少对索引列的频繁更新操作。如果必须更新,应批量处理,而不是单个操作。例如,在一个事务内需要更新多个文档的索引列时,先将这些更新操作缓存,最后一次性执行,减少索引重建或调整的次数。
- 优化跨文档事务中的复合索引查询
- 索引设计优化
- 最左前缀原则:复合索引遵循最左前缀原则,确保查询条件按照复合索引的顺序使用。例如有复合索引
(field1, field2, field3)
,查询{field1: value1, field2: value2}
可以利用该索引,而查询{field2: value2}
则不能充分利用。设计索引时要根据常见查询模式,将最常使用的字段放在索引的最左边。 - 覆盖索引:尽量使用覆盖索引,即查询所需要的字段都包含在索引中。这样查询时无需回表操作,直接从索引中获取数据,大大提高查询性能。例如查询
{field1: value1, field2: value2}
,若复合索引为(field1, field2, field3)
且查询只需要field1
和field2
,则该索引为覆盖索引。
- 最左前缀原则:复合索引遵循最左前缀原则,确保查询条件按照复合索引的顺序使用。例如有复合索引
- 查询优化
- 避免全表扫描:确保查询条件能够利用复合索引,避免在查询中使用
$or
等可能导致全表扫描的操作,除非在$or
条件中的每个子条件都能独立利用索引。例如{$or: [{field1: value1}, {field2: value2}]}
,如果field1
和field2
不在同一个复合索引的最左前缀,就可能导致全表扫描。 - 利用索引排序:如果查询需要排序,确保排序字段在复合索引中,这样可以利用索引的有序性,避免额外的排序操作。例如,查询
{field1: value1}
并按field2
排序,若复合索引为(field1, field2)
,则可以利用索引进行排序。
- 避免全表扫描:确保查询条件能够利用复合索引,避免在查询中使用
- 事务优化
- 减少事务粒度:将大事务拆分成多个小事务,降低锁的持有时间和范围。例如在跨文档事务中,若涉及多个文档的操作,可以先对部分相关文档进行操作并提交事务,再处理其他文档,减少对索引和数据的锁定时间,提高并发性能。
- 合理使用锁:在事务中明确锁的类型(共享锁、排他锁等)和范围。对于只读事务,可以使用共享锁,允许多个事务同时读取数据;对于写事务,使用排他锁,但要尽量缩小锁的粒度,只锁定需要操作的文档或集合,而不是整个数据库。
- 索引设计优化