MySQL在有索引列情况下 和 无索引情况下 select *的输出结果顺序

来源:互联网 发布:python写webservice 编辑:程序博客网 时间:2024/05/01 18:15

本文章讨论 MySQL在有索引列情况下 和 无索引情况下 select *的输出结果顺序。


1:在有索引列情况下。

创建一个表格,一个是主键列,一个是索引列。然后插入一批数据,调用select * from test_b,可以发现输出结果并没有按照Id有序,而是按照Type有序。

如果希望按照Id有序,可以使用force index (primary)这一hint语句。

mysql> CREATE TABLE `test_b` (    ->   `Id` int(11) NOT NULL,    ->   `Type` int(11) DEFAULT NULL,    ->   PRIMARY KEY (`Id`),    ->   KEY `IDX_Type` (`Type`)    -> ) ENGINE=InnoDB DEFAULT CHARSET=utf8;Query OK, 0 rows affected (0.20 sec)mysql> insert into test_b values(1,1),(2,6),(3,2),(7,3),(4,1);Query OK, 5 rows affected (0.09 sec)Records: 5  Duplicates: 0  Warnings: 0mysql> select * from test_b;+----+------+| Id | Type |+----+------+|  1 |    1 ||  4 |    1 ||  3 |    2 ||  7 |    3 ||  2 |    6 |+----+------+5 rows in set (0.03 sec)mysql> select * from test_b force index (primary);+----+------+| Id | Type |+----+------+|  1 |    1 ||  2 |    6 ||  3 |    2 ||  4 |    1 ||  7 |    3 |+----+------+5 rows in set (0.00 sec)


观察select * from test_b的前两条结果:(1,1),(4,1),当Type相等的时候,按照Id排序。为了确认这一点,再多插入点数据观察,结论相同。

mysql> insert into test_b values(9,3),(6,3),(10,3);Query OK, 3 rows affected (0.04 sec)Records: 3  Duplicates: 0  Warnings: 0mysql> select * from test_b ;+----+------+| Id | Type |+----+------+|  1 |    1 ||  4 |    1 ||  3 |    2 ||  6 |    3 ||  7 |    3 ||  9 |    3 || 10 |    3 ||  2 |    6 |+----+------+8 rows in set (0.00 sec)


默认情况下为什么会结果按照索引列有序呢?这还要从数据库内部的运行机制说起。首先系统会查询索引表(test_b_indexed_type),该索引表的主键是索引列type(通常为了保证主键唯一性,type后面会添加一个id后缀),通过索引列查到Id,然后拿着这些Id去test_b中查询最终结果。为了最高效,扫描索引表的时候会顺着type主键往下扫,

然后拿扫得的id去“逐个”请求test_b,于是自然就出现了按照索引列有序的结果。当Type列的值一致的时候,插入到索引列的数据可以根据Id顺序插入到索引表中,

保证了当Type一致的时候,会按照Id排序。


2:在无索引的情况下。Mysql会以主键当成索引来按主键从小到大输出结果。

CREATE TABLE `test_a` (      `Id` int(11) NOT NULL,      `Type` int(11) DEFAULT NULL,       PRIMARY KEY (`Id`)      ) ENGINE=InnoDB DEFAULT CHARSET=utf8;

insert into test_a values(1,1),(2,6),(3,2),(7,3),(4,1);

mysql> select * from test_a;+----+------+| Id | Type |+----+------+|  1 |    1 ||  2 |    6 ||  3 |    2 ||  4 |    1 ||  7 |    3 |+----+------+

看到上面的Id是按从小到大输出的了吧!


下面是别人的总结:


Select 语句如果不加 “Order By”, MySQL会怎么排序呢?

* 不能依赖 MySQL 的默认排序
* 如果你想排序,总是加上 Order By
* GROUP BY 强加了 Order By,

对于 MyISAM 表
MySQL Select 默认排序是按照物理存储顺序显示的。(不进行额外排序).
也就是说
SELECT * FROM tbl – 会产生“表扫描”。如果表没有删除、替换、更新操作,记录会显示为插入的顺序。

InnoDB 表
同样的情况,会按主键的顺序排列。但是这是不靠谱的,它是潜规则。

“Select” 不加 “Order by”时, MySQL 会尝试以尽可能快的方法(MySQL 实际的方法不见得快)返回数据。
由于访问主键、索引大多数情况会快一些(在Cache里)所以返回的数据有可能以主键、索引的顺序输出,
这里并不会真的进行排序,主要是由于主键、索引本身就是排序放到内存的,所以连续输出时可能是某种序列。
在一些情况下消耗硬盘寻道时间最短的数据会先返回。 如果只查询单个表,在特殊的情况下是有规律的。

最后总结

“Order By 是要加的”

我们对于翻页等逻辑必须默认加上order by排序,而且order by的字段如果有重复值,必须指定第二排序字段,如果第二排序字段还有重复值,那必须指定更多的字段,直到所有的排序字段能够指定唯一顺序。


0 0
原创粉丝点击