VARCHAR 主键 - MySQL

day*_*oli 9 mysql performance foreign-key primary-key varchar

目前,我有一个categories包含 2 列的表 -category VARCHAR(50) NOT NULL PRIMARY KEYparent VARCHAR(50). 该parent列是该列的外键 (FK) category

这似乎是最明显的方法。但是,警钟在我的脑海中响起,因为我使用一VARCHAR列作为主键,这可能会在查询表时减慢操作速度。

我可以引入名为cat_id INT AUTO_INCREMENTPK的第三列,但它会引入一个没有意义的新列。

除了哪个更快,还应该考虑哪些其他因素?

NB我预测最多会有1000个类别左右,所以行数不是很高。但是,categoriesPK 列将成为其他表中许多外键的引用列。

我也应该使用(唯一的)用户名作为 PK 吗?

Aas*_*lah 9

VARCHAR 列作为主键不是一个好的选择,因为通常我们在同一列上创建集群索引。

VARCHAR 列上的集群索引是一个糟糕的选择,因为预期的碎片率很高。每个新插入的键值都会尝试在现有键之间的某个位置找到它的位置,并且通常会导致页面拆分和高索引碎片。结果导致性能不佳和额外的索引重建/重组成本。

其次varchar,与伪键auto-incremented列相比,使用键列作为外键会占用额外的空间。

自增列上的聚集索引可能会创建“热点”。请仔细阅读“避免创建基于递增键的聚集索引”是 SQL Server 2000 天以来的神话吗?

尽管热点可能是一个问题,但何时有许多用户尝试插入值,但在您的情况下,与 varchar 相比,我仍希望使用自动递增的列。


And*_*nes 7

是的,我会添加一个代理 4 字节整数键。您当前的两列是 100 字节,然后可以通过添加新的标识列将其减少到 58 字节。如果您确定永远不会超过 65,535 个类别,您甚至可以将代理键设为 2 字节的 smallint(为了以防万一,保留为 INT 可能仍然是一个好主意)。

对于一个 1,000 行的表来说,节省的空间并不是很大,但是在将 cat_id 添加到其他表的地方,您可以节省大量空间(4 个字节而不是每个 FK 中的 50 个)。您可能还想索引这些外键,因此在所有非聚集索引中节省的空间也会更大。

此外,您的聚集索引现在是连续的,以避免在添加新类别时出现碎片(页面拆分)

表结构:-

create table dbo.Cateogory (
    CateogoryID int not null identity(1,1) constraint pkCateogory primary key clustered,
    Cateogory varchar(50) not null constraint ukCateogory unique nonclustered,
    ParentCateogoryID int null constraint fkCateogory references dbo.Cateogory(CateogoryID)
    )
Run Code Online (Sandbox Code Playgroud)

您还可以根据您的要求在生产中添加索引选项(填充因子等)。