MySQL order by
mysql by order
2023-09-14 09:14:49 时间
测试数据 :
CREATE TABLE `t` (
`id` int(11) NOT NULL,
`city` varchar(16) NOT NULL,
`name` varchar(16) NOT NULL,
`age` int(11) NOT NULL,
`addr` varchar(128) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `city` (`city`)
) ENGINE=InnoDB;
order by
查询 :
select city, name, age
from t where city = '杭州'
order by name limit 1000;
全字段排序
为避免全表扫描,要在 city
上加索引
- Using filesort : 要排序 , 会用到
sort_buffer
排序内存
explain select city, name, age
from t where city = '杭州'
order by name limit 1000;
city 索引示意图 :
- 杭州记录 : 从 ID_X 到 ID_(X+N)
全字段排序的执行流程 :
- 初始化 sort_buffer,能放入 name、city、age 字段
- 从索引 city 中找到满足条件的主键 id
- 到主键索引中,取 name、city、age 值,存入 sort_buffer 中
- 在重复 2,3步骤 ,直到条件不满足
- 在 sort_buffer 中按 name 做快速排序
- 再取排序前 1000 行返回给客户端
- 排序过程中,可能在内存中完成或 结合磁盘临时文件完成
查看排序是否用临时文件 :
/* 打开 optimizer_trace,只对本线程有效 */
SET optimizer_trace='enabled=on';
/* @a保存 Innodb_rows_read 的初始值 */
select VARIABLE_VALUE into @a
from performance_schema.session_status
where variable_name = 'Innodb_rows_read';
/* 执行语句 */
select city, name, age from t
where city='杭州' order by name limit 1000;
/* 查看 OPTIMIZER_TRACE 输出 */
SELECT * FROM `information_schema`.`OPTIMIZER_TRACE`;
/* @b保存Innodb_rows_read的当前值 */
select VARIABLE_VALUE into @b
from performance_schema.session_status
where variable_name = 'Innodb_rows_read';
/* 计算Innodb_rows_read差值 */
select @b-@a;
OPTIMIZER_TRACE 结果 :
number_of_tmp_files
: 排序时 , 用临时文件数 (0
: 排序直接在内存中完成)examined_rows=4000
: 参与排序的行数是 4000 行packed_additional_fields
: 排序时 , 对字符串做紧凑处理select @b-@a
: 整个执行过程扫描了 4000 行
rowid 排序
用于排序的行数据的长度阈值,当长度太大,就换算法
SET max_length_for_sort_data = 16;
rowid 排序执行流程 :
- 初始化 sort_buffer,确定放 name , id 字段
- 从索引 city 中找到满足条件的主键 id
- 到主键索引中,取 name、id值,存入 sort_buffer 中
- 在重复 2,3步骤 ,直到条件不满足
- 对 sort_buffer 按 name 做排序
- 排序取前 1000 行的 ID
- 根据 ID 回原表中取出 city、name、age 返回给客户端
- rowid 排序多一次访问表 t 的主键索引
OPTIMIZER_TRACE
变化 :
examined_rows = 4000
: 排序的数据是 4000 行select @b-@a
的值 : 5000 (多了 1000 行 根据 id 去原表取值)sort_mode = <sort_key, rowid>
: 参与排序的只有 name , idnumber_of_tmp_files = 10
: 每行变小了,排序的总数据量就变小,要临时文件也变少了
结论
MySQL 的设计思想:当内存够,就多用内存,尽量减少磁盘访问
- 排序内存太小,会影响排序效率,就用 rowid 排序 , 但要回表查
- 内存足够大,就优先用全字段排序
优化 order by
:
- 联合索引 : (city, name)
alter table t add index city_user(city, name);
city/ name 联合索引 :
查询过程 :
- 从索引 (city, name) 找满足条件的主键 id
- 到主键索引中取 name、city、age 值,并返回
- 重复步骤 1 , 2,直到取到 1000 条记录,或不满足条件时 , 就结束
- name 是递增排序 , 所以不用排序
explain 结果 :
- Extra 中没有
Using filesort
, 不用排序
利用覆盖索引来优化该 SQL:
- city、name、age 的联合索引
alter table t add index city_user_age(city, name, age);
执行流程 :
- 从索引 (city ,name, age) 找到满足条件的记录
- 取出 city、name、age值 , 并返回
- 重复步骤 1 , 2,直到取到 1000 条记录,或不满足条件时 , 就结束
- 覆盖索引优化:不用回表查询
执行计划 :
- Using index : 用了覆盖索引,性能会很快
相关文章
- 8c 数据库,MySQL数据库5.8以上与以下版本,Oracle数据库实现row_number() over(partition by 分组列 order by 排序列 desc)
- MySQL 查询结果倒叙后分组(先order by,再按order by的结果group by)
- 【MySQL高级】MySql中常用工具及Mysql 日志
- MySQL order by与group by查询优化实现详解
- MySQL三表联合查询:解开复杂问题的答案(mysql三表联合查询)
- MySQL ORDER BY:对查询结果进行排序
- MySQL去重复函数:轻松实现数据库中数据去重(mysql去重复函数)
- MySQL主键排序ID管理指南(mysql排序id)
- MySQL单表查询:从浅入深(mysql单表查询语句)
- MySQL 三种索引技术:实现更快的查询效率(mysql三种索引)
- MySQL 存储图片:使用 BLOB 类型字段(mysql存储图片字段)
- 调整PHP和MySQL提升性能(phpmysql性能)
- MySQL使用详解:全面学习MYSQL技术(mysql大全)
- 给初学者的MySQL性能优化入门教程(mysql 性能优化教程)
- MySQL中的外键是什么(mysql中什么代表外键)
- MySQL命令使用小白必备的BAT文件(bat mysql命令)
- MySQL实现数据并发控制加行锁(mysql中加行锁)
- 学习MySQL如何使用SQL语句在MySQL中创建表(mysql中创建表sql)
- Python操作MySQL数据库的必备模块mysqlpython(mysql_python)
- MySQL大小写不敏感(mysql 不区别大小)
- MySQL双重排序如何在SQL中使用ORDER BY进行两级排序(mysql两级排序)
- MySQL中如何获取两数之间的数据(mysql两数之间)
- GET MYSQL 免费下载并破解MySQL数据库软件(mysql下载和破解)
- MySQL下载及安装教程快速掌握MySql下载及安装方法,更高效地使用MySql数据库(mysql下载了在哪)
- MySQL上机练习题提升数据库操作实战能力(mysql上机练习题)
- Mysql 数据库丢失别慌来了解一下 MySQL 不见的可能原因及解决办法(mysql不见)
- 的order byOracle SQL中的Order By语法实现的排序(oracle中sql中)