mysql同时使用order by和limit查询时的一个严重隐患 -- 丢失数据

我经常使用order by和limit来做数据分页显示并排序,一直也没发现过什么问题。但这两天缺遇到一个严重的问题,在按时间戳升序排列并用limit分批读取数据时,却发现在某些记录丢失了,表中明明有的记录确死活读取不到。研究了大半天终于发现了问题所在,记录一下以防忘记,也是给大家提个醒。

问题重现

工具和原料

数据库:

Ver 14.14 Distrib 5.6.11, for Linux (x86_64) using EditLine wrapper

表结构:

字段 类型 说明
id int(10) 主键
pay_time int(10) 时间戳,有索引
flag tinyint(1) 类型标识,用于分类筛选

数据

大概5000条数据, 大部分记录的flag都等于0,pay_time字段时间戳格式都正确

需求

筛选出flag=0的记录,按pay_time升序依次读取所有数据。

处理方式

使用limit分批读取数据,如:

select id, pay_time from order_customer_new where flag=0 order by pay_time asc, id asc limit 250, 10;

发现问题

在读取数据的过程中,发现有时间戳相等的记录,分两次读取出来时,可能会丢失一条记录。见下图,id=465的记录就丢失了。

问题分析与猜测

当排序值相等,其先后顺序的不确定的。这里我猜想:当465和466处于limit末尾时466排在前面,而当处于limit开头时,466缺排到后面去了。所以465丢失了,466出现了两次。

排序值相等时,其顺序的不确定应该是其结果不可预测。但真正进行排序时应该会采取一定的规则以确定唯一的排序结果,也就是说,即使有相等的排序值,多次排序的结果应该是一样的。从以前的使用经历看,mysql是这么做的。但这次遇到的问题似乎说明mysql并不是这样的。不知道mysql本来就是如此,还是一个bug。

解决办法

既然猜想此问题是因为排序值相等造成顺序不确定引起的,那么就试试增加排序条件让其排序结果是确定的、唯一的。一试果然OK,如下图所示,465出来了。

请求支援

我对mysql的底层实现和数据库原理不是很了解,完全不明白mysql为什么会出现这种问题。若哪位朋友能解释一二,不胜感激!

时间: 2024-11-05 16:33:35

mysql同时使用order by和limit查询时的一个严重隐患 -- 丢失数据的相关文章

Mysql的ORDER BY 和Limit offset的一个问题,拿出来和大家研究下

今天碰到个很怪异的问题,如题关于mysql的ORDER BY 语句和Limit offset语句问题. bug再现下:select * from A a where a.culomn1 limit 5 offset 0 order by a.culomn1 asc 则出现sqlException,提示order by 这行有问题. 若将语句改为如下,将limit语句和order by 语句调换: select * from A a where a.culomn1 order by a.culom

mysql通过“延迟关联”进行limit分页查询优化的一个实例

最近在生产上遇见一个分页查询特别慢的问题,数据量大概有200万的样子,翻到最后一页性能很低,差不多得有4秒的样子才能出来整个页面,需要进行查询优化. 第一步,找到执行慢的sql,如下: SELECT         shotel_id as hotelId, mroom_type_id as mroomTypeId, available_date as availableDate, result_status as resultStatus, create_time as createTime,

MySQL 获取某个时间段每一天、每一个小时的统计数据

获取每一天的统计数据做项目的时候需要统对项目日志做分析,其中有一个需求是获取某个给定的时间段内,每一天的日志数据,比如说要获取从2018-02-02 09:18:36到2018-03-05 23:18:36这个时间段内,统计出每一天的日志数据,一般情况下,看到这种需求都是考虑使用函数来搞定,直接上sql语句 SELECT DATE_FORMAT(trigger_time, '%Y-%m-%d') triggerDay, COUNT(id) triggerCount FROM `job_qrtz_

mysql分组查询时,讲多个值合并在一行显示

mysql根据字段进行分组查询时,相同字段的数据,只会显示一个,如果要想让这个字段的所有数据,显示在一行里,可以在查询时用GROUP_CONTAT函数,默认数据合并以逗号,分开

mysql查询时不区分大小写

一次偶然的机会,发现在登陆验证时,改变用户名的大小写,同样可以登录成功,这是由于,当时使用的mysql数据库对大小写不敏感,查询时总是能查询到数据.一番查找资料,给出的原因是:在创建数据库的时候,选择了utf8_general_ci排序规则. 创建数据库时,需要同时选择字符集和排序规则,字符集大家都知道是怎么回事,那排序规则干嘛用的呢? 排序规则:是指对指定字符集下不同字符的比较规则.其特征有以下几点: 1. 两个不同的字符集不能有相同的排序规则 2. 两个字符集有一个默认的排序规则 3. 有一

mysql踩坑记录之limit和sum函数混合使用问题

问题复盘本次复盘会用一个很简单的订单表作为示例. 数据准备订单表建表语句如下(这里偷懒了,使用了自增ID,实际开发中不建议使用自增ID作为订单ID) CREATE TABLE `order` ( `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '订单ID', `amount` decimal(10,2) NOT NULL COMMENT '订单金额', PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=u

Mysql查询使用limit分页,同时使用order by可能产生的问题

昨天遇到一个比较诡异的问题,在使用MySQL分页查询数据的时候, 有的数据明明数据库里有,但是就是查不出来,有的数据却反而会 重复出现. 这里面就涉及到一个MySQL自身的问题. 具体现象大概是: 当使用order by 的字段有多个相同的结果,同时,此次结果不足以把 数据完全显示出来的时候.比如,使用order by对count字段排序, 同时使用limit 10规定取前10条.但是实际数据不止10条,那么,当使用sql 查询第二页的时候,也就是,使用limit 10,10来取第11-20条.

Mysql order by与limit混用陷阱

在Mysql中我们常常用order by来进行排序,使用limit来进行分页,当需要先排序后分页时我们往往使用类似的写法select * from 表名 order by 排序字段 limt M,N.但是这种写法却隐藏着较深的使用陷阱.在排序字段有数据重复的情况下,会很容易出现排序结果与预期不一致的问题. 比如现在有一张user表,表结构及数据如下: 表结构 表数据 现在想根据创建时间升序查询user表,并且分页查询,每页2条,那很容易写出sql为:select * from user orde

单表查询: where group by 分组 having distinct 去重 order by 排序 limit 多表查询 子查询 连表查询

今日内容 表查询 单表查询: where group by 分组 having distinct 去重 order by 排序 limit 多表查询 子查询 连表查询 单表查询 前期表准备 create table emp( id int not null unique auto_increment, name varchar(20) not null, sex enum('male','female') not null default 'male', #大部分是男的 age int(3) u