Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/23.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_Primary Key_Clustered Index_Sql Optimization_Non Clustered Index - Fatal编程技术网

Sql server 非聚集主键困境

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

假设我们必须为Stackoverflow问题定义最佳索引。但我们不要使用实际的Posts表的模式,我们只需要包含那些实际相关的列:

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
    列不属于我的上级代码)
  • 索引优化 在上述情况下,哪种指数最适合创建,特别是如果我们认为#1是最常见的情况,那么它必须非常快地工作

    我想说,更好的可能性之一是创建这些指数:

    -- 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
    列上设置了聚集索引,因为当我们对它们进行范围比较时,聚集索引特别有用。我们将按时间顺序排列问题,从最新到最旧,因此我已经设置了排序方向,并在聚集索引中包含了类型

    那么我们用这个解决了什么呢

  • 场景#1被索引2非常有效地覆盖,因为它是集群的,并且完全被覆盖;我们还可以轻松高效地进行结果分页
  • 场景#2在某种程度上被唯一索引1(获取问题)和非唯一索引3覆盖,以获取所有相关答案(场景#3),按
    ScoreCount
    排序;如果我们决定按时间顺序排列答案,也包括索引2 问题1 SQL内部结构使得SQL隐式地将聚集键添加到非聚集索引,以便它可以在行存储中定位记录

    • 如果聚集索引是唯一的,那么这就是将添加到非聚集索引的键,并且
    • 若集群索引是非唯一的,那个么SQL应该生成自己的
      UniqueId
      ,并使用它
    由于我还在表上添加了一个非聚集主键(设计上必须是唯一的),我想知道SQL是否仍将在聚集的非唯一索引上提供自己的唯一键,或者是否将使用非聚集主键来唯一标识每个记录

    问题2 所以,若主键不用于定位行存储(聚集索引)上的记录,那个么实际创建PK是否有意义呢?在这种情况下,宁愿这样做会更好吗

    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
    • 很窄,差不多
    • 它不是静态的——但我已经解释了它是如何变化的
    • 它一直在增加
    因为我还在表中添加了一个非聚集主键( 设计上必须是唯一的),我想知道SQL是否仍然 在聚集的非唯一索引上提供其自己的唯一键,否则将使用 是否使用非聚集主键来唯一标识每个记录

    当给定的非唯一聚集索引键值不唯一时,SQL Server会添加一个4字节的“唯一化器”。所有非聚集索引叶节点(包括主键)将包括LastActivityDate加上唯一标识符(如果存在)作为行定位器。在这里,只有具有相同LastActivityDate的帖子才需要内部唯一性,因此我预计实际需要唯一性的行相对较少

    所以如果主键不用于定位行存储(集群)上的记录 索引)实际创建PK有意义吗?你会在这里吗 这样做更好吗

    create unique index UX_Posts_Id
    on Posts(Id);
    -- include (Title, Body, ScoreCount);
    
    从数据建模的角度来看,每个关系表都应该有主键。隐式创建的索引可以根据需要声明为聚集索引或非聚集索引,以优化性能。如果
    LastActivity
    是更好的性能选择,则主键索引必须是非聚集索引。这个主键索引将提供检索单例文章所需的索引

    不幸的是,SQLServer没有提供在主键a上指定包含列的方法