Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/26.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql server 聚集索引和非聚集索引的性能差异_Sql Server_Indexing_Sql Server 2012 - Fatal编程技术网

Sql server 聚集索引和非聚集索引的性能差异

Sql server 聚集索引和非聚集索引的性能差异,sql-server,indexing,sql-server-2012,Sql Server,Indexing,Sql Server 2012,我在DB中发现一个表,在同一列上有两个单独的索引。列类型为int,此列上有一个聚集主键。除此之外,在同一列上还有一个唯一的非聚集索引。索引具有相同的选项(排序方向和其他),并且不包含任何包含的列 这个索引被其他一些表中的外键约束使用,因此我不能在不重新创建外键约束的情况下删除它 有什么合理的理由吗?也许是为了提高效率。非聚集索引通常小于聚集索引,因为叶级别的聚集索引包含所有(非LOB)字段。因此,它可能更喜欢使用非聚集索引来强制执行外键约束 更新:我用AdventureWorks数据库做了一些进

我在DB中发现一个表,在同一列上有两个单独的索引。列类型为
int
,此列上有一个聚集主键。除此之外,在同一列上还有一个唯一的非聚集索引。索引具有相同的选项(排序方向和其他),并且不包含任何包含的列

这个索引被其他一些表中的外键约束使用,因此我不能在不重新创建外键约束的情况下删除它


有什么合理的理由吗?

也许是为了提高效率。非聚集索引通常小于聚集索引,因为叶级别的聚集索引包含所有(非LOB)字段。因此,它可能更喜欢使用非聚集索引来强制执行外键约束

更新:我用AdventureWorks数据库做了一些进一步的测试,证明了这个理论。见下文

我可以用两个表T1和T2重现这个问题。T1是父级,从T2到T1之间存在外键关系

当T1具有聚集主键约束和非聚集唯一索引Ix-T1时,我可以更改表并删除聚集主键约束,但我不能像您发现的那样删除Ix-T1

如果我使用非聚集主键约束和聚集唯一索引Ix_T1创建T1,那么情况正好相反:我可以删除Ix-T1,但无法删除主键约束

CREATE TABLE T1
(
    id int NOT NULL CONSTRAINT PK_T1 PRIMARY KEY CLUSTERED
);

CREATE UNIQUE NONCLUSTERED INDEX Ix_T1
    ON T1(id);

CREATE TABLE T2
(
   id2 int NOT NULL PRIMARY KEY CLUSTERED,
   id1 int NOT NULL FOREIGN KEY REFERENCES dbo.T1(id)
);

INSERT INTO T1 (id)
    VALUES (1), (2), (3), (4);

INSERT INTO T2 (id2, id1)
    VALUES (11, 1), (12, 2), (13, 3);
ALTER TABLE dbo.T1
   DROP CONSTRAINT PK_T1;
ALTER TABLE dbo.T1
    DROP CONSTRAINT PK_T1;
尝试删除非聚集索引。这是失败的

DROP INDEX Ix_T1
    ON dbo.T1;

但是,我可以删除集群主键约束

CREATE TABLE T1
(
    id int NOT NULL CONSTRAINT PK_T1 PRIMARY KEY CLUSTERED
);

CREATE UNIQUE NONCLUSTERED INDEX Ix_T1
    ON T1(id);

CREATE TABLE T2
(
   id2 int NOT NULL PRIMARY KEY CLUSTERED,
   id1 int NOT NULL FOREIGN KEY REFERENCES dbo.T1(id)
);

INSERT INTO T1 (id)
    VALUES (1), (2), (3), (4);

INSERT INTO T2 (id2, id1)
    VALUES (11, 1), (12, 2), (13, 3);
ALTER TABLE dbo.T1
   DROP CONSTRAINT PK_T1;
ALTER TABLE dbo.T1
    DROP CONSTRAINT PK_T1;

对具有非聚集主键和聚集唯一索引的T1重复该测试

CREATE TABLE T1
(
    id int NOT NULL CONSTRAINT PK_T1 PRIMARY KEY NONCLUSTERED
);

CREATE UNIQUE CLUSTERED INDEX Ix_T1
   ON T1(id);
这一次,我不能删除主键约束

CREATE TABLE T1
(
    id int NOT NULL CONSTRAINT PK_T1 PRIMARY KEY CLUSTERED
);

CREATE UNIQUE NONCLUSTERED INDEX Ix_T1
    ON T1(id);

CREATE TABLE T2
(
   id2 int NOT NULL PRIMARY KEY CLUSTERED,
   id1 int NOT NULL FOREIGN KEY REFERENCES dbo.T1(id)
);

INSERT INTO T1 (id)
    VALUES (1), (2), (3), (4);

INSERT INTO T2 (id2, id1)
    VALUES (11, 1), (12, 2), (13, 3);
ALTER TABLE dbo.T1
   DROP CONSTRAINT PK_T1;
