distinct导致sql超时

前言

昨天敲着敲着代码,小杨哥跑过来给我说,快看他们大会议室演示报错了,还是一堆错了。完了啊在演示的时候报错!!!接下来我们分析一下是什么原因吧。

问题分析

查看日志: 从日志打印看明显的是sql报错了
在这里插入图片描述

这个sql明显是分页查询插件在统计分页条数,日志第一行有个distinct关键字,distinct我是从来没有用到过分页中过,这个distinct会根据后面的所有字段去重,性能太差导致连接超时。

小杨哥在这时说,人大金仓distinct只会对第一个字段去重处理,其他字段随机取一条。我当时就否定了他这个观点,有点经验的人也不会这么设计distinct吧,你这不是违反sql规范吗。实际上小杨哥说的那个语法应该是这个DISTINCT ON (column1, column2, ...) column1, column2, ...

我也马上把我结论告知了相关同事,经过测试确实也是因为这个distinct导致请求时长超时。

解决方案

问题已经定位到了,就是distinct后面的字段太多了。用distinct主要目的就是解决 在1对多的连表查询时候,根据主表数据去重。

  • 方式1:使用 distinct on ('id') 指定重复列
  • 方式2:使用group by取代distinct

总结

  1. 在 SQL 中,DISTINCTGROUP BY 都用于处理重复数据,但它们的执行原理和性能特征有所不同。在大多数情况下,GROUP BY 在处理聚合时可能比 DISTINCT 更高效,但实际性能依赖于具体查询和数据集的特性。

    在查询1对多的数据情况,只需要返回主表的数据,这时候distinctdistinct ongroup by 都满足查询结果
    eg: select distinct on (a.id) a.* from atable a left join btable b on a.id= b.a_id where b.name = 'xx'
    这种情况我们可以使用 distinct on (id) ,其他情况 或者是需要调用聚合函数时候就用 group by

  2. 在分页列表查询优化中,我还可以考虑去单独优化count sql
    开发中大多时候我们写分页查询,都是不需要管统计条数这个sql的,因为插件自动帮我们拼装执行了。有些时候需要优化的话,我们可以考虑覆盖统计sql,不动service代码。一般的分页插件在mapper中定义一个命名规则为 queryname +_COUNTmapper就行了,分页插件在执行queryname 查询的的时候,就会优化查询是否有queryname_COOUNT的统计条数SQL,有就使用自定义的。

    自定义的统计sql可以减少查询字段、在不影响统计结果的情况减少连表查询,来提升统计的效率

ps:有服务器需求的联系我返dian,提供技术支持哦

扩展知识 (distinct 和 group by 区别)

  • DISTINCTDISTINCT 用于从查询结果中去除重复的行,返回唯一的值。distinct on ('colunm ..') 指定需要去重的列,可以返回不参与去重的列,没有参与去重的列随机返回一条数据。

  • GROUP BYGROUP BY 用于将结果集按一个或多个列进行分组,并通常与聚合函数(如 COUNTSUM 等)一起使用。不能查询没有参与分组的字段。

性能测试

查询相同的sql 使用日志中的sql作为测试,使用distinctdistinct ongroup by 测试一下执行时间 。用时最短的是 distinct on ,因为只根据一个id进行去重;第二是group by ,毕竟分组的字段太多了差不多30个;distinct (去重30个字段)时间就直接指数级的增长了,列表查询的时候禁用啊。

  • distinct:14.2s (distinct后只跟一个字段的话就是 0.2s)
    在这里插入图片描述

  • distinct on (id): 0.7s
    在这里插入图片描述

  • group by: 1.9s (如果只查一个id的话就0.2s)

    在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不务专业的程序员--阿飞

兄弟们能否给口饭吃

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值