You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
最近在帮同事优化一个慢查询,这张主表的数量在 100w+,它具体的问题就是,查询条件非常多,大约有 30 多个可选的查询条件,这些查询的字段分散在数据库的各个表中,导致 left join 的表特别多,大约 left join 七八张表,这种情况下分页查询,查询时间在 5~6 秒,非常的影响查询体验。
-- 示例伪 sqlselecto.idt1.name,
t2.name,
...
from order o
left join table_1 t1
left join table_2 t2
left join table_3 t3
left join table_4 t4
left join table_5 t5
...
whereo.id=1323andt1.id=2323andt2.name='xxx'
...
解决方案
动态 left join
通常情况下,用户使用的查询条件只会有两到三个,所以就可以根据用户实际的查询条件,动态的 left join 相关的表,比如 mybatis 里可以这样编写:
<iftest="(ticketWebQueryDto.snCode != null and ticketWebQueryDto.snCode != '')">
left join ticket_product_detail tpd on t.ticket_id = tpd.ticket_id
</if>
<iftest="ticketWebQueryDto.pickingUserName != null and ticketWebQueryDto.pickingUserName != ''">
left join ticket_picking tp on tp.ticket_id = t.ticket_id
</if>
这样一来,left join 的表就可以减少不少。
主查询只返回主表主键 id
select id from xxx 直接使用 index 里面的值就返回结果的。但是一旦用了 select *,就会有其他列需要读取,这时在读完 index 以后还需要去读 data 才会返回结果。这两种处理方式性能差异非常大,特别是返回行数比较多,并且读数据需要 IO 的时候,可能会有几十上百倍的差异。主查询只返回主表 id 情况下,充分利用索引的优势,通常我们的主表存放的都是其他表的 id 字段,但是页面展示的都是 name,这时候如果我们为了省事,一次性将所需要的字段的 name select 出来,势必会降低查询效率,增加回表的次数,降低索引的命中率,所以大数据量情况下,将查询分散到应用层面,而非数据库层面,整体的效率会提升很大。
-- 示例伪 sqlselecto.idfrom order o
left join table_1 t1
left join table_2 t2
left join table_3 t3
left join table_4 t4
left join table_5 t5
...
whereo.id=1323andt1.id=2323andt2.name='xxx'
...
复杂查询拆解为多次单表查询
核心思路就是,将多表关联查询,拆解为多个单表查询,然后在进行数据整合,由于是分页查询,所以主键 id 数量肯定是有限制的,通常是 10~20 个,所以在代码层面,我们批量查询主表(单表查询):
问题分析
最近在帮同事优化一个慢查询,这张主表的数量在 100w+,它具体的问题就是,查询条件非常多,大约有 30 多个可选的查询条件,这些查询的字段分散在数据库的各个表中,导致
left join
的表特别多,大约left join
七八张表,这种情况下分页查询,查询时间在 5~6 秒,非常的影响查询体验。解决方案
动态 left join
通常情况下,用户使用的查询条件只会有两到三个,所以就可以根据用户实际的查询条件,动态的
left join
相关的表,比如 mybatis 里可以这样编写:这样一来,left join 的表就可以减少不少。
主查询只返回主表主键 id
select id from xxx
直接使用 index 里面的值就返回结果的。但是一旦用了select *
,就会有其他列需要读取,这时在读完 index 以后还需要去读 data 才会返回结果。这两种处理方式性能差异非常大,特别是返回行数比较多,并且读数据需要 IO 的时候,可能会有几十上百倍的差异。主查询只返回主表 id 情况下,充分利用索引的优势,通常我们的主表存放的都是其他表的 id 字段,但是页面展示的都是 name,这时候如果我们为了省事,一次性将所需要的字段的 nameselect
出来,势必会降低查询效率,增加回表的次数,降低索引的命中率,所以大数据量情况下,将查询分散到应用层面,而非数据库层面,整体的效率会提升很大。复杂查询拆解为多次单表查询
核心思路就是,将多表关联查询,拆解为多个单表查询,然后在进行数据整合,由于是分页查询,所以主键 id 数量肯定是有限制的,通常是 10~20 个,所以在代码层面,我们批量查询主表(单表查询):
收集其他需要 left join 表的主键id,并进行多次单表查询:
将查询到的单表数据进行内存映射,构建k-v键值对,key 是单表主键id,value 就是我们查询到的数据,这一步的目的是为了接下来循环的构建返回前端视图层 VO 的时候,直接就可以从内存里面获取我们的单表数据:
循环遍历,开始构建视图层 VO :
总结
The text was updated successfully, but these errors were encountered: