方案 1:EAV 模型(最灵活但较复杂)
适合需要无限扩展自定义属性的场景
-- 产品表
CREATE TABLE products (id INT PRIMARY KEY AUTO_INCREMENT,name VARCHAR(100),price DECIMAL(10,2)
);-- 属性名表
CREATE TABLE attributes (id INT PRIMARY KEY AUTO_INCREMENT,attr_name VARCHAR(50) UNIQUE -- color/size 等
);-- 属性值表
CREATE TABLE product_attributes (product_id INT,attribute_id INT,value VARCHAR(255),PRIMARY KEY (product_id, attribute_id),FOREIGN KEY (product_id) REFERENCES products(id),FOREIGN KEY (attribute_id) REFERENCES attributes(id)
);
优点:
- 无限扩展新属性
- 属性可复用(如多个产品共用 color 属性)
- 便于统一管理属性
缺点:
- 查询复杂(需要多次 JOIN)
- 难以对特定属性建立索引
- 值只能是字符串类型
- 数据验证需在应用层实现
方案 2:JSON 字段(MySQL 5.7+ 推荐)
适合属性结构灵活变化的场景
CREATE TABLE products (id INT PRIMARY KEY AUTO_INCREMENT,name VARCHAR(100),price DECIMAL(10,2),attributes JSON NOT NULL
);-- 插入示例
INSERT INTO products
VALUES (1, 'T-Shirt', 29.99, '{"color": "red", "size": "XL", "material": "cotton"}');
查询示例:
-- 查询特定颜色
SELECT * FROM products
WHERE JSON_EXTRACT(attributes, '$.color') = 'red';-- 查询特定尺寸
SELECT * FROM products
WHERE attributes->"$.size" = 'XL';-- 创建虚拟列并建立索引(优化查询)
ALTER TABLE products
ADD COLUMN color VARCHAR(30)
GENERATED ALWAYS AS (attributes->>"$.color") VIRTUAL,
ADD INDEX (color);
优点:
- 灵活存储任意结构
- 避免多表关联
- 支持 JSON 路径查询
- 可通过虚拟列建立索引
缺点:
- 需要 MySQL 5.7+
- 数据类型验证需在应用层处理
- 复杂查询效率较低
方案 3:关联表方案(适合固定属性)
适合已知且有限的常用属性
-- 产品表
CREATE TABLE products (id INT PRIMARY KEY AUTO_INCREMENT,name VARCHAR(100),price DECIMAL(10,2)
);-- 颜色表
CREATE TABLE product_colors (product_id INT PRIMARY KEY,color VARCHAR(50),FOREIGN KEY (product_id) REFERENCES products(id)
);-- 尺寸表
CREATE TABLE product_sizes (product_id INT PRIMARY KEY,size VARCHAR(20),FOREIGN KEY (product_id) REFERENCES products(id)
);
优点:
- 数据结构化
- 查询效率高
- 可单独建立索引
- 支持强类型约束
缺点:
- 新增属性需要修改表结构
- 扩展性较差
推荐选择建议:
-
优先推荐 JSON 方案(如果使用 MySQL 5.7+)
- 现代应用常用方案
- 平衡了灵活性和查询效率
- 结合虚拟列索引可解决性能问题
-
次选 EAV 模型(需要支持旧版本 MySQL)
- 注意要控制属性数量
- 建议配合缓存使用
-
固定属性方案(当属性非常稳定时)
- 适合明确知道需要 color/size 等固定属性的场景
实际案例参考(JSON 方案):
-- 创建带索引的优化表
CREATE TABLE optimized_products (id INT PRIMARY KEY AUTO_INCREMENT,name VARCHAR(100),price DECIMAL(10,2),attributes JSON NOT NULL,-- 生成列color VARCHAR(30) GENERATED ALWAYS AS (attributes->>"$.color") VIRTUAL,size VARCHAR(10) GENERATED ALWAYS AS (attributes->>"$.size") VIRTUAL,-- 建立索引INDEX (color),INDEX (size)
);-- 查询示例(可以直接使用虚拟列)
SELECT * FROM optimized_products
WHERE color = 'blue' AND size = 'M';
注意事项:
- 在应用层验证数据格式(如确保 size 只能是预设值)
- 对高频查询的字段创建虚拟列+索引
- JSON 文档大小不要超过 1MB
- 使用
JSON_VALID()
约束保证数据有效性:
ALTER TABLE products
ADD CONSTRAINT validate_attributes
CHECK (JSON_VALID(attributes));