PostgreSQL17优化器改进(5)GROUP BY优化

PostgreSQL17优化器改进(5)GROUP BY优化

我们知道GROUP BY聚集有两种常见实现方式,一种是基于哈希表,我们称为哈希聚集(Hash agg);另一种则要求先对元组进行排序,我们称为分组聚集(Group Agg)。本次在PostgreSQL17版本中描述的根据索引或order by排序来优化GROUP BY列的排序,同时新增了enable_group_by_reordering参数进行控制,默认值为on,这里GROUP BY优化其实就是对分组聚集实现方式的优化。

创建测试用例表

CREATE TABLE btg AS SELECTi % 100 AS x,i % 100 AS y,'abc' || i % 10 AS z,i AS w
FROM generate_series(1,10000) AS i;
CREATE INDEX abc ON btg(x,y);
ANALYZE btg;
--为了使得执行计划走排序聚集,需要禁用该参数enable_hashagg
SET enable_hashagg=off;
SET max_parallel_workers= 0;
SET max_parallel_workers_per_gather = 0;

GROUP BY存在的问题

针对PostgreSQL17优化器对GROUP BY优化的场景,我们先来查看PostgreSQL16.3版本的执行计划,在案例中GROUP BY的列和order by列以不同的组合执行,观察是否利可以用索引扫描排序来避免Sort操作。

1、GROUP BY顺序和索引顺序比较

--GROUP BY顺序和索引顺序一致
testdb=# EXPLAIN (COSTS OFF) SELECT count(*) FROM btg GROUP BY x,y;QUERY PLAN               
----------------------------------------GroupAggregateGroup Key: x, y->  Index Only Scan using abc on btg
(3 rows)
--GROUP BY顺序和索引顺序不一致
testdb=# EXPLAIN (COSTS OFF) SELECT count(*) FROM btg GROUP BY y,x;QUERY PLAN          
-----------------------------GroupAggregateGroup Key: y, x->  SortSort Key: y, x->  Seq Scan on btg
(5 rows)

2、GROUP BY和ORDER BY的顺序与索引顺序比较

  • 当order by顺序与索引顺序一致时
testdb=# EXPLAIN (COSTS OFF) SELECT count(*) FROM btg GROUP BY y,x order by x,y;QUERY PLAN               
----------------------------------------GroupAggregateGroup Key: x, y->  Index Only Scan using abc on btg
(3 rows)
testdb=# EXPLAIN (COSTS OFF) SELECT count(*) FROM btg GROUP BY x,y order by x,y;QUERY PLAN               
----------------------------------------GroupAggregateGroup Key: x, y->  Index Only Scan using abc on btg
(3 rows)

通过执行计划我们也可以很明显的看出,当order by的顺序和索引顺序一致的时候,无论 GROUP BY列的顺序是什么样的,都不影响执行计划结果。

  • 当order by顺序与索引顺序不一致时
testdb=# EXPLAIN (COSTS OFF) SELECT count(*) FROM btg GROUP BY x,y order by y,x;QUERY PLAN          
-----------------------------GroupAggregateGroup Key: y, x->  SortSort Key: y, x->  Seq Scan on btg
(5 rows)testdb=# EXPLAIN (COSTS OFF) SELECT count(*) FROM btg GROUP BY y,x order by y,x;QUERY PLAN          
-----------------------------GroupAggregateGroup Key: y, x->  SortSort Key: y, x->  Seq Scan on btg
(5 rows)

通过执行计划我们可以看出,当order by的顺序和索引顺序不一致的时候,无论 GROUP BY列的顺序是什么样的,在扫描表的时候无法使用到索引,因此使用的是顺序扫描的方式。

下面我们来对上面PostgreSQL16.3版本group by的问题简单的汇总一下

  • 在语句中没有order by子句时,GROUP BY顺序和索引顺序不一致时,未使用到索引
  • 当语句中有order by子句时且顺序与索引顺序不一致时,未使用到索引

