将 JSON 字符串作为字段数据放在 MySQL 上
Posted
技术标签:
【中文标题】将 JSON 字符串作为字段数据放在 MySQL 上【英文标题】:Putting JSON string as field data on 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 所说的那样这样做。你可能想看到这个问题***.com/questions/15367696/…。这个问题的答案解释了我想说的。 在事情变慢之前,您必须拥有数万条记录。这种模式是一种混合的 nosql,有时可能非常有用。 【参考方案1】:尝试添加新列。 JSON 解码非常昂贵。但是,如果您的 PHP 应用程序无法承受停机时间或由于某种原因无法添加更多列,您可以执行以下操作:
将伪列的数据转换为 PHP 数组并将它们序列化为字符串(请参阅 serialize)并将其存储在 MySQLCLOB
中。
同上,但使用包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 可能会更容易。
编辑:如果您担心用空列占用空间,您可以随时添加表格。说一个用户地址表。如果您有时可能需要每个用户多个地址,这实际上是一种对未来友好的好方法。
【讨论】:
以上是关于将 JSON 字符串作为字段数据放在 MySQL 上的主要内容,如果未能解决你的问题,请参考以下文章
查询Mysql表之后将结果转换为json时如何能够保持字段的原有数据类型?
将 JSON 数据作为字符串类型的一个字段写入 BigQuery 表
PHP/MySQL - 将数组数据存储为 JSON,不好的做法?