MySQL中的ORDER BY FIELD()如何在内部工作


37

我了解ORDER BY子句的工作方式以及该FIELD()函数的工作方式。我想了解的是两者如何一起工作进行排序。如何检索行以及如何导出排序顺序

+----+---------+
| id |  name   |
+----+---------+
|  1 | stan    |
|  2 | kyle    |
|  3 | kenny   |
|  4 | cartman |
+----+---------+ 

SELECT * FROM mytable WHERE id IN (3,2,1,4) ORDER BY FIELD(id,3,2,1,4)

上面的查询将导致

+----+---------+
| id |  name   |
+----+---------+
|  3 | kenny   |
|  2 | kyle    |
|  1 | stan    |
|  4 | cartman |
+----+---------+ 

类似于说ORDER BY 3,2,1,4

问题

  • 这在内部如何运作?
  • MySQL如何获取行并计算排序顺序?
  • MySQL如何知道它必须按id列排序?

1
尝试使用以下查询变体:SELECT *, FIELD(id,3,2,1,4) AS f FROM mytable WHERE id IN (3,2,1,4);然后添加ORDER BY fORDER BY FIELD(id,3,2,1,4)再试一次。
ypercubeᵀᴹ

Answers:


64

作为记录

SELECT * FROM mytable WHERE id IN (1,2,3,4) ORDER BY FIELD(id,3,2,1,4);

应该也可以正常工作,因为您不必在WHERE子句中排序列表

至于运作方式

您可以创建各种花哨的订单

例如,使用IF()函数

SELECT * FROM mytable
WHERE id IN (1,2,3,4)
ORDER BY IF(FIELD(id,3,2,1,4)=0,1,0),FIELD(id,3,2,1,4);

这将导致前4个ID出现在列表的顶部,否则,它将出现在列表的底部。为什么?

在中ORDER BY,您将得到0或1。

  • 如果第一列为0,请显示前4个ID中的任何一个
  • 如果第一列为1,则在其后显示

让我们在第一列中使用DESC进行翻转

SELECT * FROM mytable
WHERE id IN (1,2,3,4)
ORDER BY IF(FIELD(id,3,2,1,4)=0,1,0) DESC,FIELD(id,3,2,1,4);

在中ORDER BY,您仍然会得到0或1。

  • 如果第一列为1,则除了前4个ID以外,均不显示任何内容。
  • 如果第一列为0,则使前4个ID按原始顺序显示

您的实际问题

如果您真的想要此内容的内部结构,请转至《圣经》第189页和第192页

MySQL内部

进行真正的深潜。

本质上,有一个称为ORDER *orderORDER BY表达式树)的C ++类。在中JOIN::prepare*order用于称为的函数中setup_order()为什么在JOIN班级中间? 每个查询,甚至针对单个表的查询都始终作为JOIN处理(请参阅我的文章JOIN条件和WHERE条件之间是否存在执行差异?

所有这些的源代码是 sql/sql_select.cc

显然,ORDER BY树将对进行评估FIELD(id,3,2,1,4)。因此,数字0、1、2、3、4是在对涉及的行进行引用的同时进行排序的值。


1
这是一个非常出色的解释。使用这些方法,我可以得到3个阶数,即第一个第一个值是集合的最大值,然后是FIELD,然后是不是FIELD集合中的那些的另一列。我前段时间梦dream以求的东西。感谢您抽出宝贵的时间来真正解释它是如何工作的。
蜥蜴人

假设有N两个数值INFIELD。在这个例子中N=4。我是否正确理解该查询将至少执行~N^2操作。因为每次FIELD计算都~N对每一行进行一次比较。如果是这样,那么这对于大型企业来说相当慢,N也许这不是一个很好的方法?
Gherman

@Gherman该FIELD()函数应该是一个O(1)操作,因为FIELD()它具有数字索引id。因此,除了O(n)基于行之外,我什么都看不到。我看不到需要FIELD()做的任何迭代操作GREATEST()
RolandoMySQLDBA

@RolandoMySQLDBA我的观点是,如果FIELDN要比较的参数,它将执行N比较。N如果不这样做,那么如何将一个数字与其他数字进行比较O(N)?我能想到的唯一可能性是通过特殊数据结构(例如哈希或参数树)进行某种优化。其实我知道IN确实有这样的优化。我不知道FIELD。“数字索引”是什么意思?
盖尔曼

1
嘿@RaymondNijland,CASE语句更容易理解,在这种情况下,语法糖的文字更少。
RolandoMySQLDBA

1

也许这与实际代码相距太远,因此距离您想要的水平还不够低:

当MySQL无法使用索引按排序顺序检索数据时,它将创建一个临时表/结果集,其中包含所有选定的列和一些其他数据-其中之一是某种类型的列,用于存储每一行​​的ORDER BY表达式值的结果-然后它将tmp表发送到“ filesort”规则,其中包含要对哪一列进行排序的信息。之后,这些行将按排序顺序排列,以便可以一一挑选它们并返回选定的列。


该解释未考虑FIELD函数的计算方式。恐怕会对性能产生重大影响。
Gherman

@Gherman我不这么认为,除非您使用了很长的参数列表(因为该函数与参数数量成线性关系。数据访问比简单的比较慢一个数量级。)
jkavalik

是的,一长串参数。此示例中的参数与记录一样多。
盖尔曼

我只会标注成百上千的标签,然后无论如何都会遇到其他问题(查询大小等)
jkavalik

为什么没有数百个结果?有很多吗
盖尔曼
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.