关于IDENTITY列的排序

Jackforid2003 2010-07-31 03:17:48
我的系统里有这么一张表 TableA(FiledA,FieldB) 其中FieldA是IDENTITY 1开始的int,FieldB是日期类型
FieldA FieldB
=====================
1 2010/7/26 15:19
2 2010/7/26 17:19
3 2010/7/26 20:19

我取这张表的数据的时候 没有用排序,一直都是select * from TableA的方式
不过每次取出来都是按照FieldA的升序排序的。

随着数据量一大,数据库连接数一多之后,偶尔会出现上面的数据取出来的时候没有按照FieldA的升序排列。

我想问问各位大侠,为什么偶尔会不按照默认的顺序排序?有哪些可能性
我一直认为默认的顺序就是FiledA的升序。还是这个想法本身就不对?难道没有加sort的排序本身就是不稳定的?

哦,数据库是SQLServer2005
...全文
177 19 打赏 收藏 转发到动态 举报
写回复
用AI写文章
19 条回复
切换为时间正序
请发表友善的回复…
发表回复
haitao 2010-08-01
  • 打赏
  • 举报
回复
记得关系数据库就是不保证返回记录的顺序的,
如果关心顺序,则必须加上order by

这个是最原始的规则了吧
obuntu 2010-08-01
  • 打赏
  • 举报
回复
曾经也对这个问题比较困扰,并做了点研究,大家可以探讨下。

首先,对于聚集索引而言,得明白2个概念,一个是逻辑排序,一个是物理排序。逻辑排序指的是按聚集索引上所定义的来排序;物理排序指的是数据在page内或page间的排序。

但一般在物理上是没有什么排序的,因为随着频繁的插入或者更新会导致数据分别曾不规则性。看下面的例子


CREATE TABLE TEST(ID INT IDENTITY(1,1) PRIMARY KEY,A VARCHAR(50))

INSERT INTO TEST(A) VALUES('A'),('B'),('C'),('D')

/*查看数据的物理分布*/
DBCC IND('master','test',-1)
/*
PageFID PagePID IAMFID IAMPID ObjectID IndexID PartitionNumber PartitionID iam_chain_type PageType IndexLevel NextPageFID NextPagePID PrevPageFID PrevPagePID
------- ----------- ------ ----------- ----------- ----------- --------------- -------------------- -------------------- -------- ---------- ----------- ----------- ----------- -----------
1 196 NULL NULL 1899153811 1 1 72057594040811520 In-row data 10 NULL 0 0 0 0
1 193 1 196 1899153811 1 1 72057594040811520 In-row data 1 0 0 0 0 0

*/

/*查看具体页的数据内容*/
DBCC TRACEON(3604)
DBCC PAGE('master',1,193,3)

/*
在page内,会通过slot来维护数据的顺序性,下面是从dbcc page的结果提取出的slot的情况

Slot 0 Offset 0x60 Length 30
Slot 1 Offset 0x7e Length 30
Slot 2 Offset 0x9c Length 30
Slot 3 Offset 0xba Length 30

可以看到,此时四条数据现在page内的物理排序是顺序的(根据offset值判断)
*/

/*
对数据进行更新。
*/
UPDATE TEST SET A='DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD'
WHERE ID=1

DBCC TRACEON(3604)
DBCC PAGE('master',1,193,3)

/*
slot 和page的分布如下
可以看到slot 0 这条记录在页中的位置已经比后续记录靠后了,说明在物理上的排序已经是不准确的。
但仍维护着逻辑上的四条记录的排序
*/
/*
Slot 0 Offset 0xd8 Length 74
Slot 1 Offset 0x7e Length 30
Slot 2 Offset 0x9c Length 30
Slot 3 Offset 0xba Length 30
*/


这说明,SQL Server ENGINE是不会去维护每条记录的排序的,取数据的时候并不能保证按照顺序将每条记录取出。

但为什么很多时候,不加order by 仍能按照聚集索引返回正确的排序结果呢?个人认为一是可能数据量小,二可能是读取的时候对查询优化器的干扰较小,(反正做测试的时候没搞出过这个现象)


说到底,就一句话:
SQL Server不会保证返回结果的顺序,要获得正确的排序效果,一定要加order by
zh_victory 2010-08-01
  • 打赏
  • 举报
回复
一直以为加了identity,就会是有序的,原来是这样啊!
obuntu 2010-08-01
  • 打赏
  • 举报
回复
[Quote=引用 6 楼 are_you_all_right 的回复:]

select * from tb 优化器会选择table san
数据的存储是无序的。
所以取数据的时候不要依赖索引排序或者主键排序
请使用 order by 排序

以上为小女子的一些愚见,如有不对,请大家多多批评
[/Quote]

有主键了,会clustered index scan的
feixianxxx 2010-07-31
  • 打赏
  • 举报
