订单表设计需分离用户、商品、订单核心实体,主表存状态与归属信息,订单项表存价格快照与明细;通过外键、索引保障一致性与查询效率,并预留地址、日志、退换货等扩展结构。

订单表是电商或交易类系统的核心,设计时要兼顾业务清晰性、数据一致性和查询效率。重点在于分离核心实体(用户、商品、订单)、避免冗余、预留扩展空间。
订单主表:记录订单基本状态和归属
存放订单的全局信息,不存明细,不存价格快照(价格应由订单项承载)。
- order_id:主键,建议用 BIGINT 自增 或 UUID(分布式场景优先雪花ID)
- user_id:关联用户表,NOT NULL,加索引
- order_status:如 ‘pending’, ‘paid’, ‘shipped’, ‘completed’, ‘cancelled’,用 enum 或 TINYINT + 注释说明,避免字符串拼写错误
- total_amount:订单总金额(元),用 DECIMAL(10,2),不是 Float
- created_at / updated_at:时间戳,自动维护
- pay_time / ship_time:可为空,按需记录关键节点时间
订单项表(order_items):拆解每一件购买的商品
一对多关系,一个订单可含多个商品;此处保存下单时的价格、数量、规格快照,确保历史可追溯。
- id:主键,自增
- order_id:外键,关联订单主表,加索引
- product_id:商品ID,可为空(比如虚拟服务类无实物ID),加索引
- sku_id:具体规格ID(如颜色+尺寸),更精准,推荐必填
- quantity:购买数量,TINYINT 或 SMALLINT 足够
- unit_price:下单时单价,DECIMAL(10,2),不可从商品表实时查——价格可能已变
- subtotal:小计 = quantity × unit_price,冗余字段,提升统计效率,也可不存(应用层计算)
关联与约束:保障数据一致性
mysql 层面通过外键 + 索引兜底,但业务逻辑仍需在应用层校验。
- order_items.order_id 应设 FOREIGN KEY 指向 orders.order_id(启用 InnoDB,且注意外键对批量插入性能的影响)
- 在 orders 表上为 user_id、order_status、created_at 建复合索引,例如 (user_id, order_status, created_at) 支撑用户订单列表查询
- 在 order_items 上为 order_id 建索引(必选),为 sku_id 单独建索引(便于按商品查销量)
- 避免在订单主表里存用户姓名、手机号、地址——应通过 user_id 关联用户表,地址另建 order_addresses 表(支持多次收货不同地址)
可选但推荐的扩展结构
- order_addresses:独立地址表,字段包括 name、phone、province/city/district、detail、postal_code,关联 order_id
- order_logs:记录订单状态变更日志(谁、何时、从A到B、原因),用于排查和审计
- refunds / returns:退款/退货单独建表,不要直接更新订单主表字段,保证原始订单不可变