SQL Server 索引 - 升序或降序,有啥区别?
Posted
技术标签:
【中文标题】SQL Server 索引 - 升序或降序,有啥区别?【英文标题】:SQL Server indexes - ascending or descending, what difference does it make?SQL Server 索引 - 升序或降序,有什么区别? 【发布时间】:2010-10-19 03:14:44 【问题描述】:当您在 MS SQL Server(我使用的是 2005 版)中为一列或多列创建索引时,您可以指定每列的索引是升序还是降序。我很难理解为什么这个选择甚至在这里。使用二进制排序技术,查找不是一样快吗?我选择哪个顺序有什么不同?
【问题讨论】:
【参考方案1】:当您要检索大量已排序的数据而不是单个记录时,排序顺序很重要。
请注意(正如您对问题的建议),排序顺序通常远不如您要索引的列重要(如果顺序与它想要的相反,系统可以反向读取索引)。我很少考虑索引排序顺序,而我却为索引所涵盖的列而苦恼。
@Quassnoi 提供了一个great example,说明它确实重要。
【讨论】:
【参考方案2】:这主要在与复合索引一起使用时很重要:
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
单个列上的索引可以有效地用于两种方式的排序。
详情请看我博客中的文章:
Descending indexes更新:
事实上,即使对于单列索引,这也很重要,尽管它并不那么明显。
想象一下聚簇表的列上的索引:
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
的列始终是该表上任何其他索引的尾随列。
【讨论】:
当您说“不适合...”时,您的意思是它不会起作用还是性能会很糟糕? 我的意思是索引不会用于查询。当然,查询本身会起作用,但性能会很差。 在第一部分,第二个例子不应该说“ORDER BY col1 DESC, col2 DESC”吗?【参考方案3】:对于真正的单列索引,从查询优化器的角度来看几乎没有什么区别。
对于表定义
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 %% )
【讨论】:
感谢 Martin 提供的这个很棒的提示,这对我的排名查询很有帮助 我想知道我是否有一个降序索引,然后从 mytable 中选择 mycolumn,其中 indexed_column = \@myvalue 当 \@myvalue 更接近最大可能值时比 \@myvalue 时更快接近最小可能值。 @LajosArpad 为什么会更快? B树是平衡树。两者的树的深度相同。 @MartinSmith 深度是一样的,但我怀疑兄弟姐妹的顺序不会有区别 @MartinSmith,如果兄弟姐妹的顺序在性能上有一点点差异,那么运行数百万次选择就会加起来,更不用说多维连接了。以上是关于SQL Server 索引 - 升序或降序,有啥区别?的主要内容,如果未能解决你的问题,请参考以下文章
pytorch :使用两次sort函数(排序)找出矩阵每个元素在升序或降序排列中的位置
pytorch :使用两次sort函数(排序)找出矩阵每个元素在升序或降序排列中的位置