数据库优化<六>SQL优化之SELECT优化 ——filesort

本文深入解析了MySQL中filesort的工作原理,包括其涉及的快速排序和归并排序步骤,以及如何通过调整参数如sort_buffer_size和max_length_for_sort_data来优化性能。建议包括减小max_length_for_sort_data以利用更高效的方法,增加sort_buffer_size以减少磁盘I/O,以及设置多物理盘的tmpdir以分散临时文件存储。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在执行计划中,可能经常看到有Extra列有filesort,这就是使用了文件排序,这当然是不好

的,应该优化,但是,了解一下他排序的原理也许很有帮助,下面看一下filesort的过程:

         1、根据表的索引或者全表扫描,读取所有满足条件的记录

         2、对与每一行,存储一对儿值到缓冲区,一个是排序的索引列的值,即order by用到

               的列值,和执向该行数据的行指针,缓冲区的大小为sort_buffer_size大小

         3、当缓冲区满后,运行一个快速排序(qsort)来将缓冲区中数据排序,并将排序完的

                数据存储到一个临时文件,并 保存一个存储块儿的指针,当然,如果缓冲区不满,

                则不会重建临时文件了

         4、重复以上步骤,直到将所有行读完,并建立相应的有序的临时文件

         5、对块级进行排序,这个类似与归并排序算法,只通过两个临时文件的指针来不断交换

               数据,最终达到两个文件,都是有序的

         6、重复5,直到所有的数据都排序完毕

         7、采取顺序读的方式,将每行数据读入内存,并取出数据传到客户端,这里读取数据时

                并不是一行一行读,读如缓存大小由read_rnd_buffer_size来指定

这就是filesort的过程,采取的方法为:快速排序 + 归并排序,但有一个问题,就是,一行数据会

被读两次,第一次是where条件过滤时,第二个是排完序后还得用行指针去读一次,一个优化的

方法是,直接读入数据,排序的时候也根据 这个排序,排序完成后,就直接发送到客户端了,

过程如下:

           1、读取满足条件的记录

           2、对于每一行,记录排序的key和数据行位置,并且把要查询的列也读出来

           3、根据索引key排序

           4、读取排序完成的文件,并直接根据数据位置读取数据返回客户端,而不是去访问表

这也有一个问题:当获取的列很多的时候,排序起来就很占空间,因此,max_length_for_sort_data

变量就决定了是否能使用这个排序算法


建议:

            1、对于使用filesort的慢查询,可以改小一些max_length_for_sort_data来使用第一个方法

            2、对于想要加快order by 的顺序,有以下一些策略:

                       a、增加sort_buffer_size的大小,如果大量的查询较小的话,这个很好,就缓存中就搞定了

                       b、增加read_rnd_buffer_size大小,可以一次性多读到内存中

                       c、列的长度尽量小些

                       d、改变tmpdir,使其指向多个物理盘(不是分区)的目录,这将机会循环使用做为临时文件区

             



### EXPLAIN 在 SQL 查询中的作用 EXPLAIN 是一种用于分析 SQL 查询执行计划的强大工具。它展示了数据库查询优化器如何处理特定的 SQL 查询,使开发者能够深入了解查询的具体执行方式以及可能存在的性能瓶颈[^1]。 当运行带有 EXPLAIN 的 SQL 查询时,数据库会返回该查询的执行计划而非实际数据结果。这种执行计划通常包括访问路径、使用的索引、表扫描类型以及其他影响查询性能的关键因素[^2]。 --- ### 使用 EXPLAIN 进行 SQL 性能优化的方法 #### 1. **理解 EXPLAIN 输出** EXPLAIN 的输出提供了关于查询执行的重要细节。常见的字段包括: - `id`:表示查询中各个操作的选择顺序。 - `select_type`:描述查询的类型(如简单查询或子查询)。 - `table`:涉及的操作表名称。 - `type`:连接类型,表明访问方法(如全表扫描、索引扫描等)。更高效的访问类型通常是 `ref`, `eq_ref`, 或者 `const` 而不是 `ALL` 和 `index`[^3]。 - `possible_keys` 和 `key`:分别显示可用的索引和实际被选中的索引。 - `rows`:估计需要读取的行数。 - `Extra`:提供额外的信息,比如是否使用临时表或者文件排序。 通过仔细阅读这些字段,可以发现潜在的性能问题,例如不必要的全表扫描或缺乏有效索引的情况[^4]。 --- #### 2. **定位并修复性能瓶颈** 如果在 EXPLAIN 结果中观察到以下情况,则可能存在性能问题: - 如果 `type` 字段显示为 `ALL`,意味着发生了全表扫描,这可能是由于缺少适当索引引起的。 - 当 `rows` 值过高时,说明查询需要检索大量记录,应考虑改进条件过滤逻辑或创建更适合的索引。 - 若 `Extra` 列中有 “Using filesort” 或 “Using temporary”,则提示存在昂贵的排序或临时表操作,需进一步调整查询结构或增加覆盖索引来减少开销。 针对上述问题,可以通过如下手段进行优化: - 添加缺失的索引以支持频繁使用的列作为筛选条件。 - 修改复杂查询拆分为多个较小的部分以便更好地控制其行为。 - 避免 SELECT * 操作而仅选取必要的字段来降低 I/O 成本。 --- ### 实际案例演示 假设有一个查询如下所示: ```sql SELECT * FROM orders WHERE customer_id = 10; ``` 对其应用 EXPLAIN 后得到的结果指示 type=ALL, rows=10000 并且 Extra 包含 Using where。这意味着当前正在对整个订单表做线性查找而不是利用任何索引加速匹配过程。此时应该确认 customers 表上的 customer_id 是否已建立合适的索引;如果没有的话立即补充上去即可显著提升效率。 修改后的版本可改为只提取所需字段,并确保有对应索引存在: ```sql CREATE INDEX idx_customer ON orders(customer_id); EXPLAIN SELECT order_date, total_amount FROM orders WHERE customer_id = 10; ``` 重新解释新查询将显示出更加理想的存取模式——即 row 数量大幅下降至接近真实符合条件的数量范围之内。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值