当前位置: 首页 > news >正文

SQL优化 - group by优化

文章目录

  • 分组操作原理
  • Loose Index Scan

分组操作原理

分组操作的实现方案一般有hash和排序操作这两种:

  • hash:就是使用一个map,根据group by的列作为key,遍历表中数据集,放入map
  • 排序:将数据集按照group by的列进行排序

MySQL用的是排序方案

  1. 新建一个临时表
  2. 扫描原始数据,按照group by的列进行排序,保证group by列值相同的行都在一起,然后按这个顺序插入临时表
  3. 使用这个临时表来进行分组并应用聚合函数

如果group by的列使用到索引,那前面2步的开销一般可以省掉,也就是通过索引替代临时表,举个例子:

-- emp_no 上有索引, 耗时 0.4s
SELECT emp_no, MAX(salary) FROM salaries
GROUP BY emp_no LIMIT 10;-- from_date 上无索引, 耗时 2.665s
SELECT from_date, MAX(salary) FROM salaries
GROUP BY from_date LIMIT 10;

GROUP BY使用索引的最重要的前提条件是

  1. 所有GROUP BY列都引用同一索引
  2. 索引按顺序存储,BTREE索引是按顺序存储,但HASH索引则不是

同时,临时表的使用是否可以用索引访问代替,还取决于查询中使用了索引的哪些部分、为这些部分指定的条件以及所选的聚合函数。

Loose Index Scan

松散索引扫描可避免访问索引中的所有条目,并根据前缀列进行筛选。举个例子:

DROP TABLE IF EXISTS t;
CREATE TABLE t (pk_col1 INT NOT NULL,pk_col2 INT NOT NULL,c1 CHAR(64) NOT NULL,c2 CHAR(64) NOT NULL,PRIMARY KEY(pk_col1, pk_col2),KEY c1_c2_idx (c1, c2)
) ENGINE=INNODB;
INSERT INTO t VALUES (1,1,'a','b'), (1,2,'a','b'),(1,3,'a','c'), (1,4,'a','c'),(2,1,'a','d'), (3,1,'a','b'),(4,1,'d','b'), (4,2,'e','b'),(5,3,'f','c'), (5,4,'k','c'),(6,1,'y','d'), (6,2,'f','b');

执行下面的查询:

mysql> SELECT c1, MIN(c2) FROM t GROUP BY c1;
+----+---------+
| c1 | MIN(c2) |
+----+---------+
| a  | b       |
| d  | b       |
| e  | b       |
| f  | b       |
| k  | c       |
| y  | d       |
+----+---------+
6 rows in set (0.04 sec)

执行计划如下:

mysql> EXPLAIN SELECT c1, MIN(c2) FROM t GROUP BY c1;
+----+-------------+-------+------------+-------+---------------+-----------+---------+------+------+----------+--------------------------+
| id | select_type | table | partitions | type  | possible_keys | key       | key_len | ref  | rows | filtered | Extra                    |
+----+-------------+-------+------------+-------+---------------+-----------+---------+------+------+----------+--------------------------+
|  1 | SIMPLE      | t     | NULL       | range | c1_c2_idx     | c1_c2_idx | 256     | NULL |    7 |   100.00 | Using index for group-by |
+----+-------------+-------+------------+-------+---------------+-----------+---------+------+------+----------+--------------------------+
1 row in set (0.03 sec)

Extra中出现了Using index for group-by表示group by操作使用到了Loose Index Scan这个特性

什么情况下使用到松散索引扫描?

在下面一些情况下是可以使用松散索引扫描的:
• 查询针对一个单表。
• GROUP BY包括索引的第1个连续部分(如果对于GROUP BY,查询有一个DISTINCT子句,则所有DISTINCT的属性指向索引开头)。
• 如果使用聚集函数,只能使用MIN()和MAX(),并且它们均指向相同的列。
• 索引的任何其它部分(除了那些来自查询中引用的GROUP BY)必须为常数(也就是说,必须按常量数量来引用它们),但MIN()或MAX() 函数的参数例外。


http://www.mrgr.cn/news/65946.html

相关文章:

  • 数据库Redis篇
  • Android——动态注册广播
  • centos7 安装python3.9.4,解决import ssl异常
  • 【ClickHouse】创建表
  • android h5页面获取不到定位数据的问题
  • Prometheus套装部署到K8S+Dashboard部署详解
  • 俄罗斯市场开发秘籍大公开
  • Vagrant使用教程:创建CentOS 8虚拟机
  • Ubuntu20.04两种安装及配置中文界面、输入法、换源、共享文件夹实现,及注意事项
  • 从0到1!手把手教你私域流量变现的5个必备技能
  • 使用实例讲解RTOS的内核结构、任务调动、资源管理、中断处理
  • 把握数字化新趋势,迎接生态架构新时代——The Open Group 2024生态系统架构·可持续发展年度大会参会指南
  • sql中判断一个字段是否包含一个数据的方法
  • 【从零开始的LeetCode-算法】3289. 数字小镇中的捣蛋鬼
  • 影视会员充值接口对接过程中都需要注意些什么?
  • 系统安全架构
  • Ghidra无头模式(自动化批处理执行重复性任务)
  • Template Method(模板方法)
  • (八)关于InternVL2的优化加速——如何提高三倍的推理速度
  • 基于SpringBoot的母婴商城的设计与实现
  • 面试“利器“——微学时光
  • MySQL45讲 第十一讲 怎么给字符串字段加索引?
  • 责任链模式 Chain of Responsibility
  • 【指南】这款安全数据交换系统 架构全面创新优化
  • 分类算法——逻辑回归 详解
  • github.com port 22