将数据存储在MySQL中作为JSON

时间:2010-08-25 08:18:59

标签: mysql json database

我认为这是件好事。所以,我从来没有这样做过。然后我看到FriendFeed做到了这一点并且实际上使他们的DB规模更好并且减少了延迟。我很好奇我是否应该这样做。如果是这样,那么正确的方法是什么?

基本上,学习如何将所有内容作为CouchDB数据库存储在MySQL中的好地方是什么?将所有内容存储为JSON似乎更容易,更快(不构建,减少延迟)。

此外,编辑,删除等在DB上存储为JSON的内容是否容易?

16 个答案:

答案 0 :(得分:89)

每个人评论似乎都是从错误的角度来看这个问题,可以通过PHP在关系数据库中存储JSON代码,实际上加载和显示这样的复杂数据会更快,但是你会有设计搜索,索引等等的考虑因素。

这样做的最好方法是使用混合数据,例如,如果您需要根据日期时间进行搜索,MySQL(性能调整)将比PHP快得多,并且搜索距离的位置MySQL也应该要快得多(注意搜索不能访问)。您不需要搜索的数据可以以JSON,BLOB或您认为必要的任何其他格式存储。

您需要访问的数据非常容易存储为JSON,例如基本的每个案例的发票系统。如果你有正确的HTML表单结构,它们根本不会从RDBMS中受益很多,只能通过json_encoding($ _ POST ['entires'])存储在JSON中。

我很高兴你使用MongoDB很开心,我希望它能继续为你服务,但不要认为MySQL总是会让你失望,因为你的应用程序复杂性增加,你可能最终需要用于某些功能和特性的RDBMS(即使它仅用于停止存档数据或业务报告)

答案 1 :(得分:58)

MySQL 5.7现在支持类似于MongoDB和其他无模式文档数据存储的本机JSON数据类型:

  

JSON支持

     

从MySQL 5.7.8开始,MySQL支持本机JSON类型。 JSON值不存储为字符串,而是使用允许对文档元素进行快速读取访问的内部二进制格式。存储在JSON列中的JSON文档会在插入或更新时自动验证,并且无效文档会产生错误。 JSON文档在创建时进行了规范化,可以使用大多数比较运算符进行比较,例如=,<,< =,>,> =,<>,!=和< =&gt ;;有关受支持的运算符以及MySQL在比较JSON值时遵循的优先级和其他规则的信息,请参阅JSON值的比较和排序。

     

MySQL 5.7.8还引入了许多用于处理JSON值的函数。这些功能包括这里列出的功能:

     
      
  1. 创建JSON值的函数:JSON_ARRAY(),JSON_MERGE()和JSON_OBJECT()。请参见第12.16.2节“创建JSON值的函数”。
  2.   
  3. 搜索JSON值的函数:JSON_CONTAINS(),JSON_CONTAINS_PATH(),JSON_EXTRACT(),JSON_KEYS()和JSON_SEARCH()。请参见第12.16.3节“搜索JSON值的函数”。
  4.   
  5. 修改JSON值的函数:JSON_APPEND(),JSON_ARRAY_APPEND(),JSON_ARRAY_INSERT(),JSON_INSERT(),JSON_QUOTE(),JSON_REMOVE(),JSON_REPLACE(),JSON_SET()和JSON_UNQUOTE()。请参见第12.16.4节“修改JSON值的函数”。
  6.   
  7. 提供有关JSON值的信息的函数:JSON_DEPTH(),JSON_LENGTH(),JSON_TYPE()和JSON_VALID()。请参见第12.16.5节“返回JSON值属性的函数”。
  8.         

    在MySQL 5.7.9及更高版本中,您可以使用column->路径作为JSON_EXTRACT(列,路径)的简写。这可以作为列的别名,只要在SQL语句中可以出现列标识符,包括WHERE,ORDER BY和GROUP BY子句。这包括SELECT,UPDATE,DELETE,CREATE TABLE和其他SQL语句。左侧必须是JSON列标识符(而不是别名)。右侧是引用的JSON路径表达式,它根据作为列值返回的JSON文档进行评估。

         

    有关 - >的更多信息,请参见第12.16.3节“搜索JSON值的函数”。和JSON_EXTRACT()。有关MySQL 5.7中的JSON路径支持的信息,请参阅搜索和修改JSON值。另请参见二级索引和虚拟生成列。

更多信息:

https://dev.mysql.com/doc/refman/5.7/en/json.html

答案 2 :(得分:54)

