基础
MySQL
MySQL
  • 基础知识
    • MySQL 的安装与配置
      • Windows
        • 安装
        • 配置文件
      • Linux
        • 安装
        • 配置文件
      • docker
      • mysql 配置文件格式
    • MySQL 查询的执行过程
      • MySQL 的客户端/服务器通信协议
      • MySQL 查询优化器
        • 优化器可能选择错误的执行计划
        • MySQL 能够处理的优化类型
          • 优化 COUNT()、MIN() 和 MAX()
          • 预估并转化为常数表达式
          • 提前终止查询
          • 排序优化
      • MySQL如何执行联接查询
    • 事务
      • ACID
      • 隔离级别
      • 死锁
      • 事务日志
      • 两阶段锁定协议
      • 多版本并发控制(MVCC)
  • SQL 优化
    • schema 设计
      • 选择数据类型
        • 整数类型
        • 实数类型
        • 字符串类型
          • VARCHAR 和 CHAR
          • BINARY 和 VARBINARY
          • BLOB 和 TEXT
          • ENUM 和 SET
        • 日期类型
      • 选择标识符
    • 索引
      • HASH 索引
      • B-tree 索引
      • 聚簇索引
      • 覆盖索引
      • 前缀索引和索引的选择性
      • 索引合并
      • 选择合适的索引列顺序
      • 使用索引扫描来做排序
      • 维护索引和表
    • 查询优化
      • 优化 SQL 语句的一般步骤
        • 1. 通过 show status 命令了解各种 SQL 的执行频率
        • 2. 定位执行效率较低的 SQL 语句
        • 3. 通过 EXPLAIN 分析低效 SQL 的执行计划
        • 4. 通过 SHOW PROFILE 分析 SQL
        • 5. 通过 TRACE 分析优化器如何选择执行计划
        • 6. 确定问题并采取相应的优化措施
      • 两个简单实用的优化方法
      • 一个复杂查询还是多个简单查询
      • 常用 SQL 的优化
        • 大批量插入数据
        • 优化 GROUP BY 语句
        • 优化联接查询
        • 优化分页查询
        • 优化 SQL_CALC_FOUND_ROWS
        • 优化 UNION 查询
    • Performance Schema
      • 配置
      • 使用
        • 检查SQL语句
        • 检查预处理语句
        • 语句剖析
        • 检查读写性能
        • 检查内存使用情况
        • 检查变量
    • MySQL线程
    • 复制
      • 概述
        • 复制中的各类文件
        • 三种复制格式
        • 全局事务标识符(GTID)
        • 崩溃后的复制安全
      • 安装
        • 基于二进制日志文件位置的复制
        • 基于GTID的复制
      • 复制拓扑
        • 主动/被动模式
        • 主动/只读池模式
        • 多级复制架构
  • 其他
    • 查询缓存
    • 批量insert
    • MySQL 锁的类型
    • MySQL 的索引有哪些
    • INSERT ... ON DUPLICATE KEY UPDATE Statement
由 GitBook 提供支持
在本页
  • 第一种优化思路(延迟联接)
  • 第二种优化思路(把 LIMIIT 查询转换成某个位置的查询)
  1. SQL 优化
  2. 查询优化
  3. 常用 SQL 的优化

优化分页查询

在系统中需要进行分页操作的时候,我们通常会使用 LIMIT 加上偏移量的办法实现,同时加上合适的 ORDER BY 子句。如果有对应的索引,通常效率会不错,否则,MySQL 需要做大量的文件排序操作。

一个非常常见又令人头疼的问题是,在偏移量非常大的时候,例如,可能是 LIMIT 10000, 20 这样的查询,这时 MySQL 需要查询 10020 条记录然后只返回最后 20 条,前面 10 000 条记录都将被抛弃,这样的代价非常高。如果所有的页面被访问的频率都相同,那么这样的查询平均需要访问半个表的数据。要优化这种查询,要么是在页面中限制分页的数量,要么是优化大偏移量的性能。

第一种优化思路(延迟联接)

在索引上完成排序分页的操作,最后根据主键关联回原表查询所需要的其他列的内容。这种方法允许服务器在不访问行的情况下检查索引中尽可能少的数据,一旦找到所需的行,就将它们与整个表联接,以从该行中检索其他列。

EXPLAIN
SELECT a.film_id, a.description
FROM film a
INNER JOIN (
    SELECT film_id
    FROM film
    ORDER BY title
    LIMIT 50, 5
) b ON a.film_id = b.film_id;

+-------------+--------------------------------+
|id           |1         |1        |2          |
+-------------+--------------------------------+
|select_type  |PRIMARY   |PRIMARY  |DERIVED    |
+-------------+--------------------------------+
|table        |<derived2>|a        |film       |
+-------------+--------------------------------+
|partitions   |NULL      |NULL     |NULL       |
+-------------+--------------------------------+
|type         |ALL       |eq_ref   |index      |
+-------------+--------------------------------+
|possible_keys|NULL      |PRIMARY  |NULL       |
+-------------+--------------------------------+
|key          |NULL      |PRIMARY  |idx_title  |
+-------------+--------------------------------+
|key_len      |NULL      |2        |514        |
+-------------+--------------------------------+
|ref          |NULL      |b.film_id|NULL       |
+-------------+--------------------------------+
|rows         |55        |1        |55         |
+-------------+--------------------------------+
|filtered     |100       |100      |100        |
+-------------+--------------------------------+
|Extra        |NULL      |NULL     |Using index|
+-------------+--------------------------------+

第二种优化思路(把 LIMIIT 查询转换成某个位置的查询)

例如,可以和开发人员协商一下,翻页的过程中增加一个参数 last_page_record,用来记录上一页最后一行的租赁编号 rental_id。

假如第 41 页最后一行的租赁编号 rental_id=15640,当想要获取 42 页的内容时,可以使用下面的 SQL 语句进行查询:

SELECT *
FROM rental
WHERE rental_id < 15640
ORDER BY rental_id DESC
LIMIT 10;
上一页优化联接查询下一页优化 SQL_CALC_FOUND_ROWS

最后更新于8个月前