回复
按理来说:有聚集索引的表 在进行select * from tb 这样的无指定order by的搜索语句 默认是按照聚集索引列升序或者降序显示的..因为它本身的数据逻辑上都是按照聚集索引排放的(注意不是物理上就是这么存放的)..

但是在实际情况下,存在一种“走马灯式扫描”的机制
-------------------------解释------------------------------------
--在 SQL Server Enterprise 中,高级扫描功能使得多项任务可以共享完全表扫描。它可以这么理解:
1.你执行一个T-SQL语句,扫描整个A表,在执行扫描一段时间后检测到其他执行计划也在扫描A表,这个时候为另外一个执行标识当时的行,并且同步加入到第一个执行计划中.
这个时候每一次读取一页,并将每一页的行传递给这两个执行计划。此操作将一直持续到该表的结尾处。
2.此时,第一个执行计划已有完整的扫描结果,而第二个执行计划仍必须检索在它加入正在进行的扫描之前读取的数据页。
然后,第二个执行计划中的扫描将绕回到表的第一个数据页,并从这里向前扫描到它加入第一个扫描时所处的位置。可以按这种方式组合任意数量的扫描。数据库引擎将循环遍历数据页,直到完成所有扫描。

关于这个 你可以参看下:
http://topic.csdn.net/u/20100731/15/8649133c-db10-4316-bac5-cad91fa55779.html
  • 打赏
  • 举报
回复
第一个问题:
如果是自增列,插入时是按照顺序来的,就怕自增列遭到破坏。
第二:
如果你非要按第一个字段排序,那么加上索引就行了。
claro 2010-07-31
  • 打赏
  • 举报
回复

如果真的要交待什么,将事实写出来,证明是怎样。
xman_78tom 2010-07-31
  • 打赏
  • 举报
回复
从概念上来说,关系表对应的是集合,而集合中的元素是无序的。因此,使用没有 order by 子句的 select 语句所获取的结果集,也是无序的。

从执行计划上来说,微软并不保证 select 语句返回的结果集中的行是按行存储的顺序排序的。
也就是说,按 lz 的情况,即使在 FieldA 列上有聚集索引,没有 order by 子句的 select 语句返回的结果集中的行也不会保证按聚集索引中定义的顺序排列;这是因为 select 语句有可能会产生并行计划——由多个工作线程从表的各个部分同时提取行。

总之,要保证 select 语句返回的结果集中的行是按想要的顺序排列,一定要加 order by 子句!
Are_You_All_Right 2010-07-31
  • 打赏
  • 举报
回复
和你的情况很相似,呵呵
希望对你有所帮助
Jackforid2003 2010-07-31
  • 打赏
  • 举报
回复
谢谢,我也希望看到明确的说明。这样我好向上头交待。
其实我也试着找了,就是没找到。。麻烦你了
Are_You_All_Right 2010-07-31
  • 打赏
  • 举报
回复
[Quote=引用 7 楼 jackforid2003 的回复:]
ls的意思简单点说就是不加order by,出来的结果是无排序的。
可是这种说法哪里能证实哪?
[/Quote]
ms有明确说明的,呵呵,我去给你找找
不一定能找到
Jackforid2003 2010-07-31
  • 打赏
  • 举报
回复
ls的意思简单点说就是不加order by,出来的结果是无排序的。
可是这种说法哪里能证实哪?
Are_You_All_Right 2010-07-31
  • 打赏
  • 举报
回复
select * from tb 优化器会选择table san
数据的存储是无序的。
所以取数据的时候不要依赖索引排序或者主键排序
请使用 order by 排序

以上为小女子的一些愚见,如有不对,请大家多多批评
Jackforid2003 2010-07-31
  • 打赏
  • 举报
回复
哦,补充一点。。。这里的FieldA是主键,所以应该是聚集索引吧。
Are_You_All_Right 2010-07-31
  • 打赏
  • 举报
回复
不是“无需" 是无序
在聚集索引中,行的物理存储顺序与索引顺序完全相同,即索引的顺序决定了表中行的存储顺序.
所以
select * from tb where....
可能选择index seak或者index scan
所以读出来的数据会是有序的。
永生天地 2010-07-31
  • 打赏
  • 举报
回复
查询时用 with(index(n))可以决定如何使用索引
没有就由sqlserver优化器决定了,看看其执行计划,我也就知道这么多了
Jackforid2003 2010-07-31
  • 打赏
  • 举报
回复
ls说的没有聚集索引的表中,不加sort是无序的,
这句话在那里能得到证实?能不能告诉我msdn内关于这个的说明吧?我也好交差。。。。。
Are_You_All_Right 2010-07-31
  • 打赏
  • 举报
回复
在没有聚集索引的表中
select * from tb 
取出的数据是无需的,需要排序
最好指定排序列
select * from tb order by FieldA 

27,579

社区成员

发帖
与我相关
我的任务
社区描述
MS-SQL Server 应用实例
社区管理员
  • 应用实例社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