在我们日常操作数据库的时候,比如订单表、访问记录表、商品表的时候。

经常会处理计算数据列总和、数据行数等统计问题。

随着业务发展,这些表会越来越大,如果处理不当,查询统计的速度也会越来越慢,直到业务无法再容忍。

所以,我们需要先了解、思考这些场景知识点,在设计之初,便预留一些优化空间支撑业务发展。

sql聚合函数

在mysql等数据中,都会支持聚合函数,方便我们计算数据。

常见的有以下方法

取平均值 AVG()
求和 SUM() 
最大值 MAX()
最小值 MIN()
行数 COUNT() 

演示几个简单使用的sql语句:

查询u_id为100的订单总数

select count(id) from orders where u_id = 100;

查询u_id为100的订单消费总和

select sum(order_amount) from orders where u_id = 100;

查询销量最高的商品

select max(sell_num) from goods

统计7月份的订单数量、金额总和

select count(id) as count, sum(order_amount) as total_amount 
from orders where order_date between 20190701 and 20190731 and is_pay = 1

如果此时,订单表的总数是1亿条。并且此条sql运行很慢,我们应该如何排查优化?

有的同学会说了:行数多,在日期字段上加 索引,这样子筛选就很快了。

总数1亿条,假设7月份的订单有1000万条,加了索引的时候,筛选速度自然会提升不少。但是此时我们的问题真的解决了吗?

在这种聚合函数中,结果需要 遍历每一条 数据来计算,比如我们统计订单总和,就需要每一行都读取订单金额,然后加起来。

也就是说在这条统计sql中,需要先从1亿数据中筛选1000万条数据,然后再遍历这些数据来计算。 此时就会非常慢了。

增加索引并不能解决聚合函数统计慢的问题

优化聚合统计的方案

建立 统计数据表,以日期区分,如:20190801一天,销售了多少订单、金额等等数据。
当订单产生(支付完成后 可统计数据)时,便在统计数据表中对应的日期增加金额、数量。

需要注意的是,如果有退款等场景会影响减少数据,记得也相应地做操作处理

当我们需要统计8月份的数据时候,则只需要遍历计算这一个月的三十来行数据。

我们可以使用easyswoole、计划任务等。来定时(比如每20分钟一次)计算总和,然后更新到 统计数据表 中。

优点:做的处理比较少,也无需改动退款操作等api,只需要依赖 原订单 表的数据,定时统计、刷新统计数据。

需要注意的是,根据不同的订单热度,来设置不同的落地频率,比如 一周内的数据变化几率比较大,可能20分钟落地。而一年前的数据则变化几率很小,可以选择某天同步一次,甚至确保不会变动时,则不再刷新。

  • 索引并不能解决统计聚合数据慢的sql语句问题
  • 聚合函数谨慎用 最好不用,因为我们无法预算以后的数据量需要扫描多少行数据来计算
  • 优化方案离不开统计表,都需要按一定的周期储存运算好的统计数据
写在前面在我们日常操作数据库的时候,比如订单表、访问记录表、商品表的时候。经常会处理计算数据列总和、数据行数等统计问题。随着业务发展,这些表会越来越大,如果处理不当,查询统计的速度也会越来越慢,直到业务无法再容忍。所以,我们需要先了解、思考这些场景知识点,在设计之初,便预留一些优化空间支撑业务发展。sql聚合函数在mysql等数据中,都会支持聚合函数,方便我们计算数据。常见的有以下方法取平均值 AVG()求和 SUM() 最大值 MAX()最小值 MIN()行数 COUNT()
对sum的列加索引,的确能够提高性能。 经过在千万级数据量上测试,性能从8秒提高到了1秒以内。 具体可参考:https://www.cnblogs.com/sunss/archive/2010/10/30/1864949.html a、检查是否向数据库请求来了不需要的数据:比如不需要的记录、多表关联返回全部列、总是取出全部列、重复查询相同数据; b、检查是否扫描了额外的记录:比如扫描的行数和返回的行数相差很大,可以优化一下(怎么优化,看下文); c、使用索...
文章目录前言数据表的内容==没有group by==,就==只能有一条==,sum得到的是==总数====有group by==,就分组了,sum得到的是==分组后的n条==,==每一个组的总数== adb语法 数据表的内容 没有group by,就只能有一条,sum得到的是总数 有group by,就分组了,sum得到的是分组后的n条,每一个组的总数
满足 GROUP BY 子句的最通用方法是扫描整个表并创建一个新的临时表,其中每个组的所有行都是连续的,然后使用此临时表来发现组并应用聚合函数(如果有)。 在某些情况下,MySQL 能够做得比这更好,并通过使用索引访问来避免创建临时表。 为 GROUP BY 使用索引的最重要的先决条件是所有 GROUP BY 列都引用来自同一索引的属性,并且索引按顺序存储其键(例如,对于 BTREE 索引)。 临时表的使用是否可以被索引访问替代还取决于查询中使用了索引的哪些部分、为这些部分指定的条件以及所选的聚合函数。
转:https://blog.csdn.net/szwangdf/article/details/80789279 1. mysql在数据量较大的时候、使用group by查询结果集时速度很慢的原因可能有以下几种: 1)分组字段不在同一张表中 2) 分组字段没有建索引 3)分组字段加DESC后索引没有起作用(如何让索引起作用才是关键、且听下文分解) 4)分组字段中加函数导致索引不起作用...
是否遇到过这样的场景:因为一条sql查询耗时太长,降低用户体验;或者面对sql结合业务,不知道怎么写才能更高效地输出结果?今天帝都的雁为大家分享一下如何在千万级的数据量下输出高效的sql语句。 (PS:需要有mysql执行流程原理的理论基础,可参考我的另一篇博文《mysql查询和修改的底层原理》) 一、数据结构 Mysql之所以可以快速地吞吐,很大程度上依赖于其底层的数据结构--B+树。 首先我们先了解一下几种索引可选择的数据结构。
今天数据库一条查询语句很慢,如下 select a.fld1,sum(b.fld2),b.fld3 from table1 a left join table2 b on a.fld1=b.fld1 where 条件 group by a.fld1,b.fld3 测试得到,若不进行汇总,速度很快,但一旦加入汇总,则非常慢,修改如下: 先将需要汇总的数据放入到临时表中,再进行汇总,速度就会很快 select a.fld1,b.fld2,b.fld3 into #t1 from table1 a lef