ALTER TABLE dbo.T1
    DROP CONSTRAINT PK_T1;

但是,我可以删除聚集索引

DROP INDEX Ix_T1
    ON dbo.T1;

因此,如果我的理论是正确的,那么如果删除非聚集索引,性能可能会受到影响。你可能想做一些调查和测试

是否有数据库模式的文档说明索引存在的原因?或者你能问问数据库的设计者吗

我用AdventureWorks2014做了一些进一步的测试,证明了我的理论

USE AdventureWorks2014;
GO
CREATE SCHEMA test;
GO

-- Create two test tables
SELECT *
    INTO test.SalesOrderHeader
    FROM Sales.SalesOrderHeader;

SELECT *
    INTO test.SalesOrderDetail
    FROM Sales.SalesOrderDetail;

-- Test 1 - Clustered primary key and nonclustered index
ALTER TABLE test.SalesOrderHeader
    ADD CONSTRAINT PK_Test_SalesOrderHeader PRIMARY KEY CLUSTERED (SalesOrderID);

CREATE UNIQUE NONCLUSTERED INDEX Ix_Test_SalesOrderHeader
    ON test.SalesOrderHeader(SalesOrderID);

-- Test 2 - Nonclustered primary key and clustered index
CREATE UNIQUE CLUSTERED INDEX Ix_Test_SalesOrderHeader
    ON test.SalesOrderHeader(SalesOrderID);

ALTER TABLE test.SalesOrderHeader
    ADD CONSTRAINT PK_Test_SalesOrderHeader PRIMARY KEY NONCLUSTERED (SalesOrderID);

-- Test 3 - Clustered primary key only
ALTER TABLE test.SalesOrderHeader
    ADD CONSTRAINT PK_Test_SalesOrderHeader PRIMARY KEY CLUSTERED (SalesOrderID);

-- Same for all tests
ALTER TABLE test.SalesOrderDetail
    ADD CONSTRAINT PK_Test_SalesOrderDetail PRIMARY KEY CLUSTERED (SalesOrderDetailID);

ALTER TABLE test.SalesOrderDetail
    ADD CONSTRAINT FK_Test_SalesOrderDetail_SalesOrderHeader FOREIGN KEY (SalesOrderID) REFERENCES test.SalesOrderHeader(SalesOrderID);

-- Update 100 records in SalesOrderDetail
UPDATE test.SalesOrderDetail
    SET SalesOrderID = SalesOrderID + 1
    WHERE SalesOrderDetailID BETWEEN 57800 AND 57899;
测试1的实际执行计划

测试2的实际执行计划。索引搜索操作符的估计子树开销几乎与测试1相同

测试3的实际执行计划。索引搜索的估计子树成本是测试1或测试2的两倍以上

这是一个测量索引大小的查询。(测试1配置)您可以清楚地看到聚集索引要大得多

-- Measure sizes of indexes
SELECT I.object_id, I.name, I.index_id, I.[type], I.[type_desc], SUM(s.used_page_count) * 8 AS 'IndexSizeKB'
    FROM sys.indexes AS I
        INNER JOIN sys.dm_db_partition_stats AS S
            ON S.[object_id] = I.[object_id] AND S.index_id = I.index_id
    WHERE I.[object_id] = OBJECT_ID('test.SalesOrderHeader')
    GROUP BY I.object_id, I.name, I.index_id, I.[type], I.[type_desc];

下面是一些解释聚集索引和非聚集索引的参考资料

TechNet>表和索引数据结构体系结构:

培训工具包70-462管理Microsoft SQL Server 2012数据库>第10章:索引和并发性>第1课:实现和维护索引


Microsoft SQL Server 2012 Internals by Kalen Delaney>第7章:索引:内部和管理

外键约束使用一个索引而不使用另一个索引是什么意思?如何为此目的定义索引。您应该能够删除非聚集索引。我的意思是,我收到以下消息:“不允许对索引'dbo.Table.IX_index'使用显式删除索引。它正用于外键约束强制”。还找到了杰夫·摩登在这个问题上的相关答案:但在原始文档中没有找到任何证据。你能提供NCI比CI更有效的证据吗?关于大小:这篇文章说反之亦然NCI需要比CI更多的空间:无论如何,磁盘上的大小不能成为效率的一个因素,因为在搜索时它不是完全读取的。你所指的文章非常简短。他对非聚集索引的描述很混乱。他没有区分堆上的非聚集索引和聚集索引。他关于非聚集索引比聚集索引需要更多空间的说法是错误的。叶级别的聚集索引使用更多空间,因为叶节点包含所有非lob字段,而非聚集索引包含指向聚集索引或堆的指针。我在回答中添加了三个引用,解释了表和索引。我添加了使用AdventureWorks数据库的进一步测试,这证明了我的理论。我还添加了一个查询,显示聚集索引和非聚集索引的大小;聚集索引要大得多。很好的研究。现在我相信这确实是出于性能原因。谢谢