MySQL 的JSON类型违反第一范式吗?

数据库三范式 文章中,我们分析了数据库的三范式,MySQL 在 5.7 版本中正式引入了原生的 JSON 数据类型,网上很多人关于 JSON 违反了数据库第一范式的争议,那么,JSON 真的违反了数据库第一范式吗?这篇文章,我们来聊一聊。

1. MySQL的JSON

MySQL 在 5.7 版本 中正式引入了原生的 JSON 数据类型,接下来我们来详细地介绍 JSON相关的信息。

1.1 MySQL 5.7 中的 JSON 支持

  • 发布日期 :MySQL 5.7 正式发布于 2015 年10月
  • JSON 数据类型 :在此版本中,MySQL 引入了 JSON 类型,允许开发者在表中存储和操作 JSON 格式的数据。这不仅提高了处理半结构化数据的效率,还带来了更多的灵活性。
  • 功能特性
    • 验证 :MySQL 会自动验证存储在 JSON 列中的数据是否为有效的 JSON 格式。
    • 高效存储JSON 数据以二进制格式存储,优化了存储空间和访问速度。
    • 内置函数 :MySQL 5.7 提供了一系列与 JSON 操作相关的函数,如 JSON_EXTRACTJSON_SETJSON_ARRAY 等,方便对 JSON 数据进行查询和修改。
    • 索引支持 :虽然初期对 JSON 索引的支持有限,但通过生成虚拟列并在这些列上创建索引,可以提高查询性能。

1.2 后续版本的改进

  • MySQL 8.0 :在随后的 MySQL 8.0 版本中,JSON 支持得到了进一步增强,包括:
    • 更丰富的 JSON 函数 :新增了更多操作 JSON 数据的函数,如 JSON_TABLE 等。
    • 性能优化:提升了 JSON 数据的处理性能,特别是在大规模数据集上的表现。
    • 更好的与 SQL 标准的兼容性

为了更好地理解 MySQL 的 JSON 数据类型,下面给出了一个使用 JSON 数据类型的简单示例。

sql 复制代码
CREATE TABLE users (
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(100),
    attributes JSON
);

INSERT INTO users (name, attributes) VALUES 
('Alice', '{"age": 30, "city": "New York"}'),
('Bob', '{"age": 25, "city": "Los Angeles"}');

-- 查询 JSON 数据
SELECT name, JSON_EXTRACT(attributes, '$.city') AS city FROM users;

2. JSON 是否违反第一范式?

在关系数据库设计中,第一范式(1NF)要求每个表的每个字段都包含原子性 (不可再分)的值。这意味着每个字段只能存储单一值,不能包含集合、数组或其他复杂的数据结构。MySQL 的 JSON 数据类型允许在一个字段中存储复杂的嵌套数据结构,这在某些情况下可能违反 1NF,但在其他情况下又可能不违反。下面我们将分别举例来说明。

2.1 违反第一范式

为了说明 JSON违反1NF,这里以存储多个电话号码为例。假设我们有一个 users 表,每个用户可能有多个电话号码。如果我们将所有电话号码存储在一个 JSON 字段中,就违反了 1NF 的原子性要求。

sql 复制代码
CREATE TABLE users_conflict (
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(100),
    phone_numbers JSON
);

INSERT INTO users_conflict (name, phone_numbers) VALUES 
('Alice', '["123-4567", "234-5678"]'),
('Bob', '["345-6789"]');

问题分析:

  • 非原子性phone_numbers 字段中包含了一个数组,存储了多个电话号码,违反了每个字段只能包含单一值的要求。
  • 数据冗余与一致性:查询特定电话号码或更新某个电话号码变得复杂,且难以利用关系数据库的约束(如唯一性)来保证数据的一致性。

当我们要查询所有包含电话号码 "123-4567" 的用户时,SQL语句如下:

sql 复制代码
SELECT name
FROM users_conflict
WHERE JSON_CONTAINS(phone_numbers, '"123-4567"', '$');

虽然 MySQL 提供了 JSON 函数,但这种查询复杂度高于标准的关系型查询,并且性能可能较低。