其实对于上面的两种情况,问题原因是一样的,就是对于Group Agg,只是按照Group By中指定列的顺序和索引列的顺序进行比较keys,因此无法使用索引。

但是对于Group Agg,我们只是按照查询中指定的顺序比较键

解决方案

对于上述的问题,解决思路就是利用了group by并不意味着必须固定的顺序排序,而且可以以任意的顺序排序,而不影响最终的结果。下面我们来验证一下结果

testdb=# SELECT x,y, count(*) FROM btg where x<10 GROUP BY y,x ;x | y | count 
---+---+-------0 | 0 |   1001 | 1 |   1002 | 2 |   1003 | 3 |   1004 | 4 |   1005 | 5 |   1006 | 6 |   1007 | 7 |   1008 | 8 |   1009 | 9 |   100
(10 rows)testdb=# SELECT x,y, count(*) FROM btg where x<10 GROUP BY x,y ;x | y | count 
---+---+-------0 | 0 |   1001 | 1 |   1002 | 2 |   1003 | 3 |   1004 | 4 |   1005 | 5 |   1006 | 6 |   1007 | 7 |   1008 | 8 |   1009 | 9 |   100
(10 rows)

测试的结果是和预期是一样的,group by顺序并不会影响最终数据的结果。

优化场景

GROUP BY顺序和索引顺序不一致

--PostgreSQL17版本优化后的执行计划
testdb=# EXPLAIN (COSTS OFF) SELECT count(*) FROM btg GROUP BY y,x;QUERY PLAN               
----------------------------------------GroupAggregateGroup Key: x, y->  Index Only Scan using abc on btg
(3 rows)

从PostgreSQL17版本执行计划我们也可以看到,即使GROUP BY顺序和索引顺序不一致,也可以使用到创建的索引;另外在执行计划中我们也可以看到Group Key的顺序是以索引的顺序来分组的。

ORDER BY顺序与索引顺序不一致时

testdb=# EXPLAIN (COSTS OFF) SELECT count(*) FROM btg GROUP BY x,y order by y,x;QUERY PLAN                  
----------------------------------------------SortSort Key: y, x->  GroupAggregateGroup Key: x, y->  Index Only Scan using abc on btg
(5 rows)testdb=# EXPLAIN (COSTS OFF) SELECT count(*) FROM btg GROUP BY y,x order by y,x;QUERY PLAN                  
----------------------------------------------SortSort Key: y, x->  GroupAggregateGroup Key: x, y->  Index Only Scan using abc on btg
(5 rows)

从PostgreSQL17版本执行计划我们也可以看到,优化后的执行计划中可知,即使ORDER BY顺序和索引顺序不一致,也可以使用到创建的索引;另外在执行计划中我们也可以看到Group Key的顺序同样是以索引的顺序来分组的,与sql中指定的分组顺序没有关系。

适用于增量排序

--该sql语句在PostgreSQL16.3版本的执行计划和PostgreSQL17是一致的
testdb=# explain (COSTS OFF) SELECT x,y FROM btg GROUP BY x,y,z,w;QUERY PLAN                
-----------------------------------------GroupGroup Key: x, y, z, w->  Incremental SortSort Key: x, y, z, wPresorted Key: x, y->  Index Scan using abc on btg
(6 rows)
--PostgreSQL17优化后执行计划
testdb=# explain (COSTS OFF) SELECT x,y FROM btg GROUP BY z,y,w,x;QUERY PLAN                
-----------------------------------------GroupGroup Key: x, y, z, w->  Incremental SortSort Key: x, y, z, wPresorted Key: x, y->  Index Scan using abc on btg
(6 rows)
--PostgreSQL17优化后执行计划
testdb=# explain (COSTS OFF) SELECT x,y FROM btg GROUP BY w,z,x,y;QUERY PLAN                
-----------------------------------------GroupGroup Key: x, y, w, z->  Incremental SortSort Key: x, y, w, zPresorted Key: x, y->  Index Scan using abc on btg
(6 rows)
--PostgreSQL17优化后执行计划
testdb=# explain (COSTS OFF) SELECT x,y FROM btg GROUP BY w,x,z,y;QUERY PLAN                
-----------------------------------------GroupGroup Key: x, y, w, z->  Incremental SortSort Key: x, y, w, zPresorted Key: x, y->  Index Scan using abc on btg
(6 rows)

