Bohr-L Bohr-L
首页
技术
常见面试题
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

刘博

I'm a slow walker, But I never walk backwards.
首页
技术
常见面试题
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • 数据处理与存储类

  • Spring 生态类

  • 缓存问题类

  • 多线程类

  • JVM 类

  • MySQL 类

    • MySQL 为什么一定要有一个主键
    • MySQL 中的 RR 隔离级别,到底有没有解决幻读问题
    • MySQL 的行级锁到底锁的是什么东西?
    • 存储 MD5 值应该用 VARCHAR 还是用 CHAR?
    • 数据库的三范式是什么?
    • 说说 InnoDB 与 MyISAM 的区别
    • drop、truncate、delete 的区别
    • 聊一聊数据库事务机制
    • 聊一聊 MySQL 中的关联查询
    • 事务隔离级别有哪些?MySQL 的默认隔离级别是什么
    • 分库分表之后,id 主键如何处理?
    • 说说在 MySQL 中一条查询 SQL 是如何执行的?
    • 讲解下 DDL、DML、DCL
    • 存储过程和触发器的作用
    • MySQL 如何行转列和列转行
    • 如何查看 SQL 的执行计划
    • union 和 unionAll 的区别
    • having 和 where 的区别
    • 常见的索引原则
    • MySQL 中的 IN 和 EXISTS 子句有什么区别?
    • MySQL 如何处理 NULL 值,对性能有什么影响?
    • 如何在 MySQL 中处理和避免全表扫描?
    • MySQL 中的表空间是什么,它的作用是什么?
    • 在 MySQL 中,如何优化 ORDER BY 查询?
    • Java 8 + 特性类

    • 其他技术类

    • 常见面试题
    • MySQL 类
    刘博
    2025-12-29
    目录

    在 MySQL 中,如何优化 ORDER BY 查询?

    ORDER BY查询的性能瓶颈在于 “排序操作”(尤其是大数据量排序),核心优化思路是 “利用索引避免排序(文件排序)”,具体方案如下:

    # 1. 核心优化:利用索引排序(避免文件排序)

    InnoDB 的索引是有序的(B-Tree 索引按关键字排序),若ORDER BY的字段与索引字段一致,MySQL 可直接通过索引获取有序数据,无需额外排序(即 “索引排序”),效率极高。

    # 实现条件:
    • ORDER BY的字段顺序与索引字段顺序一致(遵循联合索引的最左前缀原则);
    • ORDER BY的排序方向(ASC/DESC)与索引的排序方向一致(或全部相反,MySQL 8.0 支持混合排序);
    • 查询条件与索引字段匹配(或无查询条件),无索引失效操作。
    # 示例:
    -- 创建联合索引(age升序,create_time降序)
    CREATE INDEX idx_age_createTime ON user(age ASC, create_time DESC);
    
    -- 有效:ORDER BY字段与索引一致,无文件排序
    SELECT * FROM user WHERE age > 20 ORDER BY age ASC, create_time DESC;
    
    -- 有效:ORDER BY字段顺序与索引一致,排序方向全部相反(MySQL 8.0+)
    SELECT * FROM user WHERE age > 20 ORDER BY age DESC, create_time ASC;
    
    -- 无效:ORDER BY字段跳过索引最左前缀age,索引失效,触发文件排序
    SELECT * FROM user ORDER BY create_time DESC;
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11

    # 2. 避免文件排序(Using filesort)

    EXPLAIN执行计划中,Extra 字段出现 “Using filesort” 表示触发文件排序(内存或磁盘排序),需优化:

    • 优化方案 1:调整索引字段顺序:让ORDER BY字段与索引字段顺序一致(如ORDER BY a, b,创建索引idx_a_b);

    • 优化方案 2:覆盖索引排序:查询字段均在索引中(覆盖索引),MySQL 可直接通过索引返回有序结果,无需回表;

      -- 索引包含查询字段(id, age, create_time, name)
      CREATE INDEX idx_age_createTime_name ON user(age ASC, create_time DESC, name);
      -- 查询字段均在索引中,覆盖索引排序
      SELECT id, age, create_time, name FROM user WHERE age > 20 ORDER BY age ASC, create_time DESC;
      
      1
      2
      3
      4
    • 优化方案 3:避免复杂排序条件:

      • 避免ORDER BY多个字段(尤其是非索引字段);
      • 避免ORDER BY函数结果(如ORDER BY DATE(create_time),改为ORDER BY create_time);
      • 避免ORDER BY不同表的字段(多表关联时,仅对驱动表的索引字段排序)。

    # 3. 优化文件排序性能(无法避免时)

    若ORDER BY的字段无法创建索引(如ORDER BY RAND()、ORDER BY name LIKE '%张三%'),需优化文件排序性能:

    • 1. 增大排序缓存:
      • 调整sort_buffer_size(排序缓存大小,默认 256KB),让排序操作在内存中完成(避免磁盘排序);
      • 调整max_length_for_sort_data(排序字段的最大长度,默认 4096 字节),超过该值时,MySQL 会使用 “双路排序”(先排序索引,再回表取数据),否则使用 “单路排序”(直接排序数据)。
    • 2. 减少排序数据量:
      • 避免SELECT *,只查询需要的字段(减少排序缓存占用);
      • 使用LIMIT限制排序行数(如LIMIT 100,仅排序前 100 行数据);
      • 先过滤数据(WHERE条件),再排序(减少排序的数据量)。
    • 3. 避免ORDER BY RAND():
      • ORDER BY RAND()会为每行数据生成随机数,再排序,性能极差(百万级数据需几秒);
      • 替代方案:用随机数关联查询(如SELECT * FROM user u JOIN (SELECT FLOOR(RAND()*(SELECT MAX(id) FROM user)) AS id) AS r ON u.id >= r.id LIMIT 1)。

    # 4. 其他优化建议

    • 排序方向统一:联合索引的字段排序方向统一(如均为 ASC),避免混合方向(ASC/DESC)导致索引失效(MySQL 8.0 支持混合方向,但老版本不支持);

    • 多表关联排序:仅对驱动表的索引字段排序,被驱动表的字段排序会触发文件排序;

    • 定期维护索引:碎片化索引会影响排序效率,可通过OPTIMIZE TABLE优化表空间(InnoDB 表需开启独立表空间)。


    上次更新: 12/30/2025
    MySQL 中的表空间是什么,它的作用是什么?
    使用 Java 8 的优点是什么?

    ← MySQL 中的表空间是什么,它的作用是什么? 使用 Java 8 的优点是什么?→

    最近更新
    01
    CPU 使用率较高排查和解决
    12-29
    02
    JVM OOM 问题如何排查和解决
    12-29
    03
    接口防刷怎么实现?
    12-29
    更多文章>
    Theme by Vdoing | Copyright © 2025-2026 Bohr-L's note
    • 跟随系统
    • 浅色模式
    • 深色模式
    • 阅读模式