iis服务器助手广告广告
返回顶部
首页 > 资讯 > 数据库 >MYSQL如何实现ORDER BY和LIMIT
  • 956
分享到

MYSQL如何实现ORDER BY和LIMIT

2024-04-02 19:04:59 956人浏览 泡泡鱼
摘要

这篇文章主要为大家展示了“Mysql如何实现ORDER BY和LIMIT”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“mysql如何实现ORDER BY和LIM

这篇文章主要为大家展示了“Mysql如何实现ORDER BY和LIMIT”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“mysql如何实现ORDER BY和LIMIT”这篇文章吧。

一、MYsql中的LIMIT和oracle中的分页
在MYSQL官方文档中描述limit是在结果集中返回你需要的数据,它可以尽快的返回需要的行而不用管剩下的行,
在ORACLE中也有相关的语法比如 12C以前的rownun<n,也是达到同样的效果,同时limit也能做到分页查询如
limit n,m  则代表返回n开始的m行,ORACLE 12C以前也有分页方式但是相对比较麻烦
那么如果涉及到排序呢?我们需要返回按照字段排序后的某几行:
MYSQL:
select * from test order by id limit 51,100 
ORACLE 12C以前:
SELECT *
  FROM (SELECT tt.*, ROWNUM AS rowno
          FROM (SELECT t.*
                  FROM test t)
                 ORDER BY id desc) tt
         WHERE ROWNUM <= 100) table_alias
 WHERE table_alias.rowno > 50;


当然如上的语法如果id列有索引那么就简单了,索引本生就是排序好的,使用索引结构即可,但是如果id列没有索引呢?
那该如何完成,难道把id列全部排序好在返回需要的行?显然这样代价过高,违背了limit中尽快返回需要的行的精神
这样我们必须使用一种合适的算法来完成,那这里就引入的堆排序和优先队列(Priority Queue 简称PQ)。
在MYSQL中执行计划没有完全的表现,执行计划依然为filesort:
mysql> explain select * from testshared3 order by id limit 10,20;
+----+-------------+-------------+------------+------+---------------+------+---------+------+---------+----------+----------------+
| id | select_type | table       | partitions | type | possible_keys | key  | key_len | ref  | rows    | filtered | Extra          |
+----+-------------+-------------+------------+------+---------------+------+---------+------+---------+----------+----------------+
|  1 | SIMPLE      | testshared3 | NULL       | ALL  | NULL          | NULL | NULL    | NULL | 1023820 |   100.00 | Using filesort |
+----+-------------+-------------+------------+------+---------------+------+---------+------+---------+----------+----------------+
1 row in set, 1 warning (0.02 sec)


但是根据源码的提示
DBUG_PRINT("info", ("filesort PQ is applicable"));
DBUG_PRINT("info", ("filesort PQ is not applicable"));
注意这里PQ可能弃用,什么时候弃用看后面
可以看到是否启用了PQ也就是优先队列的简写 
可以再trace中找到相关说明:
[root@testmy tmp]# cat pq.trace |grep "filesort PQ is applicable"
T@2: | | | | | | | | | | info: filesort PQ is applicable


在ORACLE中使用执行计划:
--------------------------------------------------------------------------------
Plan hash value: 1473139430
--------------------------------------------------------------------------------
| Id  | Operation                | Name   | Rows  | Bytes |TempSpc| Cost (%CPU)|
--------------------------------------------------------------------------------
|   0 | SELECT STATEMENT         |        |   100 | 77900 |       | 85431   (1)|
|*  1 |  VIEW                    |        |   100 | 77900 |       | 85431   (1)|
|*  2 |   COUNT STOPKEY          |        |       |       |       |            |
|   3 |    VIEW                  |        |   718K|   524M|       | 85431   (1)|
|*  4 |     SORT ORDER BY STOPKEY|        |   718K|   325M|   431M| 85431   (1)|
|   5 |      TABLE ACCESS FULL   | TEST10 |   718K|   325M|       | 13078   (1)|


这里SORT ORDER BY STOPKEY就代表了排序停止,但是ORACLE没有源码没法确切的证据使用了
优先队列和堆排序,只能猜测他使用了优先队列和堆排序

二、堆排序和优先队列

