如果我在MySQL数据库中有1000行,我知道使用TOP
或LIMIT
会使查询更快,但我想知道,默认情况下数据的排序方式是什么?
默认情况下如何设置order by time
或username
,以便轻松快捷地使用TOP
或LIMIT
?
答案 0 :(得分:4)
在InnoDB 中,行以主键顺序存储。如果您使用LIMIT
而没有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 |
+----+------+
如果你有更复杂的连接查询,它会变得更加复杂,因为你将获得所访问的第一个表的默认顺序返回的行(其中“first”依赖于优化器选择表的顺序),然后连接表中的行将取决于上一个表中行的顺序。
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
。
答案 1 :(得分: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
这不会(在大多数情况下......)使用索引进行排序:
select * from users where country = China order by time
答案 2 :(得分:0)
它通常以插入的顺序出现,但你不能依赖它。如果您需要特定订单,请始终指定。
将索引添加到“时间”和“用户名”以使其更快,并且只选择您需要的数据。
答案 3 :(得分:0)
“默认”订单未指定(即不可靠)
将一个ORDER BY子句添加到select中以确保。