有一个表 x:
select * from x;
+------+------+
| a | b |
+------+------+
| aaa | 999 |
| bbb | 888 |
| ccc | 777 |
+------+------+
Run Code Online (Sandbox Code Playgroud)
以下查询有什么作用?
select * from x order by a < b;
select * from x order by a = b;
select * from x order by a <> b;
select * from x order by a <> b, b;
Run Code Online (Sandbox Code Playgroud)
这个运营商的名字是什么?我在 MySQL 文档中没有找到关于这个主题的任何内容。
这是常见的比较运算符。
执行比较时,会产生一些布尔结果。它可能是 TRUE、FALSE 或 NULL。
这 3 个值相关为
NULL < FALSE < TRUE
Run Code Online (Sandbox Code Playgroud)
该关系用于排序。
例如:
select * from x order by a<b;
Run Code Online (Sandbox Code Playgroud)
如果a和/或b为 NULL,则排序表达式的结果(比较结果)为 NULL,此类记录将位于输出的开头。
如果a小于则b排序表达式的结果为 TRUE,并且此类记录将位于输出的末尾。
a大于或等于的记录b将在中间。
这些查询都不应该工作 - 它们是可憎的。编写可以查询 a 是否INTEGER小于、等于或大于 a 的SQLCHAR(n)/VARCHAR(n)/TEXT/<any_character_field>是完全没有意义的!
显示了"REAL"数据库服务器(在本例中为 PostgreSQL)如何处理此类恐怖事件(显示here了其中一个查询的示例输出):
错误:运算符不存在:字符 < 整数第 1 行:选择 * from x order by a<b;
^ 提示:没有运算符匹配给定的名称和参数类型。您可能需要添加显式类型转换。
这些查询在dbfiddle.uk除 MariaDB 之外的所有其他服务器上也会失败(赞美!),这显然对与 MySQL 的 bug-for-bug 兼容有既得利益。这并不奇怪,因为这两个服务器的主要贡献者有相当大的重叠——Monty Widenius是 MariaDB 的 CTO,并且是 MySQL 的创始人,而 MariaDB 被吹捧为 MySQL 的替代品。
MySQL 的 InnoDB 引擎有一种生成 IMPLICIT PRIMARY KEY 的机制,即使 dba/dev 没有声明一个!
从here,我们有(来自 MySQL 文档的引用 - 在帖子中链接到):
如果表没有 PRIMARY KEY 或合适的 UNIQUE 索引,InnoDB 在包含行 ID 值的合成列上内部生成一个名为 GEN_CLUST_INDEX 的隐藏聚集索引。行按 InnoDB 分配给此类表中行的 ID 排序。行 ID 是一个 6 字节的字段,随着插入新行而单调增加。因此,按行 ID 排序的行在物理上是按插入顺序排列的。
不幸的是,您无法访问此伪列。没有可访问的隐藏字段 - 不像 Oracle 的服务器那样说,它有大量这样的字段,可以SELECT(参见 参考资料here)。
在 InnoDB 中,如果您不提供 PRIMARY KEY(和...),则隐藏的 BIGINT 将用作 PK。但你不能得到它。
上一个链接中提到的文档说它是一个 6 字节INTEGER而不是一个 BIGINT(但是它8 Bytes - 64 bit与本讨论无关)。
另一个证据是here来自的帖子Bill Karwin。他要么是一个或将MySQL的社区经理,你可以从他的个人资料中看到,是在计算器上一个相当大的打者与> 40万点。他说:
如果没有明确的 ORDER BY,当前版本的 InnoDB 会按照它读取的索引的顺序返回行。哪个索引不同,但它总是从某个索引读取。甚至从“表”中读取也是一个索引——它是主键索引。
正如上面的评论一样,不能保证在 InnoDB 的下一个版本中这将保持不变。您应该将其视为巧合的行为,它没有记录,并且 MySQL 的制造商不承诺不会更改它。
同样在那篇文章中,他举例说明了 MySQL 将如何处理不同的SELECTs 和INDEXes - 值得阅读整个线程!
因此,基本上,如果! 中没有其他字段,MySQL 似乎会按隐式PK(按INSERT顺序)排序 几个简单的测试[ , ]演示了这一点(仅来自第一个测试的结果,如果感兴趣,请参考另一个):KEYSELECT12
CREATE TABLE a (b VARCHAR(10), c INT);
INSERT INTO a VALUES ('aaa', 999), ('bbb', 888), ('ccc', 777);
Run Code Online (Sandbox Code Playgroud)
和
CREATE TABLE x (y VARCHAR(10), z INT);
INSERT INTO x VALUES ('ccc', 777), ('bbb', 888), ('aaa', 999);
Run Code Online (Sandbox Code Playgroud)
运行:
SELECT * FROM a;
Run Code Online (Sandbox Code Playgroud)
结果:
b c
aaa 999
bbb 888
ccc 777
Run Code Online (Sandbox Code Playgroud)
这可能是对第一个字段的简单 ASCII 排序。但是,现在将其与:
SELECT * FROM x;
Run Code Online (Sandbox Code Playgroud)
结果:
y z
ccc 777
bbb 888
aaa 999
Run Code Online (Sandbox Code Playgroud)
但这不是第一个字段的 ASCII 排序。没有 PK,因此它使用(implicit) clustered index PK (*)按插入顺序排序的 !
(*) 这是 MySQL 执行 PK 的方式 - 并非所有服务器都这样做 - 我无法想到另一个默认情况下执行此操作的系统。MySQL 中的所有 PK 都是集群的。
我已经重写了您的查询(请参阅测试 1),以便您可以更好地了解发生了什么!
select a, b, a = b
from x
order by a = b;
Run Code Online (Sandbox Code Playgroud)
结果:
a b a = b
aaa 999 0
bbb 888 0
ccc 777 0
Run Code Online (Sandbox Code Playgroud)
在这里,表达式a = b总是假的,因此它按隐藏的 PK 排序,这取决于 INSERT 顺序!
进而:
select a, b, a <> b
from x
order by a <> b, b;
Run Code Online (Sandbox Code Playgroud)
结果:
a b a <> b
ccc 777 1
bbb 888 1
aaa 999 1
Run Code Online (Sandbox Code Playgroud)
在第二种情况下,a != b总是为真,因此它按explicitly specifiedORDER BY 中的第二个(这次)字段排序,即 ( b)!无需依赖隐式PK!
你应该能够从那里找出其余的!
正如上面提到的比尔Karwin指出,这是一个未记录的功能,并应不被依赖并可以去除/随时修改。
数据库社区普遍同意,如果你想要一个给定的顺序,那么你应该在ORDER BY子句中指定它,而不是依赖可能在未来版本中改变的未记录的功能!
ps 欢迎来到论坛!还有一个 +1 来提醒我 MySQL 是多么糟糕!
| 归档时间: |
|
| 查看次数: |
224 次 |
| 最近记录: |