返回的 MySQL 查询结果是半随机的/不一致的顺序

Posted

技术标签:

【中文标题】返回的 MySQL 查询结果是半随机的/不一致的顺序【英文标题】:MySQL query results returned are semi-random / inconsistently ordered 【发布时间】:2017-09-20 19:43:22 【问题描述】:

我正在使用使用 proxysql 的 ndb 集群设置。有4个mysql服务器,4个数据节点,2个管理节点。当我直接访问其中一台 mysql 服务器时会发生以下情况,所以我认为我可以安全地排除 proxysql 作为根本原因,但除此之外,我只是迷路了。

这是我设置的一个表格来帮助说明我的问题:

mysql> describe delain;
+----------+-------------+------+-----+---------+----------------+
| Field    | Type        | Null | Key | Default | Extra          |
+----------+-------------+------+-----+---------+----------------+
| album_id | tinyint(2)  | NO   | PRI | NULL    | auto_increment |
| album    | varchar(30) | YES  |     | NULL    |                |
+----------+-------------+------+-----+---------+----------------+
2 rows in set (0.00 sec)

它包含以下数据;请注意,我指定了 order by 子句:

mysql> select * from delain order by album_id;
+----------+-------------------------+
| album_id | album                   |
+----------+-------------------------+
|        1 | Lucidity                |
|        2 | April Rain              |
|        3 | We Are the Others       |
|        4 | The Human Contradiction |
|        5 | Moonbathers             |
+----------+-------------------------+
5 rows in set (0.00 sec)

如果我不指定 order 子句,返回的结果看起来是随机的,比如:

mysql> select * from delain;
+----------+-------------------------+
| album_id | album                   |
+----------+-------------------------+
|        3 | We Are the Others       |
|        5 | Moonbathers             |
|        1 | Lucidity                |
|        2 | April Rain              |
|        4 | The Human Contradiction |
+----------+-------------------------+
5 rows in set (0.00 sec)

当我重复查询(无顺序子句)时,几乎每次都会得到不同的顺序。它似乎并不是真正随机的,但对我来说确实没有任何可辨别的模式。

为什么会这样?我对mysql的经验一直是默认排序基本上是根据主键,但这也是我第一次特别使用ndb集群;我不知道那里是否有区别,或者配置文件中的设置是否丢失或什么。非常感谢任何帮助!

【问题讨论】:

正如您刚刚意识到的那样,除非您指定顺序,否则每个数据库中的行都不是有序的数据集。由于索引、集群、磁盘分区等,顺序可能会有所不同。只是数据库收集请求的数据是他能做到的最有效的方式。而且因为你没有设置ORDER BY,所以他没有努力订购它,每次都会得到不同的结果。 这是有道理的,并且肯定与我在试图找出解决问题的方法时看到的其他信息相匹配,根据我之前的经验,这似乎违反直觉。它一定只是确认偏差、环境差异或类似的东西,我想我不能指望找到一个更广泛、一刀切的解决方案。非常感谢您的及时回复! 由于您没有指定ORDER BY 子句,因此它不应该打扰您获得结果的顺序。如果您需要订单,请使用ORDER BY 子句,因为这是保证排序结果的唯一方法。一旦查询在并行线程中执行,对于没有ORDER BY 的查询,结果顺序会随着每次执行而变化。 【参考方案1】:

这是标准的 SQL 行为。

https://mariadb.com/kb/en/library/sql-99/order-by-clause/ 部分表示:

ORDER BY 子句可以可选地出现在查询表达式之后:它指定从该查询返回时行应具有的顺序 (如果省略该子句,您的 DBMS 将以某种随机顺序返回行)。

(强调我的)

更准确地说,它将以某种任意 顺序而不是随机顺序返回行。随机意味着顺序将从一个执行更改为下一个执行。

在 InnoDB 的情况下,顺序往往是访问行的索引顺序。它读取的索引不一定是主键。因此,如果您对内部有所了解,那么顺序是不变的并且在某种程度上是可以预测的。但这不是随机的。

在 MyISAM 的情况下,顺序往往是行在表中存储的顺序,这可能会因插入行的顺序以及文件中的空间位置而异在插入时,在行删除之后。

对于 NDB,我不太了解它的内部结构,所以我无法描述它的“默认”顺序规则,但如果没有明确的 ORDER BY,仍然是这样存储引擎可以按照它想要的任何顺序返回行。

【讨论】:

我想我可以非常自信地说,在我们启动这个集群之前,我一直使用 InnoDB,根据你在第一个要点中所说的,它可以解释为什么这让我感到困惑对于这样的循环。好吧,如果事情是这样的话,那就这样吧——我的代码会适应环境,而不是相反。【参考方案2】:

对于 NDB,顺序取决于时间,如果是 从表中选择 *;

SELECT * from table 被实现为并行化 数据节点及其数据库内的全表扫描 一个线程 MySQL 线程接收结果。

因此,使用过滤后的查询,例如 SELECT * from table where filter_column = 2; 过滤器在许多线程中并行进行评估。 这些线程中的每一个都以任何方式将行返回给 MySQL 线程 取决于操作系统调度程序、网络和许多 其他事情。所以没有默认排序,除非你 使用 ORDER BY。

所以对于 NDB 来说,顺序是真正随机的,而不仅仅是任意的。 您将在所有使用 MTR 的 NDB 测试套件中看到这一点 查询大多使用 SELECT * from table ORDER BY some_field;

【讨论】:

以上是关于返回的 MySQL 查询结果是半随机的/不一致的顺序的主要内容,如果未能解决你的问题,请参考以下文章

Hive 外部表在 EMR 上返回不一致的结果

如何在mysql 的查询结果中增加一个字段进去

如何在mysql 的查询结果中增加一个字段进去

MySQL 随机查询若干条数据

MySQL 随机查询若干条数据

mysql中如何在上一次的查询结果中再次查询