当您在MS SQL Server中创建一列或多列索引(我使用的是2005版)时,可以指定每列的索引是升序还是降序。我很难理解为什么这个选择仍然存在。使用二进制排序技术,两种查找方式都不会一样快吗?我选择哪个顺序有什么不同?
当您在MS SQL Server中创建一列或多列索引(我使用的是2005版)时,可以指定每列的索引是升序还是降序。我很难理解为什么这个选择仍然存在。使用二进制排序技术,两种查找方式都不会一样快吗?我选择哪个顺序有什么不同?
Answers:
与复合索引一起使用时,这主要很重要:
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
可以以两种方式有效地使用单个列上的索引进行排序。
有关详细信息,请参见我的博客中的文章:
更新:
实际上,即使不是很明显,这对于单个列索引也可能很重要。
想象一下在聚集表的列上的索引:
CREATE TABLE mytable (
pk INT NOT NULL PRIMARY KEY,
col1 INT NOT NULL
)
CREATE INDEX ix_mytable_col1 ON mytable (col1)
索引on col1
保留的有序值col1
以及对行的引用。
由于表是集群的,因此对行的引用实际上是的值pk
。它们也按的每个值排序col1
。
这意味着该索引的叶子实际上是在上排序的(col1, pk)
,该查询如下:
SELECT col1, pk
FROM mytable
ORDER BY
col1, pk
无需排序。
如果我们按以下方式创建索引:
CREATE INDEX ix_mytable_col1_desc ON mytable (col1 DESC)
,则的值col1
将按降序排序,但的pk
每个值内的值col1
将按升序排序。
这意味着以下查询:
SELECT col1, pk
FROM mytable
ORDER BY
col1, pk DESC
可以由ix_mytable_col1_desc
但不能由ix_mytable_col1
。
换句话说,CLUSTERED INDEX
在任何表上构成a的列始终是该表上任何其他索引的尾随列。
对于真正的单列索引,它与查询优化器的观点几乎没有什么不同。
对于表定义
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
并行扫描。
但是,就逻辑碎片而言,它可以带来很大的不同。如果索引是用降序排列的键创建的,但是新行会附加升序的键值,那么最后的每一页都可能不符合逻辑顺序。扫描表时,它会严重影响IO读取的大小,并且该表不在缓存中。
查看碎片结果
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
可以使用“空间结果”选项卡来验证以下假设:这是因为在这两种情况下,后面的页面均具有升序的键值。
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 %% )