--大顶堆特性(小顶堆相似见代码)
1、必须满足完全二叉树
关于完全二叉树参考
Http://blog.itpub.net/7728585/viewspace-2125889/
2、很方便的根据父节点的位置计算出两个叶子结点的位置
如果父节点的位置为i/2
左子节点为 i,右子节点为i+1
这是完全二叉树的特性决定
3、所有子节点都可以看做一个子堆那么所有结点都有
父节点>=左子节点 && 父节点>=右节点
4、很明显的可以找到最大的元素,就是整个堆的根结点

--堆需要完成操作
堆排序方法也是最优队列的实现方法,MYSQL源码中明显的使用了优先队列来优化order by limit n ,估计max也是用的这种算法
当然前提是没有使用到索引的情况下。
根据这些特性明显又是一个递归的成堆的操作。
参考算法导论第六章,里面的插图能够加深理解,这里截取一张构建好的大顶堆
MYSQL如何实现ORDER BY和LIMIT

构建方法:自下而上的构建自左向右构建堆,其实就是不断调用维护方法的过程
维护方法:使用递归的逐级下降的方法进行维护,是整个算法的核心内容,搞清楚了维护方法其他任何操作都来自于它。
排序方法:最大元素放到最后,然后逐层下降的方法进行调整。
数据库中的应用:
order by asc/desc limit n:简化的排序而已,只是排序前面n就可以了,不用全部排序完成,性能优越,数据库分页查询大量使用这个算法。参考代码
max/min :a[1]就是最大值,只能保证a[1]>=a[2]&&a[1]>=a[3]  不能保证a[3]>=a[4],堆建立完成后就可以找到MAX值,但是MYSQL max并没有使用这个算法

我在代码中完成了这些操作,代码中有比较详细的注释,这里就不详细说明了。
我使用了2个数组用于作为测试数据
        int i,a[11]={0,999,3,2,9,34,5,102,90,2222,1}; //测试数据 a[0]不使用
        int b[11]={0,999,3,2,9,999,888888,102,90,2222,111};//测试数据 b[0]不使用

分别求a素组的最大值和最小前3位数字,求b数组的MAX/MIN值,结果如下:
gaopeng@boGon:~/datas$ ./a.out 
大顶堆:
order by desc a array limit 3 result:2222 999 102 
max values b array reulst:888888 
小顶堆:
order by asc a array limit 3 result:1 2 3 
min values b array reulst:2 
可以看到没问题。


--优先队列:优先队列不同于普通队列先进先出的规则,而定义为以某种规定先出,比如最大先出或者最小先出,这个没什么难度了,不就和数据库的order
            by limit是一回事吗?当然是用大顶堆或者小顶堆完成
 
三、MYSQL中优先队列的接口

MYSQL中的优先队列类在
priority_queue.h中的class Priority_queue : public Less
他实现了很多功能,不过其他功能都很简单主要是堆的维护
下面是MYSQL源码中的堆的维护代码
  void heapify(size_type i, size_type last)
  {
    DBUG_ASSERT(i < size());
    size_type largest = i;

    do
    {
      i = largest;
      size_type l = left(i);
      size_type r = right(i);


      if (l < last && Base::operator()(m_container[i], m_container[l]))
      {
        largest = l;
      }


      if (r < last && Base::operator()(m_container[largest], m_container[r]))
      {
        largest = r;
      }


      if (largest != i)
      {
        std::swap(m_container[i], m_container[largest]);
      }
    } while (largest != i);
  }
可以看见实际和我写的差不多。


四、MYSQL如何判断是否启用PQ
一般来说快速排序的效率高于堆排序,但是堆排序有着天生的特点可以实现优先队列,来实现
order by limit 

