【发布时间】:2021-09-03 01:23:16
【问题描述】:
我正在尝试了解如何正确使用非聚集索引。这是我在测试数据中发现的。
CREATE TABLE TestTable
(
RowID int Not Null IDENTITY (1,1),
Continent nvarchar(100),
Location nvarchar(100)
CONSTRAINT PK_TestTable_RowID
PRIMARY KEY CLUSTERED (RowID)
)
ALTER TABLE TestTable
DROP CONSTRAINT PK_TestTable_RowID
GO
INSERT INTO TestTable
SELECT Continent, Location
FROM StgCovid19
DBCC DROPCLEANBUFFERS
DBCC FREEPROCCACHE
SELECT *
FROM TestTable
WHERE Continent = 'Asia' --551ms
CREATE NONCLUSTERED INDEX NCIContinent
ON TestTable(Continent)
DBCC DROPCLEANBUFFERS
DBCC FREEPROCCACHE
SELECT *
FROM TestTable
WHERE Continent = 'Asia' --1083ms
DROP INDEX NCIContinent
ON TestTable
CREATE NONCLUSTERED INDEX NCIContinent
ON TestTable(Continent)
INCLUDE (Location)
DBCC DROPCLEANBUFFERS
DBCC FREEPROCCACHE
SELECT *
FROM TestTable
WHERE Continent = 'Asia' ---530ms
正如你们所看到的,如果我只在Continent 列上添加非聚集索引,它会执行查找,并且执行选择的时间也会增加一倍。
当我添加 INCLUDE (Location) 时,它比没有任何聚簇索引的时间要少。
你们能告诉我发生了什么事吗?
【问题讨论】:
-
这是因为您的查询中的
select *。它需要查找匹配行中的所有列以满足查询。通读Clustered and Nonclustered Indexes Described 以了解非聚集索引在不存在/存在聚集索引时的行为 - 请注意“行定位器”的定义。 -
设计数据库是一项必须学习的技能。您在创建表后立即删除了主键(和聚集索引) - 为什么?这样做会让你的桌子变成一堆。如果您的列是 nvarchar,那么您的文字也应该是。养成良好的习惯。也许在这里您并不真正需要/打算使用 nvarchar 字符串 - 但您创建了表,因此您需要将代码与架构对齐。
-
@AlwaysLearning 那么是否正确,当我的查询在“RowID”和“Continent”上有 where 子句时,我应该为“RowID”(主键)和 Nonclustered 提供“Continent” '。如果在我的 SELECT 语句中我还选择了 Country 列,我应该在 nonclustered 上使用 INCLUDE?
-
@SMor 我正在学习数据仓库 ETL,有人告诉我应该在将数据插入表之前删除索引。然后在插入后再次创建索引。如果以上是真实情况,我一开始就不会创建任何索引。我会插入所有数据并创建索引
标签: sql-server indexing