摘要

能把复杂的知识讲的简单很重要

在学习的过程中我们看过很多资料、视频、文档等,因为现在资料视频都较多所以往往一个知识点会有多种多样的视频形式讲解。除了推广营销以外,确实有很多人的视频讲解非常优秀,例如李永乐老师的短视频课,可以在一个黑板上把那么复杂的知识,讲解的那么容易理解,那么透彻。而我们学习编程的人也是,不只是要学会把知识点讲明白,也要写明白。

问题描述

在 MySQL 中我们通常会采用 limit 来进行翻页查询,比如 limit(0,10) 表示列出第一页的10条数据, limit(10,10) 表示列出第二页。但是,当 limit 遇到 order by 的时候,可能会出现翻到第二页的时候,竟然又出现了第一页的记录。

具体如下:

SELECT  `post_title`,  `post_date`FROM  postWHERE  `post_status` = 'publish'ORDER BY  view_count descLIMIT  5, 5
SELECT  *FROM  postWHERE  post_status = 'publish'ORDER BY  view_count descLIMIT  5, 5
SELECT  `post_title`,  `post_date`FROM  postWHERE  `post_status` = 'publish'ORDER BY  view_count desc,  ID ascLIMIT  5, 5

分析问题

在 MySQL 5.6 的版本上,优化器在遇到 order by limit 语句的时候,做了一个优化,即 使用了 priority queue。

使用 priority queue 的目的,就是在不能使用索引有序性的时候,如果要排序,并且使用了 limit n,那么只需要在排序的过程中,保留n条记录即可,这样虽然不能解决所有记录都需要排序的开销,但是只需要 sort buffer 少量的内存就可以完成排序。

之所以 MySQL 5.6 出现了第二页数据重复的问题,是因为 priority queue 使用了堆排序的排序方法,而堆排序是一个不稳定的排序方法,也就是相同的值可能排序出来的结果和读出来的数据顺序不一致。

MySQL 5.5 没有这个优化,所以也就不会出现这个问题。

也就是说,MySQL 5.5 是不存在本文提到的问题的,5.6 版本之后才出现了这种情况。

再看下MySQL解释sql语言时的执行顺序:

(1) SELECT
(2) DISTINCT <select_list>
(3) FROM <left_table>
(4) <join_type> JOIN <right_table>
(5) ON <join_condition>
(6) WHERE <where_condition>
(7) GROUP BY <group_by_list>
(8) HAVING <having_condition>
(9) ORDER BY <order_by_condition>
(10) LIMIT <limit_number>

执行顺序依次为 form… where… select… order by… limit… ,由于上述 priority queue 的原因,在完成 select 之后,所有记录是以堆排序的方法排列的,在进行 order by 时,仅把 view_count 值大的往前移动。

但由于 limit 的因素,排序过程中只需要保留到5条记录即可, view_count 并不具备索引有序性,所以当第二页数据要展示时, mysql 见到哪一条就拿哪一条,因此,当排序值相同的时候,第一次排序是随意排的,第二次再执行该sql的时候,其结果应该和第一次结果一样。

解决问题

(1) 索引排序字段

如果在字段添加上索引,就直接按照索引的有序性进行读取并分页,从而可以规避遇到的这个问题。

(2) 正确理解分页

分页是建立在排序的基础上,进行了数量范围分割。排序是数据库提供的功能,而分页却是衍生出来的应用需求。

在 MySQL 和 Oracle 的官方文档中提供了 limit n 和 rownum < n 的方法,但却没有明确的定义分页这个概念。

还有重要的一点,虽然上面的解决方法可以缓解用户的这个问题,但按照用户的理解,依然还有问题:比如,这个表插入比较频繁,用户查询的时候,在 read-committed 的隔离级别下,第一页和第二页仍然会有重合。

所以,分页一直都有这个问题,不同场景对数据分页都没有非常高的准确性要求。

(3) 一些常见的数据库排序问题

不加 order by 的时候的排序问题

用户在使用 Oracle 或 MySQL 的时候,发现 MySQL 总是有序的, Oracle 却很混乱,这个主要是因为 Oracle 是堆表, MySQL 是索引聚簇表的原因。所以没有 order by 的时候,数据库并不保证记录返回的顺序性,并且不保证每次返回都一致的。

分页问题 分页重复的问题

如前面所描述的,分页是在数据库提供的排序功能的基础上,衍生出来的应用需求,数据库并不保证分页的重复问题。

NULL值和空串问题

不同的数据库对于 NULL 值和空串的理解和处理是不一样的,比如 Oracle NULL 和 NULL 值是无法比较的,既不是相等也不是不相等,是未知的。而对于空串,在插入的时候, MySQL 是一个字符串长度为0的空串,而 Oracle 则直接进行 NULL 值处理。

更多相关文章

  1. mybatisplus的坑 insert标签insert into select无参数问题的解决
  2. python起点网月票榜字体反爬案例
  3. 《Android开发从零开始》——25.数据存储(4)
  4. Android系统配置数据库注释(settings.db)
  5. Android中不同应用间实现SharedPreferences数据共享
  6. android图表ichartjs
  7. Android内容提供者源码
  8. android SharedPreferences
  9. Android(安卓)Paging组件Demo

随机推荐

  1. Android学习之路(一)之 Android文件简单介
  2. Android(安卓)ListView滑动过程中图片显
  3. Android 程式开发:(一)详解Activity —— 1.
  4. Android撬动IT市场的新支点!
  5. Android的init过程详解(一)
  6. 《程序人生 —— Android实现录音、播音
  7. Android 不要把android做成ios!
  8. Android 图片加载Bit地图 OOM异常解决方
  9. Android进程与线程基本知识一
  10. 微软的 Android 计划:邪恶的天才计划或只