【问题标题】:Native JSON support in MYSQL 5.7 : what are the pros and cons of JSON data type in MYSQL?MYSQL 5.7 中的原生 JSON 支持:MYSQL 中 JSON 数据类型的优缺点是什么?
【发布时间】:2016-02-13 03:40:24
【问题描述】:

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

文档验证 - 只有有效的 JSON 文档才能存储在 JSON 列,因此您可以自动验证数据。

高效访问 - 更重要的是,当您将 JSON 文档存储在 JSON 列中时,它不会存储为纯文本值。相反,它被存储 采用优化的二进制格式,可以更快地访问对象 成员和数组元素。

性能 - 改进您的查询 通过为 JSON 列中的值创建索引来提高性能。 这可以通过虚拟列上的“功能索引”来实现。

方便 - JSON 列的附加内联语法使其 将文档查询集成到 SQL 中是非常自然的。为了 示例(features.feature 是一个 JSON 列):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 数据类型的优缺点。

【问题讨论】:

  • 哦,请不要说我认为你在说什么。 Here, read this。你的想法是一个坏主意的另一个变种。
  • @Drew 你给了一个很大的答案。但这不是我的问题。我只想知道,如果我们为 json 数据编写查询,那么我们可能会跳过 sql 规则。因为我们不需要很多桌子
  • 你说Now it is possible to store more complex data in column。小心
  • Json 数据类型支持索引并且它有智能大小:64K & 4G。那么,如果我想存储 2000 个数据并添加 5 个嵌套标签而不是 5 个具有关系的表,那会有什么问题呢?
  • “我真的很想知道更多关于这个功能的信息。”和“MySQL JSON 数据类型的优缺点”。不是问题,如果改写为问题太宽泛。 “所以我从没想过 MySQL 中有复杂的模式结构和外键。我只使用几张表来存储复杂的关系。”是自相矛盾的,因为 JSON 不是关系和 FK。 “这样好吗”的解释只是对关系模型的介绍,所以这又太宽泛了。研究一些例子,列出你自己的利弊清单,并询问你哪里出错了。

标签: mysql json database database-normalization


【解决方案1】:
SELECT * FROM t1
WHERE JSON_EXTRACT(data,"$.series") IN ...

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

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

以此类推,如果我在电话簿中搜索名字为“Bill”的人,我仍然必须阅读电话簿中的每一页,即使已突出显示名字以便更快地发现他们。

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

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

那么如果你查询虚拟列,它可以使用索引,避免表扫描。

SELECT * FROM t1
WHERE series IN ...

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

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

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

我通常会说这是在 MySQL 中使用 JSON 的最佳方式。仅在选择列表中。