CouchDB和MySQL是两种非常不同的野兽。 JSON是在CouchDB中存储东西的本地方式。在MySQL中,您可以做的最好的事情是将JSON数据作为文本存储在单个字段中。这完全违背了将其存储在RDBMS中的目的,并且会使每个数据库事务复杂化。

<强>不

话虽如此,FriendFeed似乎在MySQL上使用extremely custom schema。这实际上取决于你想要存储什么,关于如何滥用数据库系统几乎没有一个明确的答案,所以它对你有意义。鉴于文章非常陈旧,他们反对Mongo和Couch的主要原因是不成熟,如果MySQL没有为你削减它,我会重新评估这两个。他们现在应该已经成长了很多。

答案 3 :(得分:24)

json字符在存储,诸如

等字符时并不特别

{}[]'a-z0-9 ....真的没什么特别的,可以存储为文本。

你要遇到的第一个问题就是这个

{     profile_id:22,     用户名:'Robert',     密码:'skhgeeht893htgn34ythg9er' }

存储在数据库中的

并不是那么简单,除非你有自己的进行并为mysql开发了一个jsondecode

UPDATE users SET JSON(user_data,'username') = 'New User';

因此,当你无法做到这一点时,你必须首先选择json,解码它,更改它,更新它,所以理论上你也可以花更多的时间构建一个合适的数据库结构!

我确实使用json存储数据,但只使用Meta Data,不经常更新的数据,与用户特定的相关...例如,如果用户添加帖子,并且在该帖子中他添加了图像,解析图像和创建大拇指,然后以json格式使用拇指网址。

答案 4 :(得分:14)

为了说明使用查询获取JSON数据有多困难,我将分享我为处理此问题而进行的查询。

它不考虑数组或其他对象,只考虑基本数据类型。您应该将的4个实例更改为存储JSON的列名,并将 myfield 的4个实例更改为您要访问的JSON字段。

SELECT
    SUBSTRING(
        REPLACE(REPLACE(REPLACE(column, '{', ''), '}', ','), '"', ''),
        LOCATE(
            CONCAT('myfield', ':'),
            REPLACE(REPLACE(REPLACE(column, '{', ''), '}', ','), '"', '')
        ) + CHAR_LENGTH(CONCAT('myfield', ':')),
        LOCATE(
            ',',
            SUBSTRING(
                REPLACE(REPLACE(REPLACE(column, '{', ''), '}', ','), '"', ''),
                LOCATE(
                    CONCAT('myfield', ':'),
                    REPLACE(REPLACE(REPLACE(column, '{', ''), '}', ','), '"', '')
                ) + CHAR_LENGTH(CONCAT('myfield', ':'))
            )
        ) - 1
    )
    AS myfield
FROM mytable WHERE id = '3435'

答案 5 :(得分:9)

这实际上取决于您的使用案例。如果您存储的信息在报告中绝对没有价值,并且不会通过JOIN与其他表进行查询,那么将数据存储在单个文本字段中可能是有意义的,编码为JSON。

这可以大大简化您的数据模型。但是,正如RobertPitt所提到的,不要期望能够将这些数据与已经规范化的其他数据结合起来。

答案 6 :(得分:9)

这是一个老问题,但我仍然可以在谷歌搜索结果的顶部看到这一点,所以我想在提出问题4年后添加一个新答案是有意义的。

首先,在RDBMS中存储JSON有更好的支持。您可以考虑切换到PostgreSQL(尽管MySQL自v5.7.7起支持JSON)。 PostgreSQL使用与MySQL非常相似的SQL命令,除了它们支持更多功能。他们添加的一个功能是它们提供JSON数据类型,您现在可以查询存储的JSON。 (Some reference on this)如果您没有直接在程序中编写查询,例如,在php中使用PDO或在Laravel中使用eloquent,您只需要在服务器上安装PostgreSQL并更改数据库连接设置。您甚至不需要更改代码。

大多数情况下,正如其他答案所建议的那样,将数据直接存储在RDBMS中并不是一个好主意。但有一些例外。我能想到的一种情况是具有可变数量的链接条目的字段。

例如,为了存储博客文章的标签,通常需要有一个博客文章表,一个标签表和一个匹配表。因此,当用户想要编辑帖子并且您需要显示哪个标签与该帖子相关时,您将需要查询3个表格。如果匹配的表/标签表很长,这将大大损害性能。

