id列或聚簇主键/数据库一致性

时间:2010-03-02 19:00:06

标签: sql database identity consistency

如果我有一个包含列的表:

  • 艺术家
  • 相册
  • NumberOfListens

...最好将一个聚类主键放在Artist,Album和Song上,或者拥有一个自动增量id列,并对Artist,Album和Song设置一个唯一约束。

数据库一致性有多重要?如果我的一半表具有聚簇主键而另一半表具有唯一约束的id列,那么这是坏的还是无关紧要?这两种方式对我来说都是一样的,但我不知道行业标准是什么,哪种更好,为什么。

5 个答案:

答案 0 :(得分:5)

我永远不会在长文本列上放置主键,例如:Artist,Album和Song。使用作为群集PK的自动增量ID。如果您希望艺术家,专辑和歌曲是唯一的,请在三者上添加唯一索引。如果你想通过专辑或歌曲进行搜索,独立于独立的艺术家,你需要一个索引,它可以拉入PK,所以拥有一个小的PK可以节省你对彼此的索引。节省的不仅仅是磁盘空间,而是内存缓存,以及页面上的更多键。

答案 1 :(得分:1)

你真的需要分开两个问题:

1)主键是一个逻辑结构 - 唯一且可靠地标识表中每一行的候选键之一。这可以是任何东西,真的 - 一个INT,一个GUID,一个字符串 - 选择对你的场景最有意义的东西。您在外键约束中引用主键,因此这些对于数据库的完整性至关重要。使用它们 - 总是 - 期间。

2)集群密钥(在表上定义“聚集索引”的一列或多列) - 这是物理存储相关的东西,在这里,一个小的,独特的,稳定的,不断增加的数据类型是您最好的选择 - INT或BIGINT作为您的默认选项。

默认情况下,SQL Server表上的主键也用作群集键 - 但不一定是这样,您可以轻松选择不是主键的列作为群集键

然后还有另一个需要考虑的问题:表格上的聚类键也会被添加到表格中每个非聚集索引的每个条目上 - 因此你真的想确保它尽可能小。通常,对于绝大多数表来说,具有2亿行的INT应该足够 - 并且与作为群集密钥的VARCHAR(20)相比,您可以在磁盘和服务器内存中节省数百兆字节的存储空间。

更多值得思考的东西 - 金佰利特里普的优秀作品 - 阅读,再读一遍,消化它!这是SQL Server索引福音,真的。

马克

答案 2 :(得分:0)

群集索引非常适合基于范围的查询。例如,日志日期或订单日期。将一个放在Artist,Album和Song上会在插入新行时[可能]导致碎片。

如果您的数据库支持它,请在Artist,Album和Song上添加非群集主键,并将其调用好。或者只是在艺术家,专辑和歌曲上添加一个唯一的键。

如果必须具有对另一个表的引用完整性,那么自动增量主键只会非常有用。

答案 3 :(得分:0)

在不知道确切要求的情况下,一般情况下你可能会有一个艺术家表,也可能有专辑表。然后,歌曲表将是艺术家ID,专辑ID和歌曲的独特组合。我会根据应用程序通过索引或约束来强制执行唯一性,并使用id作为主键。

答案 4 :(得分:0)

首先,这里已经存在问题,因为数据没有标准化。在一堆文本列上创建任何类索引是应该尽可能避免的。即使这些列不是文本(我怀疑它们是这样的),在同一个表中将艺术家,专辑歌曲放在一起仍然没有意义。一个很多更好的设计是:

Artists (
    ArtistID int NOT NULL IDENTITY(1, 1) PRIMARY KEY CLUSTERED,
    ArtistName varchar(100) NOT NULL)

Albums (
    AlbumID int NOT NULL IDENTITY(1, 1) PRIMARY KEY CLUSTERED,
    ArtistID int NOT NULL,
    AlbumName varchar(100) NOT NULL,
    CONSTRAINT FK_Albums_Artists FOREIGN KEY (ArtistID)
        REFERENCES Artists (ArtistID))

Songs (
    SongID int NOT NULL IDENTITY(1, 1) PRIMARY KEY CLUSTERED,
    AlbumID int NOT NULL,
    SongName varchar(100) NOT NULL,
    NumberOfListens int NOT NULL DEFAULT 0
    CONSTRAINT FK_Songs_Albums FOREIGN KEY (AlbumID)
        REFERENCES Albums (AlbumID))

一旦拥有此设计,您就可以搜索单个专辑和艺术家以及歌曲。您还可以添加覆盖索引以加快查询速度,索引将小得多,因此比原始设计更快。

如果您不需要进行范围查询(您可能不需要),那么如果更适合您的设计,则可以用IDENTITY替换ROWGUID密钥;在这种情况下,这并不重要,我会坚持使用简单的IDENTITY

您必须小心群集密钥。如果你集中了一个完全不是远程连续的键(并且艺术家,专辑和歌曲名称绝对有资格作为非顺序),那么你最终会出现页面拆分和其他恶意。你不想要这个。正如Marc所说,这个密钥的副本会被添加到每个索引中,当你的密钥长度为300或600字节时,肯定不希望这样。

如果您希望能够通过艺术家,专辑和歌曲名称快速查询特定歌曲的听众数量,实际上使用上述设计非常简单,您只需要正确索引:

CREATE UNIQUE INDEX IX_Artists_Name ON Artists (ArtistName)
CREATE UNIQUE INDEX IX_Albums_Artist_Name ON Albums (ArtistID, AlbumName)
CREATE UNIQUE INDEX IX_Songs_Album_Name ON Songs (AlbumID, SongName)
    INCLUDE (NumberOfListens)

现在这个查询会很快:

SELECT ArtistName, AlbumName, SongName, NumberOfListens
FROM Artists ar
INNER JOIN Albums al
    ON al.ArtistID = ar.ArtistID
INNER JOIN Songs s
    ON s.AlbumID = al.AlbumID
WHERE ar.ArtistName = @ArtistName
AND al.AlbumName = @AlbumName
AND s.SongName = @SongName

如果您查看执行计划,您将看到3个索引搜索 - 它的速度与您获得的速度一样快。我们保证了与原始设计中完全相同的唯一性针对速度进行了优化。更重要的是,它已经标准化,因此艺术家和专辑都有自己的特定身份,这使得长期管理变得更加容易。搜索“艺术家X的所有专辑”要容易得多。搜索“专辑Y中的所有歌曲”更容易,更快

在设计数据库时,规范化应该是您的第一个问题,索引应该是您的第二个。你可能会发现,一旦你有一个标准化的设计,最好的索引策略就变得很明显了。