【问题标题】:Putting JSON string as field data on MySQL将 JSON 字符串作为字段数据放在 MySQL 上
【发布时间】:2013-12-01 06:02:46
【问题描述】:

我有一个想法,我使用 PHP 的 json_encode 将多维/非多维数组转换为 JSON 字符串,并将数据存储到我的 SQL 数据库中。

例如,我有一个名为“用户”的表。表 'users' 有 3 个字段:id、name、data

使用php,我想获取用户John的数据:SELECT data FROM users WHERE name='john'

现在“数据”字段的值/文本将如下所示:{"gender":"male","birthday":"8-Jan-1991","country":"UK","city":"London"}

我将使用 PHP 的 json_decode 解码“数据”字段,然后使用我自制的 PHP 函数之一将 stdClass 对象转换为数组。然后我可以在任何我想要的地方显示 John 的信息:$user['data']['country']

这让我免于在数据库中为国家、城市、生日等创建额外字段。但它安全吗?使用这种方法在 MySQL 上存储数据有什么缺点或问题吗?

【问题讨论】:

  • 您为什么要这样做?创建这些数据库字段只需不到一分钟的时间,而您得到的只是性能损失、序列化和反序列化数据的变通办法,而且您也无法对数据执行正确的 SQL 语句。跨度>
  • 我不建议像@slhck 所说的那样这样做。你可能想看到这个问题stackoverflow.com/questions/15367696/…。这个问题的答案解释了我想说的。
  • 在事情变慢之前,您必须拥有数万条记录。这种模式是一种混合的 nosql,有时可能非常有用。

标签: php mysql sql arrays json


【解决方案1】:

尝试添加新列。 JSON 解码非常昂贵。但是,如果您的 PHP 应用程序无法承受停机时间或由于某种原因无法添加更多列,您可以执行以下操作:

  • 将伪列的数据转换为 PHP 数组并将它们序列化为字符串(请参阅 serialize)并将其存储在 MySQL CLOB 中。
  • 同上,但使用包http://pecl.php.net/package/igbinary进行序列化和反序列化。将其存储在 MySQL BLOB 字段中。

【讨论】:

    【解决方案2】:

    如果我是你,我会简单地为数据集添加新列。

    在 MySQL 字段中使用 JSON 还不错。它为我节省了很多悲伤。但它确实引入了很多开销,并限制了您可以从数据库引擎使用的功能。不断地操作 SQL 模式并不是最好的做法,但在不必要的时候解码 JSON 对象也不是最好的做法。

    如果数据架构是相当静态的,例如您的示例,您存储用户的性别、生日等,最好使用列。然后,您可以直接使用 SQL 快速轻松地操作数据...排序、过滤、创建索引以加快查找速度等。由于数据模式是相当静态的,除了几分钟您创建列的时间。最后,在应用程序的整个生命周期中,您会在机器周期中损失更多时间。

    我在 MySQL 字段中使用 JSON 的地方是数据架构非常灵活的地方。作为测试工程师,这几乎是常态。例如,在我当前的一个项目中,目标指标列表(存储在 MySQL 中)非常有规律地变化,具体取决于正在解决的问题或正在调整的性能特征。对于开发工程师来说,要求新的指标是一项常规活动,他们当然希望这一切都能整齐地显示出来并迅速做出改变。因此,我不是每天都使用 SQL 模式,而是将静态模式(测试类型、日期、产品版本等)存储为列,但将不断变化的测试结果数据存储为 JSON 对象。这意味着我仍然可以使用基于测试类型、版本、日期等的 SQL 语句查询数据,但在集成新指标时无需接触表架构。为了显示实际的测试数据,我简单地迭代结果并将 JSON 对象解码为数组并从那里开始。随着这个项目的扩展,我最终会实现 memcached 来缓存所有内容。

    这还具有将 100 多个测试指标捆绑到一个文本 blob 中的副作用,我对整个文本 blob 进行 zlib 压缩,使其约为原始大小的 10%。由于我们的行数已经达到 7 位数,因此节省了大量的数据存储空间。

    【讨论】:

      【解决方案3】:

      正确转义,你很好,但我必须补充一点,这是 XML 比 json 格式更好的地方,因为它还允许您在查询中使用 xml 中的数据

      <?xml version="1.0" encoding="UTF-8" ?>
      <user>
         <gender>male</gender>
         <birthday>8-Jan-1991</birthday>
         <country>UK</country>
         <city>London</city>
      </user> 
      

      选择

      SELECT ExtractValue(data, '//gender') AS gender FROM users WHERE name='john' AND EXTRACTVALUE(data, '//country') != 'UK';
      

      http://dev.mysql.com/doc/refman/5.1/en/xml-functions.html#function_extractvalue

      【讨论】:

        【解决方案4】:

        但它安全吗?

        只要您正确地转义输入,使用适当的库来访问数据库(或至少使用 mysql_real_escape_string),那么是的,它是安全的。或者至少,就破解数据库而言,不会比存储其他任何东西风险更大。

        使用这种方法在 MySQL 上存储数据有什么缺点或问题

        是的,这里有几个:

        • 查询“数据”列中的任何内容是不可能的,或者至少更难查询。假设您想要所有居住在伦敦的用户。您必须获取整个数据库中的所有“数据”列并在 PHP 中进行搜索。

        • 查询时也不能按“数据”列中的任何内容进行排序。它必须在 PHP 中完成。

        • 您必须注意确保存储的数据以正确的格式存储。无论如何你都应该这样做,但它确实消除了对存储“坏”数据的额外保护。

        看起来您实际上已经将 MySQL 变成了 NoSQL 数据库。尽管我对它们的经验有限,但它们能够在一定程度上对存储的文档/JSON数据中的数据进行索引+排序。作为关系数据库,MySQL 不能:它只能对定义的列进行排序 + 索引。您正在了解 MySQL 最糟糕的地方,即难以扩展,而没有利用它的任何优势,即能够运行复杂的查询。

        话虽如此,如果您确定永远不需要运行此类查询,那么如果您将内容存储为 JSON,那么以后迁移到 NoSQL 可能会更容易。

        编辑:如果您担心用空列占用空间,您可以随时添加表格。说一个用户地址表。如果您有时可能需要每个用户多个地址,这实际上是一种对未来友好的好方法。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2018-03-13
          • 2022-07-28
          • 2017-12-12
          • 2019-12-15
          • 2019-11-16
          • 2020-03-14
          • 2018-10-28
          • 2011-07-16
          相关资源
          最近更新 更多