通过将标记作为JSON存储在博客帖子表中,相同的操作只需要单个表搜索。然后,用户将能够更快地看到要编辑的博客帖子,但如果您要报告哪些帖子链接到标签,或者可能按标签搜索,则会损害性能。

您也可以尝试对数据库进行反规范化。通过复制数据并以两种方式存储数据,您可以获得两种方法的好处。您只需要更多的时间来存储数据和更多的存储空间(与更高的计算能力相比,这是便宜的)

答案 7 :(得分:8)

我想说的唯一两个理由是:

  • 使用规范化方法表现不够好
  • 您无法轻易建模特别流畅/灵活/不断变化的数据

我在这里写了一些关于我自己的方法:

What scalability problems have you encountered using a NoSQL data store?

(见最佳答案)

即使是JSON也不够快,所以我们使用了自定义文本格式的方法。工作/继续为我们工作。

你有没有理由不使用像MongoDB这样的东西? (可能是MySQL是“必需的”;只是好奇)

答案 8 :(得分:6)

在我看来,每个回答这个问题的人都错过了一个关键问题,除了@deceze - 使用正确的工具。您可以强制关系数据库存储几乎任何类型的数据,您可以强制Mongo处理关系数据,但代价是什么?从架构设计到应用程序代码,您最终会在各个级别的开发和维护中引入复杂性;更不用说性能打击了。

2014年,我们可以访问许多数据库服务器,这些服务器可以非常好地处理特定类型的数据。

  • Mongo(文件存储)
  • Redis(键值数据存储)
  • MySQL / Maria / PostgreSQL / Oracle / etc(关系数据)
  • CouchDB(JSON)

我确定我错过了其他一些人,比如RabbirMQ和Cassandra。我的观点是,使用正确的工具来存储您需要的数据。

如果您的应用程序需要真正,非常快速地存储和检索各种数据,并且(并且不会)不愿意为应用程序使用多个数据源。最流行的Web框架提供对多个数据源(Rails,Django,Grails,Cake,Zend等)的支持。此策略将复杂性限制为应用程序的一个特定区域,ORM或应用程序的数据源接口。

答案 9 :(得分:5)

这是一个保存/更新列中JSON数组键的函数,以及另一个检索JSON值的函数。假设存储JSON数组的列名是 json ,就会创建此函数。它使用 PDO

保存/更新功能

function save($uid, $key, $val){
 global $dbh; // The PDO object
 $sql = $dbh->prepare("SELECT `json` FROM users WHERE `id`=?");
 $sql->execute(array($uid));
 $data      = $sql->fetch();
 $arr       = json_decode($data['json'],true);
 $arr[$key] = $val; // Update the value
 $sql=$dbh->prepare("UPDATE `users` SET `json`=? WHERE `id`=?");
 $sql->execute(array(
   json_encode($arr), 
   $uid
 ));
}

其中 $ uid 是用户的ID, $ key - 要更新的JSON密钥,其值为 $ val 。< / p>

获取价值功能

function get($uid, $key){
 global $dbh;
 $sql = $dbh->prepare("SELECT `json` FROM `users` WHERE `id`=?");
 $sql->execute(array($uid));
 $data = $sql->fetch();
 $arr  = json_decode($data['json'], true);
 return $arr[$key];
}

其中 $ key JSON 数组的键,我们需要该值。

答案 10 :(得分:2)

我认为将JSON存储在mysql数据库中确实无法实现使用RDBMS的目的。我不会在任何可能在某些时候操作或报告的数据中使用它,因为它不仅会增加复杂性,而且还会根据其使用方式轻松影响性能。

但是,如果有人想到可能的理由,我很好奇。我正在考虑为记录目的做一个例外。在我的情况下,我想记录具有可变数量的参数和错误的请求。在这种情况下,我想使用表作为请求类型,并且请求本身使用获得的不同值的JSON字符串。

在上述情况下,会记录请求,并且永远不会在JSON字符串字段中操作或编入索引。但是,在更复杂的环境中,我可能会尝试使用对此类数据有更多意图的东西,并将其存储在该系统中。正如其他人所说,这实际上取决于你想要达到的目标,但遵循标准总是有助于长寿和可靠性!

答案 11 :(得分:2)

早期支持在MySQL中存储JSON已添加到MySQL 5.7.7 JSON labs releaselinux binariessource)!该版本似乎已从一系列与JSON相关的用户定义函数发展为公共back in 2013

这个新生的本机JSON支持似乎朝着一个非常积极的方向前进,包括对INSERT的JSON验证,这是一种优化的二进制存储格式,包括前导中的查找表,允许JSN_EXTRACT函数执行二进制查找而不是每次解析访问。还有一大堆新函数用于处理和查询特定的JSON数据类型:

