逻辑删除一条记录时,最好删除相关的关系表中的记录。
如果不这样做,会导致没必要的连接,在极端情况下会出现极其糟糕的性能。
今天就遇到这样一个实例。 有两个表,分别叫a表和b表,它们之间有一张a_b关系表, a可以逻辑删除。要查找b=123关联的前10个a记录,需要这样关联:
select a.a_id from a_b join a on a_b.a_id = a.a_id where a_b.b_id = 123 and a.deleted = 0 order by a.a_id limit 0, 10 -- a.deleted = 0 代表未删除
一般情况下,我们预期它会先根据a_b.b_id = 123找出相关的a_id,然后再根据a_id从a表中过滤中deleted = 0的记录。
然而今天发现一个奇怪的情况,如果b关联的a记录很多时,它会先按 deleted = 0扫描整个a表(deleted上有索引),然后再与a_b关联。性能极差。
数据的分布对执行计划的影响是很难捉摸的,最好的办法就是不做关联。 所以我们可以这样,当逻辑删除a记录时,清除a_b中的关系记录。这样就不用连接了:
select a_b.a_id from a_b where a_b.b_id = 123 order by a.a_id limit 0, 10
如果需要保留a_b表的物理记录,可以在a_b表中也加一个逻辑删除字段。