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

数据库 MySQL
网上很多人关于 JSON 违反了数据库第一范式的争议,那么,JSON 真对违反了数据库第一范式吗?我们来聊一聊。

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

一、MySQL的JSON

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

1. MySQL 5.7 中的 JSON 支持

发布日期:MySQL 5.7 正式发布于 2015 年10月。

JSON 数据类型:在此版本中,MySQL 引入了 JSON 类型,允许开发者在表中存储和操作 JSON 格式的数据。这不仅提高了处理半结构化数据的效率,还带来了更多的灵活性。

功能特性:

  • 验证:MySQL 会自动验证存储在 JSON 列中的数据是否为有效的 JSON 格式。
  • 高效存储:JSON 数据以二进制格式存储,优化了存储空间和访问速度。
  • 内置函数:MySQL 5.7 提供了一系列与 JSON 操作相关的函数,如 JSON_EXTRACT、JSON_SET、JSON_ARRAY 等,方便对 JSON 数据进行查询和修改。
  • 索引支持:虽然初期对 JSON 索引的支持有限,但通过生成虚拟列并在这些列上创建索引,可以提高查询性能。

2. 后续版本的改进

MySQL 8.0:在随后的 MySQL 8.0 版本中,JSON 支持得到了进一步增强,包括:

  • 更丰富的 JSON 函数:新增了更多操作 JSON 数据的函数,如 JSON_TABLE 等。
  • 性能优化:提升了 JSON 数据的处理性能,特别是在大规模数据集上的表现。

更好的与 SQL 标准的兼容性。

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

CREATE TABLEusers (
    idINT AUTO_INCREMENT PRIMARY KEY,
    nameVARCHAR(100),
    attributesJSON
);

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

-- 查询 JSON 数据
SELECTname, JSON_EXTRACT(attributes, '$.city') AS city FROMusers;

二、JSON 是否违反第一范式?

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

1. 违反第一范式

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

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语句如下:

SELECT name
FROM users_conflict
WHERE JSON_CONTAINS(phone_numbers, '"123-4567"', '$');

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

2. 不违反第一范式

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

CREATE TABLE products_no_conflict (
    idINT AUTO_INCREMENT PRIMARY KEY,
    nameVARCHAR(100),
    price DECIMAL(10,2),
    attributesJSON
);

INSERTINTO 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语句如下:

SELECT name, attributes
FROM products_no_conflict
WHERE JSON_EXTRACT(attributes, '$.dimensions.width') > 30;

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

三、总结

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

  • 与 1NF 冲突:当 JSON 字段用于存储多值集合(如数组、重复组)时,会违反 1NF 的原子性要求。例如,将多个电话号码存储在一个 JSON 字段中。
  • 不与 1NF 冲突:当 JSON 字段用于存储单一的结构化对象,即使该对象内部包含多个键值对,也可以视为一个原子值,从而不违反 1NF。例如,存储产品的可选属性或配置信息。

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

责任编辑:赵宁宁 来源: 猿java
相关推荐

2025-01-03 08:42:59

数据库三范式架构

2023-10-25 14:51:38

MySQL数据库JSON

2020-06-09 08:09:07

机器学习统计学习无监督学习

2011-04-21 13:53:52

2009-03-23 10:11:59

Oracle数据库唯一约束

2021-02-25 10:16:22

比特币货币虚拟货币

2017-11-16 09:03:56

数据库MySQLJSON

2024-02-19 14:58:34

编程范式开发

2024-01-24 09:14:27

编程范式数据

2019-07-17 10:19:36

MySQL数据库SQL

2016-09-26 17:48:35

戴尔

2023-02-27 23:45:09

MySQL索引存储

2017-10-27 18:40:01

机器学习终身机器学习迁移学习

2011-05-26 13:54:04

Json

2024-08-27 10:54:20

JSON函数属性

2023-09-14 23:14:57

MySQL索引

2021-08-27 06:34:04

开源协议智能

2022-12-06 09:00:11

MySQL自增主键查询

2009-10-15 17:51:25

MySQL索引类型

2021-07-15 07:23:25

MySQL故障索引
点赞
收藏

51CTO技术栈公众号