MYSQL 中的原生 JSON 支持 5.7:MYSQL 中 JSON 数据类型的优缺点是什么?

Native JSON support in MYSQL 5.7 : what are the pros and cons of JSON data type in MYSQL?

在 MySQL 5.7 中,一种用于存储 JSON data in MySQL 表的新数据类型已经出现 添加。显然会是MySQL的一大变化。他们列出了一些好处

Document Validation - Only valid JSON documents can be stored in a JSON column, so you get automatic validation of your data.

Efficient Access - More importantly, when you store a JSON document in a JSON column, it is not stored as a plain text value. Instead, it is stored in an optimized binary format that allows for quicker access to object members and array elements.

Performance - Improve your query performance by creating indexes on values within the JSON columns. This can be achieved with “functional indexes” on virtual columns.

Convenience - The additional inline syntax for JSON columns makes it very natural to integrate Document queries within your SQL. For example (features.feature is a JSON column): SELECT feature->"$.properties.STREET" AS property_street FROM features WHERE id = 121254;

哇!它们包括一些很棒的功能。现在操作数据更容易了。现在可以在列中存储更复杂的数据。 所以 MySQL 现在加入了 NoSQL。

现在我可以想象对 JSON 数据的查询类似于

SELECT * FROM t1
WHERE JSON_EXTRACT(data,"$.series") IN 
( 
SELECT JSON_EXTRACT(data,"$.inverted") 
FROM t1 | {"series": 3, "inverted": 8} 
WHERE JSON_EXTRACT(data,"$.inverted")<4 );

那么我可以在几个 json 列中存储大量的小关系吗?好吗?它会破坏规范化吗? 如果这是可能的,那么我猜它会在 MySQL 列 中表现得像 NoSQL。我真的很想知道更多关于这个功能的信息。 MySQL JSON 数据类型的优缺点。

MySQL 5.7 brings sexy back with JSON 中的以下内容对我来说听起来不错:

Using the JSON Data Type in MySQL comes with two advantages over storing JSON strings in a text field:

Data validation. JSON documents will be automatically validated and invalid documents will produce an error. Improved internal storage format. The JSON data is converted to a format that allows quick read access to the data in a structured format. The server is able to lookup subobjects or nested values by key or index, allowing added flexibility and performance.

...

Specialised flavours of NoSQL stores (Document DBs, Key-value stores and Graph DBs) are probably better options for their specific use cases, but the addition of this datatype might allow you to reduce complexity of your technology stack. The price is coupling to MySQL (or compatible) databases. But that is a non-issue for many users.

请注意有关 文档验证 的语言,因为它是一个重要因素。我想需要进行一系列测试来比较这两种方法。这两个是:

  1. Mysql 具有 JSON 数据类型
  2. Mysql 没有

截至目前,就我所看到的 mysql / json / 性能主题而言,网络上只有浅薄的幻灯片分享。

也许您的 post 可以成为它的枢纽。或者也许性能是事后才想到的,不确定,你只是很高兴没有创建一堆表。

最近遇到了这个问题,总结了以下经验:

1、没有一种方法可以解决所有问题。 2、正确使用JSON

一个案例:

我有一个名为 table 的 CustomField,它必须有两列:namefieldsname 是一个本地化的字符串,它的内容应该是这样的:

{
  "en":"this is English name",
  "zh":"this is Chinese name"
   ...(other languages)
}

fields应该是这样的:

[
  {
    "filed1":"value",
    "filed2":"value"
    ...
  },
  {
    "filed1":"value",
    "filed2":"value"
    ...
  }
  ...
]

如您所见,namefields都可以保存为JSON,而且有效!

但是,如果我经常使用name搜索这个table,我该怎么办?使用 JSON_CONTAINS,JSON_EXTRACT...?显然,再保存为JSON不是一个好主意,我们应该将其保存为一个独立的table:CustomFieldName.

从上面的案例来看,我觉得你应该牢记这些想法:

  1. 为什么 MYSQL 支持 JSON?
  2. 为什么要使用 JSON?您的业​​务逻辑是否只需要这个?或者还有别的?
  3. 永远不要偷懒

谢谢

根据我的经验,JSON 至少在 MySql 5.7 中的实现由于性能不佳而不是很有用。 好吧,这对于读取数据和验证来说还不错。但是,JSON 修改 MySql 比 Python 或 PHP 慢 10-20 倍。 让我们想象一下非常简单 JSON:

{ "name": "value" }

假设我们必须将它转换成类似的东西:

{ "name": "value", "newName": "value" }

您可以使用 Python 或 PHP 创建简单的脚本,它将 select 所有行并一一更新。您不必为此进行一笔巨大的交易,因此其他应用程序可以并行使用 table。当然,如果你愿意,你也可以做一个巨大的事务,这样你就可以保证 MySql 会执行 "all or nothing",但其他应用程序很可能无法在事务执行期间使用数据库。

我有 4000 万行 table,Python 脚本会在 3-4 小时内更新它。

现在我们有 MySql JSON,所以我们不再需要 Python 或 PHP,我们可以这样做:

UPDATE `JsonTable` SET `JsonColumn` = JSON_SET(`JsonColumn`, "newName", JSON_EXTRACT(`JsonColumn`, "name"))

看起来简单又优秀。但其速度比Python版慢10-20倍,且为单事务,其他应用无法并行修改table数据。

因此,如果我们只想复制 4000 万行中的 JSON 键 table,我们需要在 30-40 小时内完全不使用 table。没有意义。

