在 MySQL 中创建带主键的数据表时,主键必须显式声明为 NOT NULL 且保持唯一,通常推荐使用 INT/BIGINT AUTO_INCREMENT;如果使用字符串主键,必须明确指定长度,并避免使用 TEXT/BLOB;若业务必须使用 UUID,建议存储为 BINARY(16) 以获得更好的查询性能和索引效率。

主键必须是 NOT NULL 且唯一
在 MySQL 建表语句中,主键列必须不能为 NULL,同时值也不能重复。这是创建 MySQL 主键数据表的基础要求。如果你在建表时给主键字段写了 NULL,或者遗漏了 NOT NULL,MySQL 通常会自动补齐,但在实际开发中不应依赖这种隐式处理,显式声明会更规范也更安全。
一个非常常见的问题是:把 VARCHAR 字段作为主键使用,却忘记指定长度;或者直接使用了 TEXT 类型,而这类字段本身并不适合直接定义索引。最终结果往往就是建表失败,数据库直接报错:ERROR 1170 (42000): BLOB/TEXT column 'xxx' used in key specification without a key length。
- MySQL 主键字段必须声明为
NOT NULL(即使不写,MySQL 也会强制处理,但仍建议明确写出) - 字符串类型主键必须指定长度,例如
id VARCHAR(32) PRIMARY KEY,不能只写VARCHAR - 应避免使用
TEXT、BLOB、JSON作为主键,因为它们不适合直接用于索引定义
推荐用自增整数做主键:INT + AUTO_INCREMENT
除非业务场景有明确要求,例如分布式 ID、UUID 或跨系统唯一标识,否则在 MySQL 建表时优先使用 INT 或 BIGINT 搭配 AUTO_INCREMENT 作为主键。这种主键方案更高效、占用空间更小、数据天然有序,而且也是 MySQL 优化最成熟、最常见的主键设计方式。
需要注意的是:AUTO_INCREMENT 必须与 PRIMARY KEY 或 UNIQUE KEY 一起使用,并且该字段必须是索引列;如果你是在建表完成后再补充自增属性,通常需要先为该列创建索引,再进行字段修改。
id INT PRIMARY KEY AUTO_INCREMENT是最常用也最简洁的写法,等价于id INT NOT NULL PRIMARY KEY AUTO_INCREMENT- 自增主键默认从 1 开始,可以通过
ALTER TABLE tbl AUTO_INCREMENT = 100修改起始值 - 如果插入数据时显式指定了
id值(例如INSERT INTO t(id) VALUES(5)),后续自增序列会从该值加 1 继续,而不是简单“跳过”
用 UUID 或雪花 ID 当主键?注意性能和排序问题
如果在 MySQL 中使用 UUID() 或外部生成的字符串 ID 作为主键,例如 CHAR(36) 或 BINARY(16),那么主键通常会失去连续顺序性。这会带来更频繁的页分裂、插入性能下降以及索引碎片增多等问题,因此在设计 MySQL 主键时必须提前评估性能影响。
如果业务确实需要使用 UUID,推荐将其转换为二进制格式存储,例如:id BINARY(16) PRIMARY KEY DEFAULT (UNHEX(REPLACE(UUID(), '-', '')))。与直接存储字符串形式相比,这种方式可以节省近一半的存储空间,同时提高索引命中率和查询效率。
- 不要直接把
UUID()生成结果按字符串存入主键 ——CHAR(36)字段过宽,会导致索引体积更大、缓存利用率更低 - 在 UUID 主键上执行
ORDER BY id通常没有太强的业务意义,因为它并不能保证真实时间顺序 - 如果现有业务已经使用
UUID字符串,至少可以增加前缀索引,例如INDEX idx_id_prefix (id(8)),但从长期维护和性能角度看,仍不如改为二进制存储更彻底
建表语句里定义主键的三种常见写法
在 MySQL 建表语句中,主键既可以直接写在字段定义里,也可以通过表级约束单独声明。这两种写法都合法,只是在语义表达和代码可读性上有所不同。对于单列主键,列级写法通常更直观;对于多列组合主键,表级写法会更清晰。
例如这个写法:CREATE TABLE t (id INT, PRIMARY KEY (id)); 看起来似乎没有问题,但如果 id 没有显式写出 NOT NULL,虽然 MySQL 会自动补上约束,但你的 SQL 代码本身并没有清楚表达这一点,后续阅读和协作时容易造成误解。
- 列级定义(推荐用于单列主键):
id BIGINT PRIMARY KEY AUTO_INCREMENT - 表级定义(适合联合主键或组合主键):
PRIMARY KEY (user_id, order_id) - 命名主键约束(便于维护和后期管理):
CONSTRAINT pk_user PRIMARY KEY (id),后续删除主键时可使用DROP PRIMARY KEY或DROP CONSTRAINT pk_user(具体取决于 MySQL 版本)
NOT NULL,也不要忽视字段类型长度的限制。主键设计一旦进入生产环境,后续修改的成本通常远高于前期多写几个字符。合理设计 MySQL 主键,不仅关系到建表是否规范,也会直接影响查询效率、索引性能和后续系统扩展能力。