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 * FROM mytable WHERE id IN (1,2,3,4) ORDER BY FIELD(id,3,2,1,4);
应该也可以工作,因为您不必在
WHERE
子句中订购列表关于其工作方式,
FIELD()是一个函数,如果要搜索的值存在,该函数将返回逗号分隔列表的索引位置。
如果id id = 1,则FIELD(id,3,2,1,4)返回3(列表中的位置1)
如果id = 2,则FIELD(id,3, 2,1,4)返回2(列表中2的位置)
如果id = 3,则FIELD(id,3,2,1,4)返回1(列表中3的位置)
如果id id = 4,则FIELD(id,3,2,1,4)返回4(列表中的位置,其中4在列表中)。
如果id =其他,则FIELD(id,3, 2,1,4)返回0(不在列表中)
ORDER BY
值由FIELD()返回的值评估您可以创建各种订单数量
例如,使用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出现在t列表中的操作,否则,它会显示在底部。为什么?
在
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);
,您仍然会得到0或1。
如果第一列为1,则除了前4个ID之外,都显示其他内容。
如果第一列为0,则使前4个ID按原始顺序显示
您的实际问题
如果您真的想要此内部说明,请转到本书的第189页和第192页
进行真正的深潜。
本质上,存在一个名为
ORDER BY
(ORDER *order
表达式树)的C ++类。在ORDER BY
中,JOIN::prepare
用于名为*order
的函数中。为什么在setup_order()
班级中间?每个查询,甚至是针对单个表的查询都始终作为JOIN处理(请参阅我的文章JOIN条件和WHERE条件之间是否存在执行区别?) JOIN
显然,
sql/sql_select.cc
树将保留ORDER BY
的评估。因此,数字0、1、2、3、4是在对涉及的行进行引用的同时正在排序的值。评论
这是一个非常出色的解释。使用这些方法,我可以得到3个订单,第一个优先值是集合的最大值,然后是FIELD,然后是不是FIELD集合中的那些的另一列。我前段时间梦dream以求的东西。感谢您抽出宝贵的时间来真正解释它是如何工作的。
–蜥蜴
16年5月4日在23:03
假设IN和FIELD中都包含N个值。在此示例中,N = 4。我是否正确理解该查询将至少执行〜N ^ 2个操作。因为每个FIELD计算都会为每行进行一次〜N个比较。如果是这样,那么对于大N来说这相当慢,也许这不是一个很好的方法?
–盖尔曼
19 Mar 15 '19在15:53
@Gherman FIELD()函数应该是O(1)操作,因为FIELD()具有数字索引ID。因此,除了基于行的O(n)外,我什么都看不到。我看不到FIELD()要做任何迭代操作,例如GREATEST()。
– RolandoMySQLDBA
19 Mar 15 '19在18:03
@RolandoMySQLDBA我的观点是,如果FIELD具有N个要比较的参数,则它将执行N个比较。如果不通过O(N)比较一个数字和N个其他数字,还有什么其他方法?我能想到的唯一可能性是通过特殊数据结构(例如哈希或参数树)进行某种优化。实际上,我知道IN确实具有这种优化。我不了解FIELD。 “数字索引”是什么意思?
–盖尔曼
19 Mar 15 '19在20:18
嘿@RaymondNijland,CASE语句更容易理解,在这种情况下,语法糖的文字更少。
– RolandoMySQLDBA
19-10-3在14:08
#2 楼
也许这与实际代码相差太远,因此与您想要的代码相比还不够低:当MySQL无法使用索引来按排序顺序检索数据时,它将创建一个具有所有选定列的临时表/结果集还有一些其他数据(其中之一是某种类型的列,用于存储每一行的ORDER BY表达式值的结果),然后将此tmp表发送到“ filesort”程序,其中包含要对哪一列进行排序的信息。之后,这些行将按排序顺序排列,以便可以一一挑选它们并返回选定的列。
评论
该解释未考虑如何计算FIELD的功能。恐怕会对性能产生重大影响。
–盖尔曼
19年3月15日在16:07
@Gherman我不这么认为,除非您使用了很长的参数列表(因为该函数与参数数量成线性关系。数据访问比简单比较慢一个数量级)。
– jkavalik
19 Mar 15 '19在17:23
是的,一长串参数。此示例中的参数与记录一样多。
–盖尔曼
19年3月15日在20:20
我只会标注成百上千的标签,然后无论如何都会遇到其他问题(查询大小等)。
– jkavalik
19 Mar 15 '19在20:42
为什么没有数百个结果?有很多吗
–盖尔曼
19 Mar 15 '19在22:18
评论
尝试使用以下查询变体:SELECT *,FIELD(id,3,2,1,4)AS f FROM mytable WHERE id IN(3,2,1,4);然后添加ORDER BY f或ORDER BY FIELD(id,3,2,1,4),然后重试。