商品基础字段必选id(BIGINT UNSIGNED AUTO_INCREMENT)、title(VARCHAR(255))、price(DECIMAL(10,2));分类与规格需通过中间表关联;描述宜单独建表并提取标签;须用软删除和DATETIME控制时区。

商品基础字段怎么选:id、title、price 这些不能少
商品表最核心的是能唯一标识、描述清楚、支持交易。必须有 id(主键,建议用 BIGINT UNSIGNED AUTO_INCREMENT,避免未来商品量超 21 亿),title(VARCHAR(255) 足够,别用 TEXT,影响排序和索引效率),price 一定用 DECIMAL(10,2),不是 FLOAT 或 DOUBLE——浮点数存金额会导致 0.1 + 0.2 != 0.3 这类精度问题,支付对账会出事。
其他常见但非强制的字段:cover_image(VARCHAR(512) 存图 URL)、status(TINYINT,比如 0=下架、1=上架、2=售罄)、created_at/updated_at(DATETIME 或 TIMESTAMP)。
分类和规格怎么关联:别直接在商品表里加 category_id
一个商品可能属于多个分类(比如“iPhone 15”既在“手机”类目,也在“苹果专区”),硬塞一个 category_id 字段会限制扩展。正确做法是拆出中间表:
CREATE TABLE product_category ( product_id BIGINT UNSIGNED NOT NULL, category_id INT UNSIGNED NOT NULL, PRIMARY KEY (product_id, category_id), KEY idx_category_id (category_id) );
同理,规格(如颜色、内存)也别堆在商品表里加 color、memory 字段。应该建 product_spec 表存键值对,再用 product_sku 表管理具体库存单元(SKU),每个 SKU 有独立 price、stock、sku_code。
常见错误:把所有属性当字段加进 products 表,结果加到第 20 个属性时,ALTER TABLE 锁表 5 分钟,线上下单卡住。
描述富文本存在哪:别用 TEXT 字段直接存 HTML
description 字段用 LONGTEXT 可以存,但要注意两点:
- MySQL 对
LONGTEXT的单次读写性能比普通字段低,大文本会拖慢SELECT *; - 如果前端需要搜索描述内容(比如“含蓝牙耳机”),
LIKE '%蓝牙%'效率极差,且无法利用索引。
更稳妥的做法是:描述内容单独建表(如 product_detail),用 product_id 关联,并给常用关键词抽成标签存到 product_tag 表,查的时候走标签索引,而不是扫全文。
为什么不能忽略软删除和时间精度
电商中商品经常“下架”而非真删,所以别用 DELETE FROM products WHERE id = ?。加个 is_deleted TINYINT DEFAULT 0,查询时默认加 AND is_deleted = 0。否则恢复误删商品只能靠备份,恢复慢还容易丢数据。
时间字段也容易踩坑:DATETIME 默认不带时区,TIMESTAMP 会自动转为 UTC 存储、查时转回系统时区。如果你的服务器时区是 UTC,但运营后台在东八区看时间,TIMESTAMP 会显示错 8 小时。统一用 DATETIME + 应用层控制时区更可控。
真正麻烦的不是建表,是字段语义一旦定死就很难改——比如一开始用 INT 存价格,后面要支持分币种、小数点后三位,全量改字段类型+迁移数据,就得停服务。










