order by与索引

ORDER BY 通常会有两种实现方法,一个是利用有序索引自动实现,也就是说利用有序索引的有序性就不再另做排序操作了。另一个是把结果选好之后再排序。

用有序索引这种,当然是最快的,不过有一些限制条件,来看下面的测试。

测试数据:student表有两个字段id ,sid ,id是主键。一共有20W条记录,id从1到200000,sid也是从1到200000的数据。

第一种情况 :

order by的字段不在where条件也不在select中

select sid from zhuyuehua.student where sid < 50000 order by id;
第二种情况 :

order by的字段不在where条件但在select中。

select id,sid from zhuyuehua.student where sid < 50000 order by id;
第三种情况 :

order by的字段在where条件但不在select中。

select sid from zhuyuehua.student where sid < 50000 and id < 50000 order by id;
第四种情况 :

order by的字段在where条件但不在select中。倒序排列

select sid from zhuyuehua.student where sid < 50000 and id < 50000 order by id desc;
测试结果:

order by的字段不在where条件不在select中 有排序操作

order by的字段不在where条件但在select中 有排序操作

order by的字段在where条件但不在select中 无排序操作

order by的字段在where条件但不在select中(倒序) 无排序操作

结论:

当order by 字段出现在where条件中时,才会利用索引而无需排序操作。其他情况,order by不会出现排序操作。

分析:

为什么只有order by 字段出现在where条件中时,才会利用该字段的索引而避免排序。这要说到数据库如何取到我们需要的数据了。

一条SQL实际上可以分为三步。

1.得到数据

2.处理数据

3.返回处理后的数据

比如上面的这条语句select sid from zhuyuehua.student where sid < 50000 and id < 50000 order by id desc

第一步:根据where条件和统计信息生成执行计划,得到数据。

第二步:将得到的数据排序。

当执行处理数据(order by)时,数据库会先查看第一步的执行计划,看order by 的字段是否在执行计划中利用了索引。如果是,则可以利用索引顺序而直接取得已经排好序的数据。如果不是,则排序操作。

第三步:返回排序后的数据。

另外:

上面的5万的数据sort只用了25ms,也许大家觉得sort不怎么占用资源。可是,由于上面的表的数据是有序的,所以排序花费的时间较少。如果 是个比较无序的表,sort时间就会增加很多了。另外排序操作一般都是在内存里进行的,对于数据库来说是一种CPU的消耗,由于现在CPU的性能增强,对 于普通的几十条或上百条记录排序对系统的影响也不会很大。但是当你的记录集增加到上百万条以上时,你需要注意是否一定要这么做了,大记录集排序不仅增加了 CPU开销,而且可能会由于内存不足发生硬盘排序的现象,当发生硬盘排序时性能会急剧下降。

注:ORACLE或者DB2都有一个空间来供SORT操作使用(上面所说的内存排序),如ORACLE中是用户全局区(UGA),里面有SORT_AREA_SIZE等参数的设置。如果当排序的数据量大时,就会出现排序溢出(硬盘排序),这时的性能就会降低很多了。

总结:

当order by 中的字段出现在where条件中时,才会利用索引而不排序,更准确的说,order by 中的字段在执行计划中利用了索引时,不用排序操作。

这个结论不仅对order by有效,对其他需要排序的操作也有效。比如group by 、union 、distinct等。

转:https://www.cnblogs.com/zhaoyl/archive/2012/05/04/2483513.html

### SQL ORDER BY 使用索引优化排序性能 在数据库查询中,`ORDER BY` 是一种常见的需求,用于按照指定列对结果集进行排序。然而,如果未正确使用索引,则可能导致 `filesort` 的发生,从而降低查询性能[^1]。 #### 1. 索引的作用 当在 `WHERE` 条件字段上创建索引时,主要目的是加速过滤条件的匹配过程。而针对 `ORDER BY` 字段上的索引,其作用在于利用索引来实现数据的预排序状态,避免额外的文件排序操作 (`filesort`)。通过这种方式,MySQL 能够直接从索引树中读取已排序的数据,从而提升查询效率[^2]。 #### 2. 文件排序 (FileSort) 和索引排序的区别 - **FileSort**: 当 MySQL 需要对未排序的结果集执行排序时,会采用基于内存或磁盘的排序算法。这种情况下,CPU 占用较高,并可能引发大量的 I/O 操作,因此性能较差。 - **Index Sorting**: 如果目标字段已经存在于某个索引中,并且该索引定义了所需排序方向一致的顺序(升序/降序),那么可以直接利用此索引完成排序,无需额外计算[^3]。 #### 3. 如何构建适合 ORDER BY索引? 为了使 `ORDER BY` 利用到索引,需注意以下几个方面: ##### a. 创建覆盖索引 确保所涉及的所有列都包含在一个复合索引里。例如,在以下语句中: ```sql SELECT id, name FROM users WHERE status = 'active' ORDER BY created_at; ``` 应考虑为 `(status, created_at)` 或者更宽泛的形式如 `(status, created_at, id, name)` 建立组合索引,这样不仅满足筛选条件还能服务于排序逻辑[^4]。 ##### b. 排序方向一致性 对于多列排序场景下,比如: ```sql SELECT * FROM products ORDER BY category ASC, price DESC; ``` 此时需要特别关注各子项间的排列次序及其对应的升降关系是否吻合实际物理存储布局。理想状态下最好保持单一维度递增或者递减模式以便充分发挥B+Tree特性优势。 ##### c. 减少不必要的转换函数应用 任何施加于待排序属性之上的表达式都会破坏原有键值连续性进而妨碍引擎选取恰当路径进入快速通道——即所谓“Using Index”。所以应当尽量规避诸如字符串大小写变换之类的处理动作除非绝对必要。 #### 示例代码展示 下面给出一段具体实例来说明上述理论的实际运用效果对比情况: 假设存在一张名为 orders 表记录订单详情信息如下所示: | order_id | customer_name | total_amount | |----------|---------------|--------------| | 1 | Alice | 500 | | 2 | Bob | 700 | 现在我们希望获取按金额高低排列前五名客户名单列表: ```sql -- 方案一:无辅助措施仅依赖默认机制运行较慢 EXPLAIN SELECT customer_name FROM orders ORDER BY total_amount LIMIT 5; -- 方案二:预先设定好关联型二级索引后表现优异得多 CREATE INDEX idx_total ON orders(total_amount); EXPLAIN SELECT customer_name FROM orders USE INDEX(idx_total) ORDER BY total_amount LIMIT 5; ``` 可以看到第二种方法明显优于前者因为它充分利用到了提前布置好的结构化资源减少了临时开销成本。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值