在MS SQL Server中创建列或列数时(我使用的是版本2005),您可以指定每列的索引是升序还是降序。我很难理解为什么这个选择就在这里。使用二进制排序技术,任何一种查找都不会那么快吗?它选择哪个订单有什么区别?
答案 0 :(得分:124)
这在与复合索引一起使用时非常重要:
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)
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
的列始终是该表上任何其他索引的尾随列。
答案 1 :(得分:65)
对于真正的单列索引,它与查询优化工具的观点差别不大。
表格定义
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 %% )
答案 2 :(得分:8)
当您想要检索大量已排序的数据而不是单个记录时,排序顺序很重要。
请注意(正如您对问题所建议的那样)排序顺序通常远不如您正在索引的列那么重要(如果顺序与其想要的顺序相反,系统可以反向读取索引)。我很少考虑索引排序顺序,而我对索引所涵盖的列感到痛苦。
@Quassnoi在 之时提供了great example。