为什么不能一次从数据库中检索一条记录,根据需要对其进行处理,将其转换为 JSON,然后使用尾随/分隔逗号发出它?
如果您从一个仅包含 的文件开始[
,然后附加了所有 JSON 字符串,那么在最后一个条目上没有附加逗号,而是使用了一个结束符]
,您将拥有一个 JSON 哈希数组,并且只有一次处理一行的值。
它会慢一点(也许),但不会影响您的系统。如果您使用阻塞/分页一次检索合理数量的记录,则 DB I/O 可以非常快。
例如,下面是一些 Sequel 示例代码和将行提取为 JSON 并构建更大 JSON 结构的代码的组合:
require 'json'
require 'sequel'
DB = Sequel.sqlite # memory database
DB.create_table :items do
primary_key :id
String :name
Float :price
end
items = DB[:items] # Create a dataset
# Populate the table
items.insert(:name => 'abc', :price => rand * 100)
items.insert(:name => 'def', :price => rand * 100)
items.insert(:name => 'ghi', :price => rand * 100)
add_comma = false
puts '['
items.order(:price).each do |item|
puts ',' if add_comma
add_comma ||= true
print JSON[item]
end
puts "\n]"
哪个输出:
[
{"id":2,"name":"def","price":3.714714089426208},
{"id":3,"name":"ghi","price":27.0179624376119},
{"id":1,"name":"abc","price":52.51248221170203}
]
请注意,订单现在按“价格”。
验证很简单:
require 'json'
require 'pp'
pp JSON[<<EOT]
[
{"id":2,"name":"def","price":3.714714089426208},
{"id":3,"name":"ghi","price":27.0179624376119},
{"id":1,"name":"abc","price":52.51248221170203}
]
EOT
结果是:
[{"id"=>2, "name"=>"def", "price"=>3.714714089426208},
{"id"=>3, "name"=>"ghi", "price"=>27.0179624376119},
{"id"=>1, "name"=>"abc", "price"=>52.51248221170203}]
这将验证 JSON 并证明原始数据是可恢复的。从数据库中检索到的每一行都应该是您要构建的整个 JSON 结构的最小“小块”。
在此基础上,以下是如何读取数据库中传入的 JSON,对其进行操作,然后将其作为 JSON 文件发出:
require 'json'
require 'sequel'
DB = Sequel.sqlite # memory database
DB.create_table :items do
primary_key :id
String :json
end
items = DB[:items] # Create a dataset
# Populate the table
items.insert(:json => JSON[:name => 'abc', :price => rand * 100])
items.insert(:json => JSON[:name => 'def', :price => rand * 100])
items.insert(:json => JSON[:name => 'ghi', :price => rand * 100])
items.insert(:json => JSON[:name => 'jkl', :price => rand * 100])
items.insert(:json => JSON[:name => 'mno', :price => rand * 100])
items.insert(:json => JSON[:name => 'pqr', :price => rand * 100])
items.insert(:json => JSON[:name => 'stu', :price => rand * 100])
items.insert(:json => JSON[:name => 'vwx', :price => rand * 100])
items.insert(:json => JSON[:name => 'yz_', :price => rand * 100])
add_comma = false
puts '['
items.each do |item|
puts ',' if add_comma
add_comma ||= true
print JSON[
JSON[
item[:json]
].merge('foo' => 'bar', 'time' => Time.now.to_f)
]
end
puts "\n]"
生成:
[
{"name":"abc","price":3.268814929005337,"foo":"bar","time":1379688093.124606},
{"name":"def","price":13.871147312377719,"foo":"bar","time":1379688093.124664},
{"name":"ghi","price":52.720984131655676,"foo":"bar","time":1379688093.124702},
{"name":"jkl","price":53.21477190840114,"foo":"bar","time":1379688093.124732},
{"name":"mno","price":40.99364022416619,"foo":"bar","time":1379688093.124758},
{"name":"pqr","price":5.918738444452265,"foo":"bar","time":1379688093.124803},
{"name":"stu","price":45.09391752439902,"foo":"bar","time":1379688093.124831},
{"name":"vwx","price":63.08947792357426,"foo":"bar","time":1379688093.124862},
{"name":"yz_","price":94.04921035056373,"foo":"bar","time":1379688093.124894}
]
我添加了时间戳,以便您可以看到每一行都是单独处理的,并且让您了解处理行的速度。当然,这是一个很小的内存数据库,它没有网络 I/O 可以满足,但是通过交换机到合理的 DB 主机上的数据库的正常网络连接也应该很快。告诉 ORM 以块的形式读取 DB 可以加快处理速度,因为 DBM 将能够返回更大的块以更有效地填充数据包。您必须尝试确定所需的块大小,因为它会根据您的网络、主机和记录的大小而有所不同。
在处理企业级数据库时,您的原始设计并不好,尤其是在您的硬件资源有限的情况下。多年来,我们已经学会了如何解析 BIG 数据库,这使得 20,000 个行表显得微不足道。VM 切片如今很常见,我们将它们用于处理,因此它们通常是过去的 PC:具有小内存占用和极小的驱动器的单个 CPU。我们无法击败它们,否则它们将成为瓶颈,因此我们必须将数据分解成尽可能小的原子片段。
喋喋不休地谈论数据库设计:将 JSON 存储在数据库中是一种有问题的做法。现在的 DBM 可以输出 JSON、YAML 和 XML 表示的行,但是强制 DBM 在存储的 JSON、YAML 或 XML 字符串中搜索是处理速度的主要影响,因此除非您也有等效的查找数据,否则不惜一切代价避免它索引在单独的字段中,因此您的搜索速度尽可能快。如果数据在单独的字段中可用,那么进行良好的数据库查询、调整 DBM 或您选择的脚本语言以及发出经过处理的数据会变得容易得多。