0

如果我在 MySQL 数据库中有 1000 行,我知道使用TOPLIMIT使查询更快,但我想知道,默认情况下数据是如何排序的?

以及如何使order by timeorusername默认情况下,以便使用TOPorLIMIT更容易和更快?

4

4 回答 4

4

在 InnoDB中,行按主键顺序存储。如果您使用LIMITwith no ORDER BY,您将始终获得具有最低主键值的行,即使您以随机顺序插入它们也是如此。

create table foo (id int primary key, x char(1), y int) engine=InnoDB;
insert into foo values (5, 'A', 123);
insert into foo values (9, 'B', 234);
insert into foo values (2, 'C', 345);
insert into foo values (4, 'D', 456);
insert into foo values (1, 'E', 567);
select * from foo;
+----+------+------+
| id | x    | y    |
+----+------+------+
|  1 | E    |  567 |
|  2 | C    |  345 |
|  4 | D    |  456 |
|  5 | A    |  123 |
|  9 | B    |  234 |
+----+------+------+

在 MyISAM中,行存储在任何适合的地方。最初,这意味着行被附加到数据文件中,但是当您删除行并插入新行时,删除行留下的空白将被新行重新使用。

create table bar (id int primary key, x char(1), y int) engine=MyISAM;
insert into bar values (1, 'A', 123);
insert into bar values (2, 'B', 234);
insert into bar values (3, 'C', 345);
insert into bar values (4, 'D', 456);
insert into bar values (5, 'E', 567);
select * from bar;
+----+------+------+
| id | x    | y    |
+----+------+------+
|  1 | A    |  123 |
|  2 | B    |  234 |
|  3 | C    |  345 |
|  4 | D    |  456 |
|  5 | E    |  567 |
+----+------+------+
delete from bar where id between 3 and 4;
insert into bar values (6, 'F', 678);
insert into bar values (7, 'G', 789);
insert into bar values (8, 'H', 890);
select * from bar;
+----+------+------+
| id | x    | y    |
+----+------+------+
|  1 | A    |  123 |
|  2 | B    |  234 |
|  7 | G    |  789 | <-- new row fills gap
|  6 | F    |  678 | <-- new row fills gap
|  5 | E    |  567 |
|  8 | H    |  890 | <-- new row appends at end
+----+------+------+

如果您使用 InnoDB,另一个例外情况是您从二级索引而不是从主索引检索行。当您在 EXPLAIN 输出中看到“使用索引”注释时,就会发生这种情况。

alter table foo add index (x);
select id, x from foo;
+----+------+
| id | x    |
+----+------+
|  5 | A    |
|  9 | B    |
|  2 | C    |
|  4 | D    |
|  1 | E    |
+----+------+

如果您有更复杂的连接查询,它会变得更加复杂,因为您将获得按访问的第一个表的默认顺序返回的行(其中“第一个”取决于优化器选择表的顺序),然​​后连接表中的行将取决于前一个表中行的顺序。

select straight_join foo.*, bar.* from bar join foo on bar.x=foo.x;
+----+------+------+----+------+------+
| id | x    | y    | id | x    | y    |
+----+------+------+----+------+------+
|  1 | E    |  567 |  5 | E    |  567 |
|  5 | A    |  123 |  1 | A    |  123 |
|  9 | B    |  234 |  2 | B    |  234 |
+----+------+------+----+------+------+

select straight_join foo.*, bar.* from foo join bar on bar.x=foo.x;
+----+------+------+----+------+------+
| id | x    | y    | id | x    | y    |
+----+------+------+----+------+------+
|  5 | A    |  123 |  1 | A    |  123 |
|  9 | B    |  234 |  2 | B    |  234 |
|  1 | E    |  567 |  5 | E    |  567 |
+----+------+------+----+------+------+

底线是最好是明确的:当你使用时LIMIT,指定一个ORDER BY.

于 2013-03-11T19:27:30.740 回答
2

如何默认按时间或用户名下单,以便使用 TOP 或 LIMIT 更简单快捷?

使用InnoDB作为引擎时,可以设置一个索引(其中的列或集合)为主键。如果这些值是唯一的,则在存储时将按原样进行排序。

如果将常规索引用作查询条件的一部分,或者如果查询从所有行中获取数据,则可以使用常规索引来加快排序速度。如果您的标准使用除您正在排序的字段之外的其他索引,它们将无济于事。

例子

给定下表:

| username (Primary) | time (Index) | country |

这些查询将具有使用索引的排序:

select * from users order by time #Will use the index

select * from users where time between X and Y order by time #Will also use the index

Thise 不会(在大多数情况下......)使用索引进行排序:

select * from users where country = China order by time
于 2013-03-11T19:27:40.490 回答
0

它通常按照插入的顺序出现,但你不能依赖它。如果您需要特定的订单,请始终指定它。

将索引添加到“时间”和“用户名”以使​​其更快,并且只选择您需要的数据。

于 2013-03-11T19:24:37.607 回答
0

“默认”顺序未指定(即不可靠)

将 ORDER BY 子句添加到选择以确保。

于 2013-03-11T19:25:18.183 回答