从PostgreSQL17版本执行计划我们也可以看到,当语句中没有order by子句时,不论 GROUP BY中的分组以任何顺序排序,都可以使用到索引;另外在执行计划中我们也可以看到Presorted Key的顺序就是索引的顺序;Sort Key是以Presorted Key的顺序为准,并添加剩余的字段;Group Key的顺序就是增量排序的顺序。

子查询

--PostgreSQL16.3执行计划
testdb=# explain (COSTS OFF) SELECT x,y
testdb-# FROM (SELECT * FROM btg ORDER BY x,y,w,z) AS q1
testdb-# GROUP BY (w,x,z,y);QUERY PLAN                        
----------------------------------------------------------GroupGroup Key: q1.w, q1.x, q1.z, q1.y->  SortSort Key: q1.w, q1.x, q1.z, q1.y->  Subquery Scan on q1->  Incremental SortSort Key: btg.x, btg.y, btg.w, btg.zPresorted Key: btg.x, btg.y->  Index Scan using abc on btg
(9 rows)
--PostgreSQL17优化后执行计划
testdb=# explain (COSTS OFF) SELECT x,y
testdb-# FROM (SELECT * FROM btg ORDER BY x,y,w,z) AS q1
testdb-# GROUP BY (w,x,z,y);QUERY PLAN                  
----------------------------------------------GroupGroup Key: btg.x, btg.y, btg.w, btg.z->  Incremental SortSort Key: btg.x, btg.y, btg.w, btg.zPresorted Key: btg.x, btg.y->  Index Scan using abc on btg
(6 rows)
============================================第二条sql===========================================
--PostgreSQL16.3执行计划
testdb=# explain (COSTS OFF) SELECT x,y
testdb-# FROM (SELECT * FROM btg ORDER BY x,y,w,z LIMIT 100) AS q1
testdb-# GROUP BY (w,x,z,y);QUERY PLAN                           
----------------------------------------------------------------GroupGroup Key: q1.w, q1.x, q1.z, q1.y->  SortSort Key: q1.w, q1.x, q1.z, q1.y->  Subquery Scan on q1->  Limit->  Incremental SortSort Key: btg.x, btg.y, btg.w, btg.zPresorted Key: btg.x, btg.y->  Index Scan using abc on btg
(10 rows)
--PostgreSQL17优化后执行计划
testdb=# explain (COSTS OFF) SELECT x,y
testdb-# FROM (SELECT * FROM btg ORDER BY x,y,w,z LIMIT 100) AS q1
testdb-# GROUP BY (w,x,z,y);QUERY PLAN                     
----------------------------------------------------GroupGroup Key: btg.x, btg.y, btg.w, btg.z->  Limit->  Incremental SortSort Key: btg.x, btg.y, btg.w, btg.zPresorted Key: btg.x, btg.y->  Index Scan using abc on btg
(7 rows)

通过以上对子查询执行计划的对比,我们可以看到执行计划的差异还是很明显的,对于子查询外面的GROUP BY 即使指定的顺序与索引不一致,也用到了索引。

总结

总的来说,当使用多列GROUP BY子句计算查询时,如果我们将GROUP BY子句的顺序与order BY排序子句或索引顺序保持一致,则可以最小化或避免排序操作。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/30640.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

昇思25天学习打卡营第1天|基本介绍及快速入门

1.第一天学习总体复盘 1&#xff09;成功注册昇思大模型平台&#xff0c;并成功申请算力&#xff1b; 2)在jupyter环境下学习初学入门/初学教程的内容&#xff1b; 在基本介绍部分&#xff0c;快速撸了一边内容&#xff0c;有了一个基本的了解&#xff08;没理解到位的计划采用…

