SQL中聚合查询是否存在高尾延迟?若存在原因是什么?
这个观点不存在错误,SUM查询慢的核心瓶颈从来都不是加法运算——CPU做一次64位整数加法只需要1纳秒左右,哪怕累加1亿行数据,纯加法的耗时也不到0.1秒,实际场景里的高延迟全来自加法之外的执行环节。
返回逻辑的本质差异是尾延迟高的核心原因
普通的多行返回查询是流水线执行模式:数据库从存储引擎逐行读取符合条件的数据,攒够一批(通常是几KB到几十KB)就立刻通过网络发给客户端,不需要等所有数据全部扫描完成。这种模式下首包响应极快,哪怕总扫描数据量很大,只要前几批数据读取顺利,大部分请求的延迟都不会太高,即使扫描过程中碰到短暂IO抖动,也只会拖慢某一批数据的传输,不会让整体延迟出现量级级的跳变。
但SUM这类聚合查询是全阻塞模式:必须把所有符合WHERE条件的行全部扫描完成、全部累加计算结束,才能返回唯一的结果值,中途不可能给客户端返回任何有效数据。只要扫描过程中碰到一次缓存失效、锁等待、磁盘IO抖动、CPU抢占,所有等待时间都会全额算进查询总耗时,非常容易出现极端高值,直接拉高p90、p99尾延迟。聚合计算的额外开销远高于加法本身
很多人对SUM的执行逻辑有误解,以为就是拿个内存变量循环累加:
如果查询带GROUP BY(生产环境80%以上的聚合查询都带分组),数据库需要维护哈希表/有序树结构存储每个分组的中间累加值,每读一行就要先做哈希查找/树查找定位到对应分组,才能做加法,这部分查找、内存结构扩容的开销比加法本身高3~4个数量级。如果分组数量太多超出了数据库设置的工作内存阈值,中间结果还会溢写到磁盘,带来的随机IO开销更是和纯加法不在一个量级。
就算是不带分组的全局SUM,如果求和的列没有对应索引,数据库需要扫描全表、甚至回表读取对应列的数据,这部分IO开销也远高于计算本身。对比场景不对等带来的感知偏差
很多人觉得SUM慢,是下意识拿带LIMIT的普通查询和无LIMIT的SUM做对比:带LIMIT的查询扫到满足数量的行就会立刻终止扫描,而SUM必须扫完所有符合条件的行,两者实际扫描的数据量可能差几个数量级,耗时差距自然明显。
如果是完全对等的场景:同样扫描同一张表同一个二级索引上的100万行数据、无分组、工作内存足够不发生磁盘溢写,SUM的实际执行速度反而会比返回所有行更快——毕竟最终只需要给客户端传一个数值,省掉了大量网络传输开销。但这种理想场景在生产环境占比极低,大部分业务场景下聚合查询的阻塞执行特性,决定了它天然比普通查询更容易出现高尾延迟。
内容的提问来源于stack exchange,提问作者fraiser

