CREATE TABLE 是什么
CREATE TABLE 在建表时把主键、约束、字符集与存储引擎一次定清楚,因为表一旦有数据,改类型的代价远高于一次写对。MySQL 8.0 默认引擎就是 InnoDB,字符集建议显式写 utf8mb4,才能完整支持 Unicode 与 emoji;PostgreSQL 更关注类型选择与约束表达,自增列推荐写 GENERATED ALWAYS AS IDENTITY,而不是已不推荐的 serial。金额一律用 DECIMAL 或 numeric 定点类型,时间列给默认值,主键必建,常用查询条件提前规划索引,这几点在两库通用。
基本信息
| 适用平台 | MySQL 8.0 与 PostgreSQL 12 及以上 |
|---|---|
| MySQL 引擎 | 显式写 ENGINE=InnoDB,8.0 默认即为 InnoDB |
| MySQL 字符集 | 显式写 DEFAULT CHARSET=utf8mb4,不要依赖服务器默认值 |
| PostgreSQL 自增 | GENERATED ALWAYS AS IDENTITY,替代旧的 serial |
| 金额类型 | DECIMAL(p,s) 或 numeric(p,s),不用 FLOAT 与 DOUBLE |
| 时间列默认值 | MySQL 用 CURRENT_TIMESTAMP,PostgreSQL 用 now() |
| 索引声明 | MySQL 可写在 CREATE TABLE 内,PostgreSQL 通常独立建索引 |
典型使用场景
- 新业务建表:一次把主键、时间列与常用查询索引定好
- 设计文档落地:把 ER 图转成 DDL,字段类型与约束逐条对齐
- 在线变更:先建同构的影子表,迁完数据再改名切换
- 归档表:按时间维度建结构一致的归档表
- 测试环境初始化:脚本化建表,保证环境可重复搭建
- 分表场景:按业务键建同构子表,字段与索引保持一致
MySQL 建表
MySQL 建表
CREATE TABLE orders (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, # 主键用 BIGINT 起步
user_id BIGINT UNSIGNED NOT NULL, # 关联用户
amount DECIMAL(12,2) NOT NULL DEFAULT 0.00, # 金额用定点类型
status TINYINT NOT NULL DEFAULT 0, # 状态用小整型
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (id),
KEY idx_user_created (user_id, created_at) # 联合索引:等值列在前
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;PostgreSQL 建表
PostgreSQL 建表
CREATE TABLE orders (
id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY, # 自增主键
user_id bigint NOT NULL,
amount numeric(12,2) NOT NULL DEFAULT 0, # 定点类型
status smallint NOT NULL DEFAULT 0,
created_at timestamptz NOT NULL DEFAULT now(),
updated_at timestamptz NOT NULL DEFAULT now()
);
CREATE INDEX idx_orders_user_created ON orders (user_id, created_at);建表要点对照
| 要点 | MySQL | PostgreSQL |
|---|---|---|
| 自增主键 | AUTO_INCREMENT | GENERATED ALWAYS AS IDENTITY |
| 字符集 | DEFAULT CHARSET=utf8mb4 | 由库编码决定,通常 UTF8 |
| 时间类型 | DATETIME / TIMESTAMP | timestamp / timestamptz |
| 索引声明 | 可写在 CREATE TABLE 内 | 通常独立 CREATE INDEX |
| 布尔类型 | TINYINT 约定 0 与 1 | boolean 原生支持 |
不写字符集就依赖服务器默认值,老实例可能是 latin1,新老库混用后中文与 emoji 直接出错;建表时显式声明最省心。
自增主键从 BIGINT 起步,避免业务增长后改类型;主键类型一旦上线要改,牵涉所有关联表,代价很高。
PostgreSQL 的 timestamptz 会做时区转换,timestamp 不会;用哪种要在建模阶段统一,混用会造成时间显示错乱。
给列加 NOT NULL 与默认值能挡掉一批脏数据,可空列越多,后续查询要处理的空值边界就越多。
建表实践要点
- 主键必建:没有主键的表在复制与在线变更时问题很多
- 字段尽量给默认值:新增列给默认值能避免应用侧到处判空
- 类型一次选对:金额定点、状态小整型、时间带时区信息
- 索引与查询一起设计:常用等值加范围条件组成联合索引
- 表与字段写注释:COMMENT 能省下后来人大量猜测时间
- 预留扩展:新增枚举值不要写进注释当契约,改用独立字典表