SQL Server索引 – 升序或降序,它有什么不同?

当您在MS SQL Server(我正在使用版本2005)的一列或多列上创build索引时,可以指定每列上的索引是升序还是降序。 我很难理解为什么这个select甚至在这里。 使用二进制sorting技术,不会查找速度一样快? 我select哪个订单有什么不同?

与复合索引一起使用时,这主要关键:

CREATE INDEX ix_index ON mytable (col1, col2 DESC); 

可以用于:

 SELECT * FROM mytable ORDER BY col1, col2 DESC 

要么:

 SELECT * FROM mytable ORDER BY col1 DESC, col2 

,但不适用于:

 SELECT * FROM mytable ORDER BY col1, col2 

单列上的索引可以有效地用于两种sorting。

有关详细信息,请参阅我的博客文章:

  • 降序索引

更新:

事实上,即使对于单列索引,这也可能很重要,尽pipe这并不明显。

设想一下聚簇表的列上的索引:

 CREATE TABLE mytable ( pk INT NOT NULL PRIMARY KEY, col1 INT NOT NULL ) CREATE INDEX ix_mytable_col1 ON mytable (col1) 

col1上的索引保留col1有序值以及对行的引用。

由于表是聚集的,对行的引用实际上是pk的值。 它们也在col1每个值内sorting。

这意味着索引的叶子实际上是在(col1, pk)和这个查询上sorting的:

 SELECT col1, pk FROM mytable ORDER BY col1, pk 

不需要sorting。

如果我们创build索引如下:

 CREATE INDEX ix_mytable_col1_desc ON mytable (col1 DESC) 

那么col1的值将被降序排列,但col1每个值中的pk值将按升序sorting。

这意味着下面的查询:

 SELECT col1, pk FROM mytable ORDER BY col1, pk DESC 

可以由ix_mytable_col1_desc服务,但不能由ix_mytable_col1

换句话说,在任何表上构成CLUSTERED INDEX的列总是该表上任何其他索引的尾部列。

对于真正的单列索引,与查询优化器的观点没什么区别。

对于表格定义

 CREATE TABLE T1( [ID] [int] IDENTITY NOT NULL, [Filler] [char](8000) NULL, PRIMARY KEY CLUSTERED ([ID] ASC)) 

查询

 SELECT TOP 10 * FROM T1 ORDER BY ID DESC 

在执行计划中可以看到扫描方向为BACKWARD的有序扫描。 不过,目前只有FORWARD扫描可以并行。

计划

然而它在逻辑碎片方面可能会有很大的不同 。 如果索引是使用递减键创build的,但是新行添加了递增键值,则可以使每个页面都不符合逻辑顺序。 这会严重影响扫描表时IO读取的大小,并且不在caching中。

查看碎片结果

  avg_fragmentation avg_fragment name page_count _in_percent fragment_count _size_in_pages ------ ------------ ------------------- ---------------- --------------- T1 1000 0.4 5 200 T2 1000 99.9 1000 1 

下面的脚本

 /*Uses T1 definition from above*/ SET NOCOUNT ON; CREATE TABLE T2( [ID] [int] IDENTITY NOT NULL, [Filler] [char](8000) NULL, PRIMARY KEY CLUSTERED ([ID] DESC)) BEGIN TRAN GO INSERT INTO T1 DEFAULT VALUES GO 1000 INSERT INTO T2 DEFAULT VALUES GO 1000 COMMIT SELECT object_name(object_id) AS name, page_count, avg_fragmentation_in_percent, fragment_count, avg_fragment_size_in_pages FROM sys.dm_db_index_physical_stats(db_id(), object_id('T1'), 1, NULL, 'DETAILED') WHERE index_level = 0 UNION ALL SELECT object_name(object_id) AS name, page_count, avg_fragmentation_in_percent, fragment_count, avg_fragment_size_in_pages FROM sys.dm_db_index_physical_stats(db_id(), object_id('T2'), 1, NULL, 'DETAILED') WHERE index_level = 0 

可以使用空间结果标签来validation这种情况,因为在这两种情况下,后面的页面都有递增的键值。

 SELECT page_id, [ID], geometry::Point(page_id, [ID], 0).STBuffer(4) FROM T1 CROSS APPLY sys.fn_PhysLocCracker( %% physloc %% ) UNION ALL SELECT page_id, [ID], geometry::Point(page_id, [ID], 0).STBuffer(4) FROM T2 CROSS APPLY sys.fn_PhysLocCracker( %% physloc %% ) 

在这里输入图像说明

当你想要检索大量的sorting数据,而不是单个logging时,sorting顺序很重要。

需要注意的是(就像你在提出你的问题一样),sorting顺序通常远不及你正在编制索引的列(如果顺序相反,系统可以反向读取索引)。 我很less给出任何想法的索引sorting顺序,而我对索引覆盖的列感到痛苦。

@Quassnoi提供了一个很好的例子 。