当您在其他子句(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 倍。

MySQL 正在积极推广其新的 JSON 功能,主要是为了劝阻人们不要迁移到 MongoDB。但是像 MongoDB 这样的面向文档的数据存储从根本上说是一种非关系的数据组织方式。它与关系不同。我并不是说一个比另一个更好,它只是一种不同的技术,适用于不同类型的查询。

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

不要仅仅因为它是新的或为了时尚而选择一种技术。


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

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

除非我通过测试此功能发现,如果表达式是 JSON 提取函数,则由于某种原因它不起作用。它适用于其他类型的表达式,但不适用于 JSON 函数。更新:据报道,这最终在 MySQL 5.7.33 中有效。

【讨论】:

  • 非常值得关注幻灯片的链接
  • 好点,这两种技术各自都很好,这意味着我们决定哪种技术适合我们的需求,以及哪种技术在安全性和性能方面给我们带来更多优势。
  • 问题的症结在于,仍然需要 ALTER TABLE 来为 JSON 中的每个新键使用生成列上的索引。很高兴看到它被指出。
  • 仅当您需要添加虚拟列和/或索引时。如果您将 JSON 数据视为“黑匣子”并且不尝试对 JSON 中的子字段进行搜索或排序的任何查询,那么您不需要这样做。这就是为什么我建议避免在 JOINWHERE 或其他子句中引用 JSON。只需获取选择列表中的 JSON 列。
  • @PaulBenn,很高兴听到这个消息!我可以理解为什么实现起来可能会非常棘手,但很遗憾他们从 MySQL 5.7 GA 开始花了六年时间才做到这一点。
【解决方案2】:

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

在 MySQL 中使用 JSON 数据类型有两个优点 在文本字段中存储 JSON 字符串:

数据验证。 JSON 文档将被自动验证并 无效的文件会产生错误。改进的内部存储 格式。 JSON 数据被转换为允许快速读取的格式 以结构化格式访问数据。服务器能够 通过键或索引查找子对象或嵌套值,允许添加 灵活性和性能。

...

NoSQL 存储的特殊风格 (文档数据库、键值存储和图形数据库)可能更好 其特定用例的选项,但添加此 数据类型可能允许您降低技术的复杂性 堆。代价是耦合到 MySQL(或兼容)数据库。但 这对许多用户来说不是问题。

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

  1. 带有 JSON 数据类型的 MySQL
  2. Mysql 没有

从我所看到的情况来看,到目前为止,网络上关于 mysql / json / 性能的主题只有浅薄的幻灯片。

也许您的帖子可以成为它的中心。或者也许性能是事后才想到的,不确定,而您只是为不创建一堆表而感到兴奋。

【讨论】:

  • 一个骗局; Mysql 内存表不支持 JSON 数据类型,例如数据类型 TEXT 和 BLOB。这意味着如果需要一个临时表,它将创建一个基于磁盘的表而不是内存。此处概述了使用临时表的一些情况:dev.mysql.com/doc/refman/5.7/en/internal-temporary-tables.html
  • @raizmedia 您能否详细说明为什么基于磁盘的表与内存(我猜是基于表)相比是个问题?
  • @lapin 可能是由于速度限制。
  • @LittleHelper 如果您使用 PCI 4x 40 Gb/s M.2 插槽并插入 40 Gb/s 支持的驱动器,则可以避免这种情况。这和内存一样快。您也可以对用于格式化内存的驱动器应用特殊格式。
  • @SergeyRomanov, [citation required]您是否对该驱动器与 RAM 进行了基准测试?
【解决方案3】:

最近接触到这个问题,总结如下经验:

1,没有办法解决所有问题。 2、你应该正确使用JSON。

一个案例:

我有一个名为: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 非常频繁地搜索此表,我该怎么办?使用JSON_CONTAINS,JSON_EXTRACT...?显然,现在保存为 JSON 已经不是什么好主意了,我们应该把它保存到一个独立的表中:CustomFieldName

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

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

谢谢

【讨论】:

【解决方案4】:

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

{ "name": "value" }

假设我们必须将其转换为类似的东西:

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

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

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

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

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

它看起来简单而出色。但是它的速度比Python版本慢10-20倍,而且是单事务,其他应用不能并行修改表数据。

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

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

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

【讨论】:

    【解决方案5】:

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

    我们已经非常谨慎地开始采用 JSON 字段,并且持怀疑态度。随着时间的推移,我们一直在添加更多内容。

    这一般描述了我们所处的情况:

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

    最后,

    当我们使用 JSON 存储复杂数据时,其他表永远不会直接引用该数据。我们也倾向于永远不需要在热路径中的 where 子句中使用它们。

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

    复杂性和性能需要仔细平衡。不应盲目应用 JSON 字段,但在这种情况下,它是很棒的。

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

    一个具体的例子是,我们有一个表格,用于存储视频转码的设置。设置表每行有 1 个“配置文件”,设置本身的最大嵌套级别为 4(数组和对象)。

    尽管这是一个整体上的大型数据库,但数据库中只有几百条这样的记录。建议将其拆分为 5 张表不会产生任何好处,而且会带来很多痛苦。

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

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

    【讨论】:

      猜你喜欢
      • 2018-08-07
      • 1970-01-01
      • 1970-01-01
      • 2016-06-18
      • 2023-04-07
      • 2011-04-03
      • 2010-10-02
      相关资源
      最近更新 更多