知识卡片
把关联查询拆成多条单表查询,搬到应用层做关联
内容
一条多表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的嵌套循环关联",逐条
列出拆分关联查询在缓存、锁竞争、扩展性、执行效率、冗余数据几方面的
收益,直接支撑卡片结论。
- 原始内容:用分解关联查询的方式重构查询有如下的优势:让缓存的效率
更高……将查询分解后,执行单个查询可以减少锁的竞争。在应用层做关联,
可以更容易对数据库进行拆分,更容易做到高性能和可扩展。