Sql server 非聚集主键困境
假设我们必须为Stackoverflow问题定义最佳索引。但我们不要使用实际的Posts表的模式,我们只需要包含那些实际相关的列:Sql server 非聚集主键困境,sql-server,primary-key,clustered-index,sql-optimization,non-clustered-index,Sql Server,Primary Key,Clustered Index,Sql Optimization,Non Clustered Index,假设我们必须为Stackoverflow问题定义最佳索引。但我们不要使用实际的Posts表的模式,我们只需要包含那些实际相关的列: create table Posts ( Id int not null identity, PostTypeId tinyint not null, LastActivityDate datetime not null default getdate(), Title nvarchar(500) nu
create table Posts (
Id int not null
identity,
PostTypeId tinyint not null,
LastActivityDate datetime not null
default getdate(),
Title nvarchar(500) null, -- answers don't have titles
Body nvarchar(max) not null,
...
)
我已经将Id
添加为identity,即使这些表和identity列都没有主键约束。有许多只是唯一/非唯一的聚集/非聚集索引
使用场景
因此,基本上有两种主要的帖子场景:
LastActivityDate
列中(或者可能是LastEditDate
,我在上面没有包括,因为它不太重要)ScoreCount
列不属于我的上级代码)-- index 1
alter table Posts
add primary key nonclustered (Id);
-- index 2
create clustered index IX_Posts_LastActivityDate
on Posts(LastActivityDate desc);
-- index 3
create index IX_Posts_ParentId
on Posts(ParentId, PostTypeId)
include (ScoreCount);
这样我们基本上得到了三个指数,其中第二个指数是聚集的
所以为了使#1工作得非常快,我在LastActivityDate
列上设置了聚集索引,因为当我们对它们进行范围比较时,聚集索引特别有用。我们将按时间顺序排列问题,从最新到最旧,因此我已经设置了排序方向,并在聚集索引中包含了类型
那么我们用这个解决了什么呢
ScoreCount
排序;如果我们决定按时间顺序排列答案,也包括索引2李>
问题1
SQL内部结构使得SQL隐式地将聚集键添加到非聚集索引,以便它可以在行存储中定位记录
- 如果聚集索引是唯一的,那么这就是将添加到非聚集索引的键,并且
- 若集群索引是非唯一的,那个么SQL应该生成自己的
,并使用它UniqueId
create unique index UX_Posts_Id
on Posts(Id);
-- include (Title, Body, ScoreCount);
同时包含注释掉的列会很好,但这样会使该索引效率低下,因为它在缓存方面会更差。。。为什么我要问,创建这个索引而不是主键
约束是否更好,是因为我们可以在这个索引中包含额外的非键列,而当我们添加一个在内部生成唯一索引的PK约束时,我们不能这样做
问题3
我知道,代码> ListActuviyDATE < /COD>不适合用聚集索引来进行更改,但是我们必须考虑这样一个事实,即该列在变得静态或静态之前更容易改变一段时间,因此,它不应该导致太多索引碎片,因为只要LastActivityDate发生更改,记录大多会追加到末尾。一些任意页面上的索引碎片永远不会发生,因为一些新记录将插入到一些旧(er)页面中,因为
LastActivityDate
只会增加。因此,大多数修改将发生在最后一页
因此,问题是这些更改是否有害,因为LastActivityDate
不是聚类索引键的最佳候选项:
- 它不是唯一的——尽管人们可能会对此争论,特别是如果我们将
更改为datetime
并使用更高精度的函数datetime2
并将索引设置为sysdatetime()
unique
- 很窄,差不多
- 它不是静态的——但我已经解释了它是如何变化的
- 它一直在增加
create unique index UX_Posts_Id
on Posts(Id);
-- include (Title, Body, ScoreCount);
从数据建模的角度来看,每个关系表都应该有主键。隐式创建的索引可以根据需要声明为聚集索引或非聚集索引,以优化性能。如果LastActivity
是更好的性能选择,则主键索引必须是非聚集索引。这个主键索引将提供检索单例文章所需的索引
不幸的是,SQLServer没有提供在主键a上指定包含列的方法