2.2 不违反第一范式

为了说明 JSON 不违反1NF,这里以存储可选的、结构化的属性为例。假设我们有一个 products 表,其中大部分产品都有固定的属性(如 idnameprice),但某些产品可能有额外的可选属性(如 dimensionsmanufacturer_details)。这些可选属性可以存储在一个 JSON 字段中,而不会违反 1NF。

sql 复制代码
CREATE TABLE products_no_conflict (
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(100),
    price DECIMAL(10,2),
    attributes JSON
);

INSERT INTO products_no_conflict (name, price, attributes) VALUES 
('Laptop', 999.99, '{"dimensions": {"width": 35, "height": 2, "depth": 25}, "manufacturer_details": {"name": "TechCorp", "warranty": "2 years"}}'),
('Smartphone', 599.99, '{"color": "black", "storage": "128GB"}'),
('Book', 19.99, NULL);

问题分析:

  • 维持原子性attributes 字段用于存储可选的、结构化的额外信息。每个 attributes 字段本身被视为一个单一的 JSON 值,符合 1NF 的原子性要求。
  • 数据灵活性:不需要为每种可能的属性创建单独的列,保持了表结构的简洁性。
  • 查询与维护:尽管某些查询可能需要使用 JSON 函数,但由于这些属性是附加的、可选的,不会影响表的主要结构和核心数据的完整性。

当我们要查询所有宽度大于 30 的产品时,SQL语句如下:

sql 复制代码
SELECT name, attributes
FROM products_no_conflict
WHERE JSON_EXTRACT(attributes, '$.dimensions.width') > 30;

虽然这种查询依赖于 JSON 函数,但由于 attributes 字段仅包含相关的附加信息,主表结构依然保持了 1NF 的原子性。

3. 总结

本文,我们分析了 MySQL 的 JSON 数据类型是否违反了数据库的第一范式(1NF),通过全文的分析,我们可以知道:JSON 是否违反 1NF 取决于具体的应用需求和数据模型设计:

  • 与 1NF 冲突 :当 JSON 字段用于存储多值集合 (如数组、重复组)时,会违反 1NF 的原子性要求。例如,将多个电话号码存储在一个 JSON 字段中。

  • 不与 1NF 冲突 :当 JSON 字段用于存储单一的结构化对象,即使该对象内部包含多个键值对,也可以视为一个原子值,从而不违反 1NF。例如,存储产品的可选属性或配置信息。

需要注意的是,虽然在某些情况下使用 JSON 字段不会直接违反 1NF,但过度依赖 JSON 可能会带来查询复杂性、性能问题和数据一致性维护的挑战。因此,在设计数据库时,应权衡使用 JSON 字段的优势与潜在的规范化冲突,确保数据模型的可靠性和可维护性。

4. 学习交流

如果你觉得文章有帮助,请帮忙转发给更多的好友,或关注公众号:猿java,持续输出硬核文章。

相关推荐
_一条咸鱼_1 分钟前
深度剖析!解锁 Android RelativeLayout 的底层原理与高级玩法
android·面试·android jetpack
卡皮巴拉爱吃小蛋糕5 分钟前
MySQL的MVCC【学习笔记】
数据库·笔记·mysql
HuaHua的世界9 分钟前
说说Vue 模板是如何编译的?
vue.js·面试
玄明Hanko13 分钟前
生产环境到底能用Docker部署MySQL吗?
后端·mysql·docker
清流君15 分钟前
【MySQL】数据库 Navicat 可视化工具与 MySQL 命令行基本操作
数据库·人工智能·笔记·mysql·ue5·数字孪生
邂逅岁月15 分钟前
MySQL表的增删改查初阶(下篇)
数据库·sql·mysql
创码小奇客17 分钟前
MongoDB 时间序列:解锁数据时光机的终极指南
java·mongodb·trae
黯_森17 分钟前
Java面向对象
java·后端
代码小侦探19 分钟前
Java中以Maven方式引入Oracle JDBC Driver依赖的详解
java·oracle·maven
不畏惧的少年19 分钟前
AQS的底层实现原理
java