知识卡片

把关联查询拆成多条单表查询,搬到应用层做关联

普通读书笔记卡

内容

一条多表JOIN查询,看起来比多条单表查询”更高效”(一次往返、数据库自己 做完关联),但把它拆成对每张表各自查询、结果在应用层拼接,在不少场景下 反而是更优的重构方向。这个反直觉结论背后有几条独立成立的理由:拆开后 每张单表查询的结果对象更容易被独立缓存——比如某个”标签”表本身几乎不变, 拆开后关于这个标签的查询可以直接命中缓存,而不必因为关联链路里别的表 发生了变化就被迫失效整条JOIN结果(MySQL的查询缓存本身也是按这个粒度 失效的:关联中任何一张表变了,整条JOIN的缓存就作废,拆开后各表缓存互不 牵连);执行多条更小的单表查询能缩短单次锁的持有时间,降低锁竞争; 在应用层做关联天然更容易把数据水平拆到不同的MySQL实例上,为后续的 扩展性铺路;某些场景下用IN()代替JOIN还能让MySQL按主键顺序批量查找, 比JOIN背后的随机访问更高效;而且应用层按需只取一次某条记录,可以避免 数据库端JOIN因为多对多关系产生的冗余重复行,省下网络和内存开销。更进 一步看,这本质上是在应用层手工实现了”哈希关联”(把结果按key放进哈希表 后再拼接),替代了MySQL默认走的”嵌套循环”关联方式(逐行遍历外层结果去 驱动内层查找),而哈希关联在某些数据规模和分布下效率明显更高。这条 重构思路提醒:数据库能一次做完的事, 未必是让数据库做最合算——关联的”位置”本身就是一个可以搬动的架构决策。

参考来源

- 位置:《高性能MySQL:第3版》第6章"查询性能优化"6.3.3节"分解关联查询" (源文件:_epub-src/OEBPS/Text/part0013.xhtml) - 结论依据:原文明确"用分解关联查询的方式重构查询有如下的优势:让缓存 的效率更高……将查询分解后,执行单个查询可以减少锁的竞争……这样做 相当于在应用中实现了哈希关联,而不是使用MySQL的嵌套循环关联",逐条 列出拆分关联查询在缓存、锁竞争、扩展性、执行效率、冗余数据几方面的 收益,直接支撑卡片结论。 - 原始内容:用分解关联查询的方式重构查询有如下的优势:让缓存的效率 更高……将查询分解后,执行单个查询可以减少锁的竞争。在应用层做关联, 可以更容易对数据库进行拆分,更容易做到高性能和可扩展。