EAV or JSON
MongoDB 之类的 NoSQL 之所以流行,很大程度上取决于相对自由的 schema 设计,不管数据量多大,可以随时在线上环境添加新字段来保存新数据,而这种能力恰恰是传统的关系数据库所欠缺的,不过别担心,传统关系数据库有自己的应对之道。我们今天就讨论一下其中最具代表性的两种方法,看看孰优孰劣。
在讨论前,我们不妨虚拟一个业务场景:假设我们要做一个类似汽车之家的产品库,首当其冲的是如何保存汽车的各种属性,比如说:长度、宽度、高度、GPS 导航系统、倒车影像、上坡辅助、陡坡缓降等等,最传统的方法是每一个属性都用一个独立的字段来保存,不过这样有问题:汽车属性有可能非常多,如此一来我们的表需要创建几十甚至上百个字段,而且以后还可能想要不断的添加新字段。最要命的是不同的汽车拥有的属性大不相同,比如有的汽车有 GPS 导航系统、倒车影像,但是却没有上坡辅助、陡坡缓降,如果把这些属性统统作为字段存在的话,那么表就是稀疏的,存在很多空值。
传统的 EAV 方法
所谓 EAV,实际上是 Entity–Attribute–Value 的缩写。它的核心思想是把原本按列保存的数据转换成按行保存。不同的项目设计在表结构上可能会有些许差异,不过核心通常就是 entity,attribute,value 三张表,下面看看采用 EAV 如何解决问题:
CREATE TABLE eav_entities (
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
entity_name VARCHAR(100) NOT NULL,
PRIMARY KEY(id)
);
INSERT INTO `eav_entities`
(`id`, `entity_name`)
VALUES
(1,'普拉多 3.5L TX-L'),
(2,'帕杰罗 3.0L 豪华版');
CREATE TABLE eav_attributes (
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
attribute_name VARCHAR(100) NOT NULL,
PRIMARY KEY(id)
);
INSERT INTO `eav_attributes`
(`id`, `attribute_name`)
VALUES
(1,'长度'),
(2,'宽度'),
(3,'高度'),
(4,'GPS 导航系统'),
(5,'倒车影像'),
(6,'上坡辅助'),
(7,'陡坡缓降');
CREATE TABLE eav_values (
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
entity_id INT UNSIGNED NOT NULL,
attribute_id INT UNSIGNED NOT NULL,
attribute_value VARCHAR(100) NOT NULL,
PRIMARY KEY(id)
);
INSERT INTO `eav_values`
(`id`, `entity_id`, `attribute_id`, `attribute_value`)
VALUES
(1,1,1,'4780'),
(2,1,2,'1885'),
(3,1,3,'1890'),
(4,1,6,'有'),
(5,1,7,'有'),
(6,2,1,'4900'),
(7,2,2,'1875'),
(8,2,3,'1900'),
(9,2,4,'有'),
(10,2,5,'有');
在 EAV 模型中查询巨麻烦,主要特征就是不停的 JOIN 连表:
EAV
随便说一句,前些天途牛介绍的运维系统就是利用 EAV 设计的。
新锐的 JSON 方法
现在的关系数据库已不在是单纯的关系数据库了,很多时候视情况可以打破范式的束缚,主流的 MySQL 和 PostgreSQL 都已经支持 JSON 数据类型,以 MySQL 为例:
CREATE TABLE entities (
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
name VARCHAR(100) NOT NULL,
data JSON NOT NULL,
PRIMARY KEY(id)
);
INSERT INTO `entities`
(`id`, `name`, `data`)
VALUES
(1,'普拉多 3.5L TX-L','{
"Length": 4780,
"Width": 1885,
"Height": 1890,
"HAC": "有",
"HDC": "有"
}'),
(2,'帕杰罗 3.0L 豪华版','{
"Length": 4900,
"Width": 1875,
"Height": 1900,
"GPS": "有",
"ReverseImage": "有"
}');
和 EAV 的相比,少了 JOIN 的累赘,简单的想哭:
JSON
如果你使用的关系数据库不支持 JSON 数据类型,那么你可能倾向于使用 EAV 来保存动态数据,但是只要条件允许,还是尽可能使用 JSON 为妙,不过 JSON 虽好,却万万不可滥用,如果我们不加区分的把大部分数据都放到一个 JSON 字段里去,那还不如直接用 MongoDB 算了,更详细的说明大家可以参考 2ndquadrant 中的介绍。当然对付动态数据,不止有 EAV 和 JSON,比如 FriendFeed 看似奇葩的做法,就不多说了。
相关文章
- 直接在代码里面对list集合进行分页
- .NET Framework 4.5新特性详解
- 大数据的简要介绍
- 大数据的由来
- 高斯混合模型的自然梯度变量推理
- timing-wheel 仿Kafka实现的时间轮算法
- 使用Navicat软件连接自建数据库(Linux系统)
- 那一天,我被Redis主从架构支配的恐惧
- Redis 深入了解键的过期时间
- C#使用委托调用实现用户端等待闪屏
- 基于流计算 Oceanus 和 Elasticsearch Service 构建百亿级实时监控系统
- GRAND | 转录调控网络预测数据库
- JFreeChart API中文文档
- 临床相关突变查询数据库
- TIGER | 人类胰岛基因变化查询数据库
- 视频边缘计算网关EasyNVR在视频整体监控解决方案中的应用分析
- Apache Arrow - 大数据在数据湖后的下一个风向标
- 常见的电商数据指标体系
- AKShare-艺人数据-艺人流量价值
- MySQL中多表联合查询与子查询的这些区别,你可能不知道!