适当的稀疏主键表设计

时间:2017-08-10 03:28:35

标签: sql-server database-design

在我的系统中,我有根据存储在我的数据库中的规则创建的临时实体,并且实体不会被保留。

现在,我需要存储有关这些实体的信息,因为它们是根据规则创建的,并且没有存储,所以它们没有ID。

我想出了一个公式,根据用于生成它们的规则为这些临时实体生成ID:id = rule id +" - " +规则中的实体索引。此公式生成164-3,123-0,432-2等形式的唯一字符串...

我的问题是,当我的密钥没有关系或订单时,我应该如何构建我的表(关于主键和聚簇索引)?请记住,我只会(99.9%的时间)使用上面提到的ID查询表格。

我经过多次阅读后想到的选项,但没有知识来确定哪个更好:

1)具有聚簇索引的varchar列上的主键。 - 根据各种消息来源,由于碎片和密钥的广泛性,这将是不好的。他们的格式对于排序也很奇怪。

2)varchar列上的主键没有聚簇索引(堆表)。 - 由于索引和碎片问题,根据各种来源也是一个坏主意。

3)identity int column with clustered index,varchar column as primary key with unique index。 - 不能在这里看到surogate键的好处,因为它主要有助于范围查询和排序,我永远不会根据这个键查询表,因为它在任何时候都是未知的。

4)2列复合键:规则id +规则索引列。 - 现在我没有字符串,但我有两列将被复制到FK和非聚集索引。此外,我不确定在这种情况下我会使用哪些索引。

有人能在这里发光吗?任何帮助表示赞赏。

- 编辑
我将执行比插入更多的选择;
我将执行更多插入而不是更新;
所有选择将至少包括规则ID;

如果我使用surogate主键和(rule id,index)上的唯一索引,那么我可以在按规则ID检索数据后使用surogate进行后续操作,这会更快。此外,插入会更快。 但是,因为数据将根据surogate键存储,所以我可能有相同规则id但不同索引的记录,在磁盘上存储的距离相当远,这意味着即使使用规则id的索引,也可以检索数据可能有点慢。

如果我使用(rule id,index)作为聚簇主键,则具有相同规则id的行将彼此靠近地存储,并且按规则id选择数据将足够有效。但是,我怀疑插入会很慢。

上面的基本原理是否正确?

1 个答案:

答案 0 :(得分:1)

除非另有证明,否则使用堆通常是个坏主意。即便如此,您还需要一个非常坚实的理由,即没有聚集索引(任何一个都能让事情变得更好,即使在identity列上也是如此)。

将此密钥存储在一个列中是可以的;例如,如果您想要自然排序,可以用零填充数字。但是,这将扩大关键。

拥有复合主键(以及随后的外键)是完全可以接受的,尤其是在处理自然键时,例如你所拥有的键。这将为您提供尽可能最窄的密钥 - int + int或其他一些密钥 - 同时消除排序问题。我建议将这个PK集群化,以减少额外的密钥查找。

这里的碎片不是一个大问题;至少,不比任何其他索引决定更大。在这样的密钥上构建的任何索引都将容易碎片化,聚集或不碎片。在任何情况下,您的DBA都应该知道如何以最佳形式保留这样的索引。

关于索引中列的顺序,通常适用以下规则:

  1. 如果发生部分密钥匹配(按密钥的一部分而不是另一部分进行过滤),那么最常使用的密钥应先行;
  2. 如果No.1不适用且密钥的所有部分都在所有查询中使用,则cardinality最高的列应首先显示。
  3. 剩余列的顺序(如果超过1)并不重要,因为SQL Server仅为复合索引中的第一列创建分布统计信息。但是,按照降低基数的顺序列出它们是个好主意。

    编辑:查看您的更新以及其他详细信息,以下是最合适的选项。假设你的表看起来像这样:

    -- Sample table
    create table dbo.TempEntities (
        RuleId int not null,
        IndexId int not null,
        -- Remaining columns listed here
        EntityData xml not null
    );
    go
    

    从这里开始,最直接的方法是使用自然键作为聚集索引:

    -- Option 1 - natural clustered index
    alter table dbo.TempEntities
    add constraint PK_TempEntities primary key clustered (RuleId, IndexId);
    go
    

    但是,如果你有任何子表可以引用这个,它可能不是最方便的解决方案,因为自然键很容易更新,这会造成一个混乱,你可以避免它。相反,可以引入代理键,如下所示:

    -- Option 2 - surrogate clustered, natural nonclustered
    alter table dbo.TempEntities add Id bigint identity(1,1) not null;
    
    alter table dbo.TempEntities
    add constraint PK_TempEntities primary key clustered (Id);
    
    alter table dbo.TempEntities
    add constraint UQ_TempEntities_RuleIdIndexId unique (RuleId, IndexId);
    go
    

    将代理PK聚类是有意义的,因为它将导致更少的页面拆分,使插入更快(尽管与选项1相比有一个索引更多)。如果您对查询没有任何了解,这可能是最平衡的解决方案。

    在代理和自然键之间混合clustered属性具有很大的学术价值,只能在高负荷系统上产生差异,在24 * 7时间表上每秒钟发生数百次插入。如果您的系统确实如此,请寻求专业顾问,他将分析您的疑问并提供适合您情况的解决方案。