日期:2014-05-18  浏览次数:20560 次

关于IDENTITY列的排序
我的系统里有这么一张表 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

------解决方案--------------------
在没有聚集索引的表中
SQL code
select * from tb

------解决方案--------------------
从概念上来说,关系表对应的是集合,而集合中的元素是无序的。因此,使用没有 order by 子句的 select 语句所获取的结果集,也是无序的。

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

总之,要保证 select 语句返回的结果集中的行是按想要的顺序排列,一定要加 order by 子句!
------解决方案--------------------
按理来说:有聚集索引的表 在进行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
------解决方案--------------------
曾经也对这个问题比较困扰,并做了点研究,大家可以探讨下。

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

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


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
*/