win11使用qemu安装arm64 openEuler虚拟机 并虚拟机中在安装docker

1、安装openEuler教程&#xff1a;Windows11 上使用 QEMU 创建 aarch64&#xff08;ARM64&#xff09;虚拟机_tap-windows-9.24.7-i601-win10.exe-CSDN博客 2、虚拟机安装docker&#xff1a;Windows11 上使用 QEMU 创建 aarch64&#xff08;ARM64&#xff09;虚拟机_tap-windo…

【尝鲜】SpringCloudAlibaba AI 配置使用教程

1、环境配置 maven依赖pom.xml 注意配置远程仓库&#xff0c;原因见&#xff1a;Unresolved dependency: ‘org.springframework.ai:spring-ai-core:jar:0.8.1’ <dependencies><!--Base--><dependency><groupId>org.springframework.boot</group…

用qq邮箱发送邮件验证码java

添加依赖 <dependency><groupId>com.sun.mail</groupId><artifactId>javax.mail</artifactId><version>1.6.2</version> </dependency>配置邮箱 实现代码 package com.example.demo.service; import org.springframework.st…

芜湖!恒驰大数据迁移案例荣幸亮相“东数西算”芜湖集群创新大会暨华为云华东(芜湖)数据中心全球开服活动

6月13日至14日&#xff0c;“东数西算”芜湖集群创新大会暨华为云华东&#xff08;芜湖&#xff09;数据中心全球开服活动在安徽芜湖隆重举办&#xff0c;标志着“东数西算”芜湖集群正式上线、华为云全国存算网的枢纽节点布局全面完成。 本次活动由华为技术有限公司主办、芜湖…

软磁盘阵列与硬磁盘阵列介绍

前言 软磁盘阵列&#xff08;软RAID&#xff09;与硬磁盘阵列&#xff08;硬RAID&#xff09;在多个方面存在显著的差异。以下是关于两者对比的详细分析&#xff1a; 一、定义与实现方式 软RAID&#xff1a;通过软件程序并由计算机的CPU提供运行能力来实现RAID功能。阵列的配…

金属配件加工厂设备远程监控

随着科技的飞速发展&#xff0c;智能制造已成为制造业转型升级的重要方向。在金属配件加工领域&#xff0c;设备的稳定运行和高效管理对于提升产品质量、降低生产成本至关重要。HiWoo Cloud平台凭借其强大的远程监控功能&#xff0c;为金属配件加工厂提供了全新的解决方案&…

Android SurfaceFlinger——服务启动流程(二)

SurfaceFlinger 是 Android 系统中的一个核心服务&#xff0c;负责管理图形缓冲区的合成和屏幕显示&#xff0c;是 Android 图形系统的关键组件。 一、启动流程 SurfaceFlinger 作为一个系统服务&#xff0c;在 Android 启动早期由 init 进程通过 servicemanager 启动。它是作…

【黑马TS】学习资料Day4

五、在 React 中使用 TypeScript 现在&#xff0c;我们已经掌握了 TS 中基础类型、高级类型的使用了。但是&#xff0c;如果要在前端项目开发中使用 TS&#xff0c;还需要掌握 React、Vue、Angular 等这些库或框架中提供的 API 的类型&#xff0c;以及在 TS 中是如何使用的。 …

作为一名程序员,最大的成就感来自哪里?

说在前面 &#x1f388;作为一名程序员&#xff0c;我们的生活充满了挑战与创造。在成千上万行代码的背后&#xff0c;我们的成就感来源于何处&#xff1f;是解决问题的瞬间&#xff0c;是产品发布的一刻&#xff0c;还是用户的一声赞叹&#xff1f; 解决问题的瞬间 每当我们调…

Python基础学习文档

