背景
用户反馈说分页数据重复,查看日志,发现说这样的sql:1
2
3
4
5select column1,column2
from table
where columnx = 'xxx'
order by columny
limit current,size
原因
- mysql版本
mysql5.7.20
查看mysql的changes listMySQL 5.6 has only one way one can check whether filesort used priority queue. You need to enable optimizer_trace (set optimizer_trace=1), and then run the query (not EXPLAIN, but the query itself). Then, you can look into the optimizer trace
- order by
MySQL 执行查询语句, 对于order by谓词,可能会使用filesort或者temporary。比如explain一条语句的时候,会看到Extra字段中可能会出现,using filesort和using temporary。下面我们就来探讨下两个的区别和适用场景。 - filesort
filesort主要用于查询数据结果集的排序操作,首先MySQL会使用sort_buffer_size大小的内存进行排序,如果结果集超过了sort_buffer_size大小,会把这一个排序后的chunk转移到file上,最后使用多路归并排序完成所有数据的排序操作。
filesort有两种使用模式:
模式1: sort的item保存了所需要的所有字段,排序完成后,没有必要再回表扫描。
模式2: sort的item仅包括,待排序完成后,根据rowid查询所需要的columns。很明显,模式1能够极大的减少回表的随机IO。
- priority query
- 打开optimizer_trace
1
mysql> set session optimizer_trace=’enabled=on';
- 查询information_schema.optimizer_trace表
主要分为三个部分
join_preparation:SQL的准备阶段,sql被格式化
对应函数 JOIN::prepare
join_optimization:SQL优化阶段
对应函数JOIN::optimize
join_execution:SQL执行阶段
对应函数:JOIN::exec - 查看sql执行阶段当使用order by limit时,filesort_priority_queue_optimization给出的useable为true,在mysql5.6之后(包括5.6)做了一个优化,即priority queue,使用priority queue的目的是为了加快查询,如果sql中未使用到索引有序性时,order by limit会在满足buffer size设置后返回只保证返回limit size,但不保证排序出来的结果和读出来的数据顺序一致,这就是堆排序对效果,先select出符合条件的rows,再order by column,如果这个column没有明确的唯一性,则再limit后,只是会随机出limit的size条数,这个随机性不保证数据是否重复
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27"join_execution": {
"select#": 1,
"steps": [
{
"filesort_information": [
{
"direction": "asc",
"table": "`film`",
"field": "actor_age"
}
],
"filesort_priority_queue_optimization": {
"usable": false,
"cause": "not applicable (no LIMIT)"
},
"filesort_execution": [
],
"filesort_summary": {
"rows": 1,
"examined_rows": 5,
"number_of_tmp_files": 0,
"sort_buffer_size": 261872,
"sort_mode": "<sort_key, packed_additional_fields>"
}
}
]
}解决方法
- 使用有序索引排序
1
select from table where xx order by column desc,id desc limit size
- 给order by 的column加上索引
1
alter table add index (column)
- 强制使用索引
1
select from table force index(column) order by column limit size