关于读取数据,根据我的经验,通过 JSON_EXTRACTWHERE 中直接访问 JSON 字段也非常慢(比 TEXT 和 [=16 慢得多=] 在未索引的列上)。虚拟生成的列执行得更快,但是,如果我们事先知道我们的数据结构,我们就不需要 JSON,我们可以使用传统的列来代替。当我们在真正有用的地方使用 JSON 时,我。 e.当数据结构未知或经常更改时(例如,自定义插件设置),为任何可能的新列定期创建虚拟列看起来不是个好主意。

Python 和 PHP 使 JSON 验证成为一种魅力,因此我们是否需要 MySql 方面的 JSON 验证值得怀疑。为什么不同时验证 XML、Microsoft Office 文档或检查拼写? ;)

SELECT * FROM t1
WHERE JSON_EXTRACT(data,"$.series") IN ...

像这样在表达式或函数中使用列会破坏查询使用索引帮助优化查询的任何机会。上面显示的查询被强制执行 table-scan.

关于“高效访问”的说法具有误导性。这意味着查询检查带有 JSON 文档的行后,它可以提取字段而无需解析 JSON 语法的文本。但是它仍然需要 table-scan 来搜索行。换句话说,查询必须检查每一行。

打个比方,如果我在 telephone 书中搜索名字为“Bill”的人,我仍然必须阅读 phone 书中的每一页,即使是第一页名称已突出显示,以便更快地发现它们。

MySQL 5.7允许你在table中定义一个虚拟列,然后在虚拟列上创建索引。

ALTER TABLE t1
  ADD COLUMN series AS (JSON_EXTRACT(data, '$.series')),
  ADD INDEX (series);

那么如果查询虚拟列,可以使用索引,避免table-scan.

SELECT * FROM t1
WHERE series IN ...

这很好,但有点忽略了使用 JSON 的要点。使用 JSON 的吸引人之处在于它允许您添加新属性而无需执行 ALTER TABLE。但事实证明,如果你想在索引的帮助下搜索 JSON 字段,你必须定义一个额外的(虚拟)列。

但您不必为 JSON 文档中的 每个 字段定义虚拟列和索引 — 只需为您要搜索或排序的字段定义虚拟列和索引。 JSON 中可能还有其他属性,您只需要在 select-list 中提取,如下所示:

SELECT JSON_EXTRACT(data, '$.series') AS series FROM t1
WHERE <other conditions>

我通常会说这是在 MySQL 中使用 JSON 的最佳方式。仅在 select-list.

当您在其他子句(JOIN、WHERE、GROUP BY、HAVING、ORDER BY)中引用列时,使用常规列更有效,而不是 JSON 文档中的字段。

我在 2018 年 4 月的 Percona Live 会议上发表了一个名为 How to Use JSON in MySQL Wrong 的演讲。我将在秋季的 Oracle Code One 上更新并重复这个演讲。

JSON 还有其他问题。例如,在我的测试中,与存储相同数据的传统列相比,JSON 文档需要 2-3 倍的存储空间 space。

MySQL 正在积极推广他们的新 JSON 功能,主要是为了劝阻人们不要迁移到 MongoDB。但是像 MongoDB 这样的 document-oriented 数据存储基本上是一种 non-relational 组织数据的方式。它不同于关系。我并不是说一个比另一个好,它只是一种不同的技术,适用于不同类型的查询。

当 JSON 使您的查询更有效率时,您应该选择使用 JSON。

不要因为新技术或时尚而选择技术。


编辑:如果您的 WHERE 子句使用与虚拟列定义完全相同的表达式,MySQL 中的虚拟列实现应该使用索引。即下面应该使用虚拟列上的索引,因为虚拟列定义AS (JSON_EXTRACT(data,"$.series"))

SELECT * FROM t1
WHERE JSON_EXTRACT(data,"$.series") IN ...

除了我通过测试此功能发现,如果表达式是 JSON-extraction 函数,它出于某种原因不起作用。它适用于其他类型的表达式,但不适用于 JSON 函数。更新:据报道,这最终在 MySQL 5.7.33.

中有效

强烈不同意其他答案中的某些内容(公平地说,这是几年前的事)。

我们已经非常谨慎地开始采用 JSON 带着健康的怀疑态度的领域。随着时间的推移,我们一直在添加更多内容。

这大致描述了我们所处的情况:

  • 像 99% 的应用程序一样,我们并没有大规模地做事。我们使用许多不同的应用程序和数据库,其中大多数都能够 运行 在适度的硬件上。
  • 如果性能确实成为问题,我们有适当的流程和专业知识来进行更改。
  • 我们大致了解哪些 table 会变大,并仔细考虑我们如何为它们优化查询。
  • 我们也知道在哪些情况下不需要
  • 我们非常擅长应用层的数据验证和静态类型。

最后,

当我们使用 JSON 存储复杂数据时,该数据永远不会被 other tables 直接引用。我们也往往永远不需要在热路径的 where 子句中使用它们。

因此,考虑到所有这些,使用一点 JSON 字段而不是 1 个或多个 table 可以大大降低查询和数据模型的复杂性。消除这种复杂性可以更轻松地编写某些查询,使我们的代码更简单并且通常可以节省时间。

复杂性和性能需要仔细权衡。 JSON 不应盲目应用字段,但对于这种方法有效的情况来说,这是非常棒的。

“JSON 字段表现不佳”是不使用 JSON 字段的正当理由,如果您处在性能差异很重要的地方。

一个具体的例子是我们有一个 table 存储视频转码设置的地方。设置 table 每行 1 'profile',设置本身的最大嵌套级别为 4(数组和对象)。

尽管这是一个总体上很大的数据库,但数据库中只有几百条这样的记录。建议将其分成 5 tables 不会产生任何好处和很多痛苦。

这是一个极端的例子,但我们还有很多其他例子(行数更多)使用 JSON 字段的决定是几年前的事了,现在还没有引起问题。

最后一点:现在可以直接在 JSON 个字段上建立索引。