mysql优化(排序分组优化)

总结:

order by子句需要配合limit子句才能让索引生效
如果涉及多个字段的排序,那么这些字段的排序方向一定要一致(要么都是升序,要么都是降序)
否则失效。

测试order by分组

mysql优化(排序分组优化)_第1张图片

mysql优化(排序分组优化)_第2张图片 

测试排序方向的影响

mysql优化(排序分组优化)_第3张图片

 mysql优化(排序分组优化)_第4张图片

1.单路排序和双路排序

如果order by排序的时候,索引生效就在内存中进行排序,如果索引不生效就只能文件中排序, 

执行 filesort 又分两种不同情况:

- 双路排序:
    - 特征:两批 I/O
    - 对应的 MySQL 版本:4.1 之前
    - 大致工作机制:
        - 第一次读取硬盘:读取『行指针』以及『order by 子句指定的字段』
        - 排序:对已读取的『order by 子句指定的字段』进行排序
        - 第二次读取硬盘:根据『行指针』读取 select 子句中指定的其他字段
    - I/O方式:随机 I/O
- 单路排序:(如果内存不足会退化到双路排序)
    - 特征:一批 I/O
    - 对应的 MySQL 版本:4.1 之后
    - 大致工作机制:
        - 读取硬盘:读取 select 子句指定的所有列
        - 排序:按照 order by 列在 buffer 中对它们进行排序
    - I/O方式:顺序I/O

单路优化:

mysql优化(排序分组优化)_第5张图片 

最终目标:

  • 尽量能够基于索引执行排序
  • 如果确实要执行 filesort,那么尽量使用单路排序,而且尽量让单路排序只做一次 I/O。

select * 会影响排序:

        在实际业务功能开发过程中,禁止在 select 子句中使用 * 号代表全部字段。如果确实需要查询全部字段,那就把全部字段都写明。其实这个时候更要注意的是:是不是真的要查全部字段。

        具体从 SQL 优化的角度来说,select * 会导致我们加载很多没有创建索引的字段到内存中,增加了数据体积超过 sort_buffer_size 的风险。有可能会导致单路排序变成双路排序,性能下降。       

3.group by优化:

Group by 分组优化原则如下:

- group by 先排序再分组,同样遵照最左原则
- 当无法使用索引列,增大 max_length_for_sort_data 和 sort_buffer_size 参数的设置
- **where 高于 having**,能写在 where 限定的条件就不要写在 having 中了

举个例子帮助大家理解:

- 假设有 100W 条记录待筛选
- 有一个 X 条件能够过滤掉 90W 条
    - X 条件用在 where 子句:后续 GROUP BY 操作针对 10W 条数据操作
    - X 条件用在 having子句:后续 GROUP BY 操作还是针对原来的 100W 条数据操作,
      操作完了还要再干掉 90W 条

所以在整个 SQL 查询语句中,能够将数据过滤掉的条件在不影响查询结果的前提下都要尽早使用,
尽早过滤数据,缩小要操作的数据量,让后续操作减轻负担。

关闭 ONLY_FULL_GROUP_BY 模式:

mysql优化(排序分组优化)_第6张图片

查看当前 SQL 模式:

select @@GLOBAL.sql_mode;

 

  • 关闭 ONLY_FULL_GROUP_BY 模式

    修改 /etc/my.cnf 配置文件,在配置文件末尾增加一行:

sql_mode=STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION
  • 重启 MySQL 服务
  • 查看修改完成后的效果
select @@GLOBAL.sql_mode;

你可能感兴趣的:(mysql,sql,数据库,database)