🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
### 一,有问题的代码 CleverCode发现在mysql有分页丢失数据的问题。如下面的代码,system_user表有400万行数据,这时候需要把这张表里面的所有的userid取出来。这时候只能分页取,一次取2万。 ~~~ //系统用户表(400万行的数据) $systemUserTable = new systemUserTable(); // 每次取20000 $pageSize = 20000; for($curPage = 1;; $curPage++) { $sql = "select userid from system_user order by userid asc limit " . (($curPage - 1) * $pageSize) . "," . $pageSize; //取数据 $rows = $systemUserTable->fetchAll($sql); // 没有数据了,结束 if (empty($rows)) { break; } // 遍历数据 foreach ( $rows as $key => $val ) { $userid = $val['userid']; echo $userid."\r\n"; } } ~~~ ### 二,问题分析 1)假如system_user只有10行数据(u1,u2,u3,u4,u5,u6,u7,u8,u9,u10)。 2) 这时候每次取5行。分2两次取。 3)正常情况第一页取(u1,u2,u3,u4,u5),正常情况第二页取(u6,u7,u8,u9,u10)。 4)如果在第一页去完,第二页取之前的时间间隙里面。u2,u3被删除了。 5)那么第二页取的时候。数据变成了(u1,u4,u5,u6,u7,u8,u9,u10)。 6)那么取出来第二页的数据就变成了(u8,u9,u10)。 7)u6,u7被丢失了。 ### 三,解决方案 每次取的时候where带着最大偏移量。如下面的代码。 ~~~ $systemUserTable = new systemUserTable(); // 每次取20000 $pageSize = 20000; // 每页最大编号 $pageMaxId = 0; while ( 1 ) { $sql = "select userid from system_user where userid > ${pageMaxId} order by userid asc limit " . $pageSize; //取数据 $rows = $fyHouse->fetchAll($sql); // 没有数据,结束 if (empty($rows)) { break; } // 遍历数据 foreach ( $rows as $key => $val ) { $userid = $val['userid']; // 记录当前最大分页编号 if ($userid > $pageMaxId) { $pageMaxId = $userid; } echo $userid."\r\n"; } } ~~~ 过程分析: 1)system_user只有10行数据(u1,u2,u3,u4,u5,u6,u7,u8,u9,u10)。 2) 第一次取,最大偏移量0,limit 5;则取出(u1,u2,u3,u4,u5)。记录最大的偏移量u5的值。 4)如果在第一页去完,第二页取之前的时间间隙里面。u2,u3被删除了。 5)那么第二页取的时候。数据变成了(u1,u4,u5,u6,u7,u8,u9,u10)。 3)第二次取,最大偏移量u5,limit 5;则取出(u6,u7,u8,u9,u10)。记录最大的偏移量u10的值。 ![](https://box.kancloud.cn/2016-03-29_56fa2a0c7acf5.jpg)