一、Python入门 1.Python简介&#xff1a; Python是一种高级编程语言&#xff0c;用于多种应用&#xff0c;包括网站开发、数据科学、人工智能等。 Python具有语法简洁、易读性强、功能强大等特点。 2.安装Python ①访问Python官网&#xff08;https://www.python.org/&am…

AI写作平台:提升文档撰写效率的神器

工欲善其事&#xff0c;必先利其器。 随着AI技术与各个行业或细分场景的深度融合&#xff0c;日常工作可使用的AI工具呈现出井喷式发展的趋势&#xff0c;AI工具的类别也从最初的AI文本生成、AI绘画工具&#xff0c;逐渐扩展到AI思维导图工具、AI流程图工具、AI生成PPT工具、AI…

驱动层透明加密技术是什么?

驱动层透明加密技术的应用场景主要集中在确保数据在存储、传输和使用过程中的安全性&#xff0c;特别是在需要严格控制文件访问和防止数据泄露的场合。以下是几个具体的应用场景&#xff0c;结合参考文章中的相关信息进行归纳&#xff1a; www.weaem.com 内部文件流通&#xf…

【索引】数据库索引之顺序索引概述

目录 1、索引的基本概念 2、顺序索引 3、稠密索引和稀疏索引 3.1 什么是稠密索引&#xff1f; 3.2 什么是稀疏索引&#xff1f; 4、索引的更新 4.1 索引的插入操作 4.1 索引的删除操作 5、辅助索引 1、索引的基本概念 数据库中的索引与图书馆中书的索引作用相同&#xf…

Spire.PDF for .NET【文档操作】演示:如何删除 PDF 中的图层

借助Spire.PDF&#xff0c;我们可以在新建或现有pdf文档的任意页面中添加线条、图像、字符串、椭圆、矩形、饼图等多种图层。同时&#xff0c;它还支持我们从pdf文档中删除特定图层。 Spire.PDF for .NET 是一款独立 PDF 控件&#xff0c;用于 .NET 程序中创建、编辑和操作 PD…

【Python/Pytorch 】-- 滑动窗口算法

文章目录 文章目录 00 写在前面01 基于Python版本的滑动窗口代码02 算法效果 00 写在前面 写这个算法原因是&#xff1a;训练了一个时序网络&#xff0c;该网络模型的时序维度为32&#xff0c;而测试数据的时序维度为90。因此需要采用滑动窗口的方法&#xff0c;生成一系列32…

虚拟DOM的比较

patch 将虚拟DOM渲染成DOM&#xff0c;这就是patch的作用 在vue运行的时候会生成新旧两个虚拟DOM树&#xff0c;通过比较这两棵DOM树&#xff0c;我们就能针对性的修改真实DOM 事实上&#xff0c;我们大可以在每次比较两棵DOM树的时候删除现有的DOM结构&#xff0c;然后根据新的…

大数据-数据分析初步学习,待补充

参考视频&#xff1a;数据分析只需3小时从入门到进阶&#xff08;up亲身实践&#xff09;_哔哩哔哩_bilibili 数据指标&#xff1a; 对当前业务有参考价值的统计数据 分类&#xff1a;用户数据&#xff0c;业务数据&#xff0c;行为数据 用户数据 存量&#xff1a; DAU&#…

可信计算和数字水印技术

可信计算 可信计算可信计算基础概述可信计算关键技术要素可信性认证可信计算优劣 数字水印技术数字版权保护技术 可信计算 可信计算基础概述 可信计算&#xff08;Trusted Computing&#xff0c;TC&#xff09;&#xff1a;在计算和网络通信系统中广泛使用的、基于硬件安全模块…

Android Glide, first start based on loadThumbnail, Kotlin(二)

Android Glide, first start based on loadThumbnail, Kotlin&#xff08;二&#xff09; Android Glide, first start based on loadThumbnail, Kotlin&#xff08;一&#xff09;中有个小问题&#xff0c;通过loadThumbnail()采集到的缩略图真的就是整张图片的完整缩略图&…