什么是"SELECT*FROM table_name;"的MySQL行顺序?

kno*_*orv 17 mysql select sql-order-by

假设向MySQL数据库发出以下查询:

SELECT * FROM table_name;
Run Code Online (Sandbox Code Playgroud)

请注意,没有 ORDER BY给出任何条款.

我的问题是:

MySQL是否给出了结果集行的顺序保证?

更具体地说,我可以假设行将按插入顺序返回吗?这与行插入表中的顺序相同.

Bil*_*win 29

不,没有保证.除非您使用ORDER BY子句指定订单,否则订单完全取决于内部实施细节.也就是RDBMS引擎最方便的东西.

实际上,行可能以其原始插入顺序返回(或者更准确地说是行存在于物理存储中的顺序),但您不应该依赖于此.如果端口您的应用程序到另一个品牌的RDBMS的,或者即使你升级到MySQL可能不同的方式实现存储的新版本,该行可能会再次在一些其他命令.

对于任何符合SQL的RDBMS,后一点都适用.


以下是存储中行存在顺序与存储顺序的比较:

CREATE TABLE foo (id SERIAL PRIMARY KEY, bar CHAR(10));

-- create rows with id 1 through 10
INSERT INTO foo (bar) VALUES
  ('testing'), ('testing'), ('testing'), ('testing'), ('testing'), 
  ('testing'), ('testing'), ('testing'), ('testing'), ('testing');

DELETE FROM foo WHERE id BETWEEN 4 AND 7;

+----+---------+
| id | bar     |
+----+---------+
|  1 | testing |
|  2 | testing |
|  3 | testing |
|  8 | testing |
|  9 | testing |
| 10 | testing |
+----+---------+
Run Code Online (Sandbox Code Playgroud)

所以现在我们有六行.此时的存储包含第3行和第8行之间的间隙,在删除中间行后留下.删除行不会对这些间隙进行碎片整理.

-- create rows with id 11 through 20 
INSERT INTO foo (bar) VALUES
  ('testing'), ('testing'), ('testing'), ('testing'), ('testing'), 
  ('testing'), ('testing'), ('testing'), ('testing'), ('testing');

SELECT * FROM foo;

+----+---------+
| id | bar     |
+----+---------+
|  1 | testing |
|  2 | testing |
|  3 | testing |
| 14 | testing |
| 13 | testing |
| 12 | testing |
| 11 | testing |
|  8 | testing |
|  9 | testing |
| 10 | testing |
| 15 | testing |
| 16 | testing |
| 17 | testing |
| 18 | testing |
| 19 | testing |
| 20 | testing |
+----+---------+
Run Code Online (Sandbox Code Playgroud)

请注意在将新行附加到表的末尾之前,MySQL如何重复使用通过删除行打开的空格.还要注意,行11到14以相反的顺序插入这些空间,从末端向后填充.

因此,存储行的顺序与它们的插入顺序不完全相同.


Kal*_*see 5

根据此线程,默认排序是MyISAM的插入顺序,以及InnoDB的主键升序.但我不认为这是一种保证,只是它的工作原理.


Der*_*sed 5

你不能。

有时 MySQL 会使用您不期望的键执行选择查询。考虑这个表:

CREATE TABLE `user_permissions` (
  `permId` int(5) unsigned NOT NULL AUTO_INCREMENT,
  `permKey` varchar(16) NOT NULL,
  `permDesc` varchar(64) DEFAULT NULL,
  PRIMARY KEY (`permId`),
  KEY `key_lookup` (`permKey`,`permId`,`permDesc`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
Run Code Online (Sandbox Code Playgroud)

MySQL几乎总是使用该key_lookup键对此表进行任何选择操作;由于permKey是第一个字段,因此通常会按此键“排序”(按字母顺序显示,但不完全如此)。

如果没有ORDER BY子句,MySQL(以及大多数/所有 RDBMS 引擎)将尝试以尽可能快的速度获取存储的数据。