(关于快速排序参考:http://blog.itpub.net/7728585/viewspace-2130743/)

那么这里就涉及一个问题,那就是快速排序和最优的队列的临界切换,比如
表A 100W行记录 id列没有索引
select * from a order by id limit 10;

select * from a order by id limit 900000,10;

肯定前者应该使用最优队列,而后者实际上要排序好至少900010行数据才能返回。
那么这个时候应该使用快速排序,那么trace信息应该为
filesort PQ is not applicable
[root@testmy tmp]# cat pqdis.trace |grep "filesort PQ "
T@2: | | | | | | | | | | info: filesort PQ is not applicable

那么MYSQL值确定是否使用PQ,其判定接口为check_if_pq_applicable函数,
简单的说MYSQL认为堆排序比快速排序慢3倍如下:
 
  const double PQ_slowness= 3.0;


所以就要进行算法的切换,但是具体算法没有仔细研究可以自行参考check_if_pq_applicable函数
至少和下面有关
1、是否能够在内存中完成
2、排序行数
3、字段数


最后需要说明一点PQ排序关闭了一次访问排序的pack功能如下:
   

五、实现代码,维护方法列出了2种实现,方法2是算法导论上的更容易理解

点击(此处)折叠或打开



  1. #include<stdio.h>

  2. #include<stdlib.h>


  3. #define LEFT(i) i<<1

  4. #define RIGTH(i) (i<<1)+1

  5. //堆排序的性能不及快速排序但是在某些情况下非常有用

  6. //数据库的order by limit使用了优先队列,基于堆排序


  7. int swap(int k[],int i,int j)

  8. {

  9.         int temp;


  10.         temp = k[i];

  11.         k[i] = k[j];

  12.         k[j] = temp;

  13.         return 0;

  14. }



  15. int bigheapad(int k[],int s,int n) //s=4,n=9

  16. {

  17.         

  18.         // two: 参考算法导论P155页,整个方法更容易理解其原理,调整使用逐层下降的方法进行调整

  19.         int l; //s 左节点编号

  20.         int r; //s 右节点编号

  21.         int largest;


  22.         l=LEFT(s); //左节点编号

  23.         r=RIGTH(s);//右节点编号


  24.         if(s<=n/2) // n/2为最小节点编号的父亲节点 如果s大于这个值说明这个节点不会有任何子节点不需要进行调整 !!,这是整个算法的核心中的核心。搞了我老半天

  25.         {

  26.                 if (l<=n && k[l] > k[s])

  27.                 {

  28.                         largest = l;

  29.                 }

  30.                 else

  31.                 {

  32.                         largest = s;

  33.                 }


  34.                 if(r<=n && k[r] > k[largest])

  35.                 {

  36.                         largest = r;

  37.                 }


  38.                 if(largest != s)

  39.                 {

  40.                         swap(k,largest,s);

  41.                         bigheapad(k,largest,n); //对数据调整后可能的子节点树继续进行调整直到达到递归退出条件

  42.                 }

  43.         }

  44. return 0;

  45. }



  46. int bigheapbulid(int k[],int n)

  47. {

  48.         int i;

  49.         for(i=n/2;i>0;i--)//采用自底向上的方法构建 算法导论P156 EXP 1:i= n/2 p:4 l:8 r:9  2: i = p:3 l:6 r:7  n/2刚好是最后一个节点的父亲节点所以自下而上

  50.         {

  51.                 bigheapad(k,i,n);

  52.         }

  53. return 0;


  54. }


  55. int bigheapsort(int k[],int n) //sort的过程就是将最大元素放到最后,然后逐层下降的方法进行调整

  56. {

  57.         int i;

  58.         for(i=n;i>1;i--)

  59.         {

  60.                 swap(k,1,i);

  61.                 bigheapad(k,1,i-1);

  62.         }

  63. return 0;

  64. }


  65. int biglimitn(int k[],int n,int limitn)//limit 也是我关心的 这里明显可以看到他的优势实际它不需要对整个数组排序,你要多少我排多少给你就好,也是最大元素放到最后,然后逐层下降的方法进行调整的原理

  66. {

  67.         int i;

  68.         for(i=n;i>n-limitn;i--)

  69.         {

  70.                 swap(k,1,i);

  71.                 bigheapad(k,1,i-1);

  72.         }

  73. return 0;

  74. }


  75. int smallheapad(int k[],int s,int n) //s=4,n=9

  76. {


  77.         int l; //s 左节点编号

  78.         int r; //s 右节点编号

  79.         int smallest;


  80.         l=LEFT(s); //左节点编号

  81.         r=RIGTH(s);//右节点编号


  82.         if(s<=n/2) // n/2为最小节点编号的父亲节点 如果s大于这个值说明这个节点不会有任何子节点不需要进行调整 !!

  83.         {


  84.                 if (l<=n && k[l] < k[s])

  85.                 {


  86.                         smallest = l;

  87.                 }

  88.                 else

  89.                 {


  90.                         smallest = s;

  91.                 }


  92.                 if(r<=n && k[r] < k[smallest])

  93.                 {


  94.                         smallest = r;

  95.                 }


  96.                 if(smallest != s)

  97.                 {


  98.                         swap(k,smallest,s);

  99.                         smallheapad(k,smallest,n); //对数据调整后可能的子节点树继续进行调整直到达到递归退出条件

  100.                 }

  101.         } 

  102. return 0;

  103. }



  104. int smallheapbulid(int k[],int n)

  105. {


  106.         int i;

  107.         for(i=n/2;i>0;i--)

  108.         {


  109.                 smallheapad(k,i,n);

  110.         }

  111. return 0;

  112. }


  113. int smallheapsort(int k[],int n)

  114. {


  115.         int i;

  116.         for(i=n;i>1;i--)

  117.         {


  118.                 swap(k,1,i);

  119.                 smallheapad(k,1,i-1);

  120.         }

  121. return 0;

  122. }


  123. int smalllimitn(int k[],int n,int limitn)

  124. {


  125.         int i;

  126.         for(i=n;i>n-limitn;i--)

  127.         {


  128.                 swap(k,1,i);

  129.                 smallheapad(k,1,i-1);

  130.         }

  131. return 0;

  132. }



  133. int main()

  134. {


  135.         int i,a[11]={0,999,3,2,9,34,5,102,90,2222,1}; //测试数据 a[0]不使用

  136.         int b[11]={0,999,3,2,9,999,888888,102,90,2222,111};//测试数据 b[0]不使用

  137.         bigheapbulid(a,10);

  138.         biglimitn(a,10,3);


  139.         printf("大顶堆:\n");

  140.         printf("order by desc a array limit 3 result:");

  141.         for(i=10;i>10-3;i--)

  142.         {

  143.                 printf("%d ",a[i]);

  144.         }

  145.         printf("\n");

  146.         bigheapbulid(b,10);

  147.         printf("max values b array reulst:");

  148.         printf("%d \n",b[1]);


  149.         smallheapbulid(a,10);

  150.         smalllimitn(a,10,3);

  151.         printf("小顶堆:\n");

  152.         printf("order by asc a array limit 3 result:");

  153.         for(i=10;i>10-3;i--)

  154.         {

  155.                 printf("%d ",a[i]);

  156.         }

  157.         printf("\n");

  158.         smallheapbulid(b,10);

  159.         printf("min values b array reulst:");

  160.         printf("%d \n",b[1]);

  161. return 0;

  162. }

以上是“MYSQL如何实现ORDER BY和LIMIT”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注编程网数据库频道!

您可能感兴趣的文档:

--结束END--

本文标题: MYSQL如何实现ORDER BY和LIMIT

本文链接: https://www.lsjlt.com/news/62321.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • MYSQL如何实现ORDER BY和LIMIT
    这篇文章主要为大家展示了“MYSQL如何实现ORDER BY和LIMIT”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“MYSQL如何实现ORDER BY和LIM...
    99+
    2024-04-02
  • mysql order by limit的坑怎么解决
    这篇文章主要介绍“mysql order by limit的坑怎么解决”,在日常操作中,相信很多人在mysql order by limit的坑怎么解决问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操...
    99+
    2024-04-02
  • mysql中order by如何用
    本篇内容主要讲解“mysql中order by如何用”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“mysql中order by如何用”吧! ...
    99+
    2024-04-02
  • (转)MySQL ORDER BY 的实现分析
    作者:Sky.Jian | 可以任意转载, 但转载时务必以超链接形式标明文章原始出处 和 作者信息 及 版权声明 链接:http://www.jianzhaoyang.com/database/mysql_...
    99+
    2024-04-02
  • MySQL中Order By如何使用
    这篇文章将为大家详细讲解有关MySQL中Order By如何使用,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。 ORDER BY uid ASC 按照u...
    99+
    2024-04-02
  • MySQL索引查询limit offset及排序order by用法
    目录引言使用 limit 和 offset 来限制返回的数量1、limit2、offsetorder by 的如下几个用法1、order by 的升序、倒序2、多个字段排序3、按照中文排序引言 “ ...
    99+
    2023-05-20
    MySQL limit offset order by MySQL 索引查询
  • MySQL中关于排序order by limit值不稳定分析
    这篇文章主要介绍“MySQL中关于排序order by limit值不稳定分析”,在日常操作中,相信很多人在MySQL中关于排序order by limit值不稳定分析问题上存在疑惑,小编查阅了各式资料,整...
    99+
    2024-04-02
  • MySQL order by与group by查询优化实现详解
    目录前言where与order by满足最左匹配法则中间断裂大哥不在范围失效order by 次序相反覆盖索引filesort的两种算法group by前言 order by满足两种情况,会使用 index 方...
    99+
    2024-04-02
  • order by+limit分页时数据重复问题如何解决
    本文小编为大家详细介绍“order by+limit分页时数据重复问题如何解决”,内容详细,步骤清晰,细节处理妥当,希望这篇“order by+limit分页时数据重复问题如何解决”文章能帮助大家解决疑惑,下面跟着小编的...
    99+
    2023-07-05
  • MySQL中如何优化order by语句
    order by 查询语句使用也是非常频繁,有时候数据量大了会发现排序查询很慢,本文就介绍一下 mysql 是如何进行排序的,以及如何利用其原理来优化 order by 语句。 建立一张表: CREATE TABLE `...
    99+
    2023-01-12
    MySQL优化orderby 优化orderby
  • mysql查询语句group by和order by的使用
    这篇文章主要讲解了“mysql查询语句group by和order by的使用”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“mysql查询语句group b...
    99+
    2024-04-02
  • MySQL中如何优化Order By Rand()效率
    这篇文章主要介绍了MySQL中如何优化Order By Rand()效率,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。 最近由于需要大概研...
    99+
    2024-04-02
  • 如何在Mysql中优化order by语句
    这篇文章给大家介绍如何在Mysql中优化order by语句,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。MySQL中的两种排序方式1.通过有序索引顺序扫描直接返回有序数据因为索引的结...
    99+
    2024-04-02
  • 如何进行MySQL中的order by 优化
    这篇文章将为大家详细讲解有关如何进行MySQL中的order by 优化,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。 一 前言...
    99+
    2024-04-02
  • 怎么解决MySQL分页时使用 limit+order by出现数据重复的问题
    这期内容当中小编将会给大家带来有关怎么解决MySQL分页时使用 limit+order by出现数据重复的问题,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。0 问题描述在...
    99+
    2024-04-02
  • sql中order by降序怎么实现
    在SQL中,可以使用DESC关键字来实现ORDER BY降序排列。例如: SELECT * FROM table_name ...
    99+
    2024-04-09
    sql
  • 编码踩坑——MySQL order by&limit顺序不一致 / 堆排序 / 排序稳定性
    本篇介绍一个MySQL下SQL查询语句同时包含order by和limit出现的一个问题及原因,其中涉及的知识点包括 :MySQL对limit的优化、MySQL的order排序、优先级队列和堆排序、堆排序的不稳定性; 问题现象 后台...
    99+
    2023-10-01
    mysql order by limit 堆排序 排序稳定性 Powered by 金山文档
  • 如何优化sql中order By语句
    这篇文章主要介绍“如何优化sql中order By语句”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“如何优化sql中order By语句”文章能帮助大家解决问题。在...
    99+
    2024-04-02
  • mysql中order by和分组能一起使用么
    是的,mysql 允许在分组查询中使用 order by 子句排序结果,步骤如下:分组数据(group by)聚合数据(使用聚合函数)排序结果(order by) MySQL 中 OR...
    99+
    2024-05-09
    mysql 聚合函数
  • 我们如何使用 ORDER BY 子句创建 MySQL 视图?
    我们可以使用 MySQL ORDER BY 子句对结果集中的记录进行排序。 。为了理解带有视图的 GROUP BY 子句,我们使用具有以下数据的基表“Student_info”创建一个名为“Info”的视图 -mysql> Selec...
    99+
    2023-10-22
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作