要考虑的一件事是主键和聚簇索引不是同一件事。主键是一个约束,它处理数据生存所依据的规则(即数据完整性);它与效率/性能无关。主键要求键列是唯一的(组合)和NOT NULL(单独)。PK是通过唯一索引强制执行的,尽管它可以是群集的也可以是非群集的。
聚集索引是一种物理(即在磁盘上)对表中的数据进行排序并处理性能的方法。它与数据完整性无关。聚集索引可以要求键列是唯一的(组合),但不是必须的。但是,由于聚簇索引是数据的物理顺序,因此无论如何都需要唯一地标识每一行。因此,如果您不将其设置为要求唯一性,它将通过一个隐藏的4字节“ uniquifier”列创建自己的唯一性。该列始终在非唯一聚集索引中存在,但是当键字段是唯一的(组合)时,它不会占用任何空间。首先了解一下“ uniquifier”列的工作方式(在聚集索引中以及对非聚集索引的影响),用于测试Uniquifier大小的T-SQL脚本。
因此,主要问题是:
添加自动递增id
字段并将其与company_id
主键结合使用会更有效,还是会增加不必要的开销
将这两个概念混为一谈,因此尽管确实存在一些重叠,但仍需要分别解决。
应该IDENTITY
添加一列还是不必要的开销?
如果添加一INT IDENTITY
列并使用它来创建PK(假设它是集群PK),则会向每行添加4个字节。该列是可见的,可用于查询。它可以作为外键添加到其他表中,尽管在这种情况下不会发生。
如果不添加该INT IDENTITY
列,则无法在此表上创建PK。但是,只要不使用该UNIQUE
选项,仍可以在表上创建聚簇索引。在这种情况下,SQL Server将添加一个名为“ uniquifier”的隐藏列,其行为如上所述。由于该列是隐藏的,因此无法在查询中使用或用作外键的引用。
因此,就效率而言,这些选择大致相同。是的,将有稍微由具有非唯一聚集索引占据更少的空间,由于某些行(连同初始唯一密钥值的)占0字节,而在所有的行IDENTITY
/ PK将采取4个字节。但是不会有足够的0字节行(尤其是预期的行数很少)来注意到差异,更不用说能够ID
在查询中使用该列的便利了。
INT IDENTITY列还是org_path
持久计算列的哈希?
鉴于您不会根据org_path
值查找行,因此添加“持久计算列”的开销以及需要在查询中计算该哈希值以与“计算列”进行匹配都没有道理(这是我的原始建议,可在此处的修订历史中找到,该建议基于问题的初始措辞/细节)。在这种情况下,INT IDENTITY
“ ID”列可能是最好的。
关键列顺序
鉴于ID
Column很少(如果有的话)用在查询中,并且鉴于两个主要用例是获取“所有行”或“给定的所有行company_id
”,我将在上创建PK company_id, id
。并且由于这意味着行不会被顺序插入,因此我将指定a FILLFACTOR
为90。您还需要确保进行常规索引维护以减少碎片。
第二个问题
company_id是另一个表中的主键的事实在这里是否有任何作用
没有。
触发
由于中的org_path
值company_id
是唯一的,因此您仍应创建一个Trigger INSERT, UPDATE
来强制执行此操作。在触发器中,对IF EXISTS
可能执行COUNT(*)
和的查询执行GROUP BY company_id, org_path
。如果发现任何问题,请发出a ROLLBACK
来取消DML操作,然后RAISERROR
说有重复项。
校对
在我的最初答案中(基于问题的原始措辞/稀疏细节,并在此处的修订历史记录中提供),我建议可能使用二进制(即_BIN2
)归类。现在我们已经了解了到底org_path
是什么,我不建议使用二进制归类。由于会有变音符号,因此您确实想使用语言对等。