电子商务系统的核心业务包含用户管理、商品管理、订单处理、购物车、支付、物流等多个模块,设计可维护的MySQL表结构需要优先梳理这些模块的核心实体和关联关系,在保证数据一致性的同时预留扩展空间。

核心表结构设计
用户表 user
用户表存储平台注册用户的基础信息,字段设计需要兼顾基础属性和扩展需求,避免使用过多冗余字段。
CREATE TABLE `user` ( `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '用户ID', `username` varchar(50) NOT NULL COMMENT '用户名', `password_hash` varchar(255) NOT NULL COMMENT '密码哈希值', `phone` varchar(20) DEFAULT NULL COMMENT '手机号', `email` varchar(100) DEFAULT NULL COMMENT '邮箱', `nickname` varchar(50) DEFAULT NULL COMMENT '昵称', `avatar` varchar(255) DEFAULT NULL COMMENT '头像地址', `status` tinyint(4) NOT NULL DEFAULT '1' COMMENT '状态 1正常 0禁用', `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', `updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', PRIMARY KEY (`id`), UNIQUE KEY `uk_username` (`username`), UNIQUE KEY `uk_phone` (`phone`), UNIQUE KEY `uk_email` (`email`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户基础信息表';
商品相关表
商品模块需要拆分商品基础表、商品分类表、商品库存表、商品属性表,避免单表字段过多,同时方便后续扩展商品类型。
商品分类表 category
CREATE TABLE `category` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '分类ID', `name` varchar(50) NOT NULL COMMENT '分类名称', `parent_id` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '父分类ID 0为一级分类', `sort` int(11) NOT NULL DEFAULT '0' COMMENT '排序值 越大越靠前', `status` tinyint(4) NOT NULL DEFAULT '1' COMMENT '状态 1启用 0禁用', `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', PRIMARY KEY (`id`), KEY `idx_parent_id` (`parent_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='商品分类表';
商品基础表 product
CREATE TABLE `product` ( `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '商品ID', `category_id` int(11) unsigned NOT NULL COMMENT '所属分类ID', `name` varchar(100) NOT NULL COMMENT '商品名称', `sub_title` varchar(200) DEFAULT NULL COMMENT '商品副标题', `main_image` varchar(255) DEFAULT NULL COMMENT '商品主图地址', `detail` text COMMENT '商品详情', `price` decimal(10,2) NOT NULL COMMENT '商品售价', `original_price` decimal(10,2) DEFAULT NULL COMMENT '商品原价', `status` tinyint(4) NOT NULL DEFAULT '1' COMMENT '状态 1上架 0下架', `sales_count` int(11) NOT NULL DEFAULT '0' COMMENT '销量', `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', `updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', PRIMARY KEY (`id`), KEY `idx_category_id` (`category_id`), KEY `idx_status` (`status`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='商品基础信息表';
商品库存表 product_stock
CREATE TABLE `product_stock` ( `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '库存ID', `product_id` bigint(20) unsigned NOT NULL COMMENT '商品ID', `stock` int(11) NOT NULL DEFAULT '0' COMMENT '库存数量', `locked_stock` int(11) NOT NULL DEFAULT '0' COMMENT '锁定库存 下单未支付数量', `updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', PRIMARY KEY (`id`), UNIQUE KEY `uk_product_id` (`product_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='商品库存表';
订单相关表
订单模块拆分订单主表和订单明细表,订单主表存储订单整体信息,明细表存储订单中的商品信息,避免单表数据量过大。
订单主表 order
CREATE TABLE `order` ( `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '订单ID', `order_no` varchar(32) NOT NULL COMMENT '订单编号', `user_id` bigint(20) unsigned NOT NULL COMMENT '用户ID', `total_amount` decimal(10,2) NOT NULL COMMENT '订单总金额', `pay_amount` decimal(10,2) NOT NULL COMMENT '实际支付金额', `discount_amount` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '优惠金额', `status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '订单状态 0待支付 1已支付 2已发货 3已完成 4已取消', `pay_type` tinyint(4) DEFAULT NULL COMMENT '支付方式 1微信 2支付宝 3银行卡', `pay_time` datetime DEFAULT NULL COMMENT '支付时间', `delivery_time` datetime DEFAULT NULL COMMENT '发货时间', `receive_time` datetime DEFAULT NULL COMMENT '收货时间', `cancel_time` datetime DEFAULT NULL COMMENT '取消时间', `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', `updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', PRIMARY KEY (`id`), UNIQUE KEY `uk_order_no` (`order_no`), KEY `idx_user_id` (`user_id`), KEY `idx_status` (`status`), KEY `idx_created_at` (`created_at`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='订单主表';
订单明细表 order_item
CREATE TABLE `order_item` ( `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '明细ID', `order_id` bigint(20) unsigned NOT NULL COMMENT '订单ID', `product_id` bigint(20) unsigned NOT NULL COMMENT '商品ID', `product_name` varchar(100) NOT NULL COMMENT '商品名称 快照', `product_image` varchar(255) DEFAULT NULL COMMENT '商品图片 快照', `price` decimal(10,2) NOT NULL COMMENT '商品单价 快照', `quantity` int(11) NOT NULL COMMENT '购买数量', `total_price` decimal(10,2) NOT NULL COMMENT '该商品总价', `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', PRIMARY KEY (`id`), KEY `idx_order_id` (`order_id`), KEY `idx_product_id` (`product_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='订单明细表';
购物车表 cart
购物车表存储用户临时选中的商品信息,支持未登录用户的临时购物车可以结合缓存实现,这里展示登录用户的购物车表结构。
CREATE TABLE `cart` ( `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '购物车ID', `user_id` bigint(20) unsigned NOT NULL COMMENT '用户ID', `product_id` bigint(20) unsigned NOT NULL COMMENT '商品ID', `quantity` int(11) NOT NULL DEFAULT '1' COMMENT '商品数量', `checked` tinyint(4) NOT NULL DEFAULT '1' COMMENT '是否选中 1是 0否', `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', `updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', PRIMARY KEY (`id`), UNIQUE KEY `uk_user_product` (`user_id`,`product_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户购物车表';
可维护性设计要点
字段类型选择规范
合理选择字段类型可以减少存储空间,提升查询效率,常见规范如下:
- 主键优先使用自增的
bigint类型,避免使用UUID作为主键,减少索引碎片 - 金额相关字段使用
decimal(10,2)类型,避免使用float或double导致精度丢失 - 状态、类型等固定取值范围的字段使用
tinyint类型,减少存储空间 - 字符串字段根据实际长度选择
varchar,长度不超过255,超过255的文本内容使用text类型 - 时间字段统一使用
datetime类型,避免使用时间戳,方便直接查看和查询
索引设计原则
索引是提升查询效率的关键,但是过多索引会影响写入性能,需要平衡设计:
- 主键默认创建聚簇索引,不需要额外创建
- 频繁作为查询条件的字段创建普通索引,比如用户表的手机号、邮箱,订单表的用户ID、状态
- 关联查询的关联字段创建索引,比如订单明细表的订单ID、商品ID
- 唯一约束的字段创建唯一索引,比如用户名、订单编号,保证数据唯一性
- 避免在低区分度的字段上创建索引,比如性别字段,索引效果很差
范式与反范式的平衡
完全遵循第三范式可以减少数据冗余,但是会增加关联查询的次数,电商场景中可以适当使用反范式设计:
- 订单明细表中存储商品名称、单价、图片的快照信息,避免查询订单时关联商品表,提升查询效率
- 用户表中可以冗余常用统计字段,比如订单数量、收藏数量,避免频繁聚合查询
- 商品表中可以冗余销量、评论数等统计字段,避免每次查询都关联统计表
预留扩展空间
表结构设计需要预留一定的扩展空间,避免后续业务迭代频繁修改表结构:
- 每个表都添加
created_at和updated_at字段,方便排查问题和数据同步 - 状态类字段预留足够的取值空间,避免后续新增状态需要修改字段类型
- 对于可能扩展的属性,比如商品的扩展属性,可以单独设计属性表,而不是在商品表中添加大量冗余字段
- 避免使用
SELECT *查询,明确指定需要的字段,后续新增字段不会影响现有查询逻辑
常见问题规避
设计电商表结构时需要注意规避以下常见问题:
- 不要在订单表中存储商品的所有信息,避免商品信息更新后订单数据不一致,使用快照存储即可
- 库存扣减需要结合事务和行锁,避免超卖问题,扣减库存时先锁定库存,支付成功后再实际扣减
- 订单编号不要使用自增ID,避免被遍历猜测,使用雪花算法或者时间戳加随机数的方式生成唯一编号
- 不要在核心业务表中使用外键约束,外键会影响写入性能,数据一致性通过业务逻辑保证
- 大文本字段比如商品详情,如果查询频率低,可以拆分到单独的表,避免影响主表查询效率
表结构设计不是一次性工作,需要随着业务发展不断迭代优化,初期设计不需要过度追求完美,优先满足核心业务需求,后续根据业务量和性能瓶颈逐步调整即可。