主键必须显式声明NOT NULL且唯一,推荐用INT/BIGINT AUTO_INCREMENT;字符串主键需指定长度,禁用TEXT/BLOB;UUID应存为BINARY(16)以提升性能。
MySQL 要求主键列不能为 NULL,也不能重复。如果你在建表时给主键列写了 NULL 或漏写 NOT NULL,MySQL 会自动补上——但别依赖这个行为,显式声明更安全。
常见错误:用 VARCHAR 字段当主键却没设长度,或用 TEXT 类型(不支持索引),直接报错 ERROR 1170 (42000): BLOB/TEXT column 'xxx' used in key specification without a key length。
NOT NULL(即使不写,MySQL 也会强制,但建议明写)id VARCHAR(32) PRIMARY KEY,不能只写 VARCHAR
TEXT、BLOB、JSON 做主键——它们不支持索引定义除非业务强要求(如分布式 ID、UUID),否则优先选 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
ALTER TABLE tbl AUTO_INCREMENT = 100 调整起始值id 值(如 INSERT INTO t(id) VALUES(5)),后续自增会从该值+1继续,不是“跳过”如果用 UUID() 或外部生成的字符串 ID(如 CHAR(36) 或 BINARY(16)),主键就失去顺序性,会导致频繁页分裂、插入变慢、索引碎片多。
真正要用 UUID,建议转成二进制存:id BINARY(16) PRIMARY KEY DEFAULT (UNHEX(REPLACE(UUID(), '-', ''))),比字符串节省一半空间,查询也更快。
UUID() 函数直接存字符串 —— CHAR(36) 太宽,索引体积大,缓存效率低ORDER BY id 在 UUID 主键上基本无业务意义,时间顺序无法保证UUID 字符串,至少加前缀索引,如 INDEX idx_id_prefix (id(8)),但不如换二进制方案彻底主键可以在列定义内声明,也可以在表级约束中声明。两种都合法,但语义和可读性不同。列级写法更紧凑,表级写法方便多列联合主键。
错误示范:CREATE TABLE t (id INT, PRIMARY KEY (id)); 看似没问题,但如果 id 没写 NOT NULL,MySQL 会隐式加上——但你代码里没体现,容易误导协作者。
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(取决于版本)NOT NULL 或忽略类型长度限制。主键设计一旦上线,后期改起来代价远高于初期多敲几个字符。