CREATE TABLE users (id INT, preferences JSON);

INSERT INTO users VALUES (1, JSN_OBJECT('showSideBar', true, 'fontSize', 12));

SELECT JSN_EXTRACT(preferences, '$.showSideBar') from users;

+--------------------------------------------------+
| id   | JSN_EXTRACT(preferences, '$.showSideBar') |
+--------------------------------------------------+
| 1    | true                                      |
+--------------------------------------------------+
恕我直言,以上是这个新功能的一个很好的用例;许多SQL数据库已经有了一个用户表,而不是进行无休止的架构更改以适应不断变化的用户首选项集,只需一个JSON列就可以完成单个JOIN。特别是因为不太可能需要查询单个物品。

虽然现在还处于早期阶段,但MySQL服务器团队在沟通变更方面做得很好on the blog

答案 12 :(得分:2)

JSON也是PostgreSQL数据库中的有效数据类型。但是,MySQL数据库尚未正式支持JSON。但它正在烘焙:http://mysqlserverteam.com/json-labs-release-native-json-data-type-and-binary-format/

我也同意有许多有效的案例,一些数据最好被序列化为数据库中的字符串。主要原因可能是它没有定期查询,并且当它自己的架构可能会发生变化时 - 您不希望更改与之对应的数据库架构。第二个原因是当序列化字符串直接来自外部源时,您可能不想解析所有这些字符串并以任何代价输入数据库,直到您使用任何字符串。所以我将等待新的MySQL版本支持JSON,因为它可以更容易在不同的数据库之间切换。

答案 13 :(得分:1)

我使用json记录项目的任何内容,实际上我使用了三个表!一个用于json中的数据,一个用于json结构的每个元数据的索引(每个元数据由唯一的id编码),一个用于会话用户,这就是全部。 在这个早期的代码状态下,基准测试无法量化,但例如,我是用户视图(带索引的内部联接)来获取类别(或任何东西,作为用户,......),并且它非常慢(非常非常慢) ,在mysql中使用的视图不是好方法)。 在这个结构中,搜索模块可以做任何我想做的事情,但是,我认为mongodb在这个完整的json数据记录概念中会更有效率。 对于我的例子,我用户视图来创建类别树,以及面包屑,我的天啊!这么多查询要做!阿帕奇自己走了!而且,事实上,对于这个小网站,我使用知道生成树和面包屑的php,数据的提取是由搜索模块(谁只使用索引)完成的,数据表仅用于更新。 如果我想,我可以销毁所有索引,并使用每个数据重新生成它,并执行相反的工作,例如,销毁所有数据(json)并仅使用索引表重新生成它。 我的项目很年轻,在php和mysql下运行,但是,有时我使用节点js和mongodb对这个项目更有效。

如果您认为自己可以这样做,请使用json,因为您可以这样做!并且,如果它是一个错误,请忘记它;尝试做出好的或坏的选择,但尝试!

法国用户

答案 14 :(得分:1)

我知道这已经很晚了,但我确实遇到了类似的情况,我使用混合方法维护RDBMS标准,将表规范化到一个点,然后将数据作为文本值存储在JSON之外。因此,例如,我按照RDBMS规范化规则将数据存储在4个表中。但是,在容纳动态模式的第4个表中,我以JSON格式存储数据。每次我想检索数据时,我都会检索JSON数据,解析它并用Java显示。到目前为止,这对我有用,并确保我仍然能够使用ETL将我转换为表中json数据的字段索引为规范化方式。这确保了当用户正在处理应用程序时,他面临最小的延迟,并且字段被转换为RDBMS友好格式以进行数据分析等。我看到这种方法运行良好并且相信给定MYSQL(5.7+)也允许解析JSON这种方法为您提供了RDBMS和NOSQL数据库的好处。

答案 15 :(得分:0)

您可以使用此要点:https://gist.github.com/AminaG/33d90cb99c26298c48f670b8ffac39c3

将它安装到服务器后(只需root权限而不是super),你可以这样做:

select extract_json_value('{"a":["a","2"]}','(/a)')

它会回来 a 2 你可以使用这个来返回JSON中的任何内容 好的部分是它支持MySQL 5.1,5.2,5.6。而且您不需要在服务器上安装任何二进制文件。

基于旧项目common-schema,但它今天仍然有效 https://code.google.com/archive/p/common-schema/