目前我正在使用Ruby PStore
在磁盘上保存大对象(> 1GB)。不幸的是,PStore的大小似乎限制在2GB左右,这对我的应用来说还不够。
然后我开始尝试使用Postgres 9.5 + PostGIS。这将允许存储更多数据,并且还可以执行将来需要的一些空间操作。我在Yosemite的macbook pro(16GB)上使用pg-0.18.4。
令我惊讶的是(我不是数据库专家),性能损失是巨大的。举个例子:
为了提供更多信息,这是我创建表格的脚本:
CREATE TABLE public.radiation(
id integer NOT NULL,
time timestamp with time zone NOT NULL,
surface_total_shortwave double precision,
person_total_shortwave double precision,
mean_radiant_temperature double precision,
cell_id integer
) WITH ( OIDS=FALSE )
表的每一行表示某个时刻(时间)在网格(cell_id)上某个位置的某个计算值。
INSERT
是(在Ruby中):
INSERT INTO radiation (
id,
time,
surface_total_shortwave,
person_total_shortwave,
mean_radiant_temperature,
cell_id
) VALUES (
#{id},
'#{time}',
#{surface_total_shortwave},
#{person_total_shortwave},
#{mean_radiant_temperature},
#{cell_id}
)
根据此处的建议,所有键,索引,触发器等都被禁用。所有INSERT
都在一个交易中。
如果查询被更改,以便不是每个cell_id存储一行,而是存储完整数组(double precision[]
),INSERT
时间与PStore相当,但我失去了空间能力(我想)。
我的问题是。这是正常的吗?表现能否得到改善?也许存储二进制数据?
直接用libpq切换到C会有什么不同吗?
答案 0 :(得分:2)
您可能想尝试两件事:
在一个交易中执行所有INSERT
:
BEGIN;
INSERT ...;
INSERT ...;
COMMIT;
Disable synchronous commit这样做:
SET synchronous_commit TO OFF;
BEGIN;
INSERT ... ;
INSERT ... ;
COMMIT;
SET synchronous_commit TO ON;
请注意,如果在插入过程中断电,可能会导致数据丢失。
答案 1 :(得分:1)
我在编写索引应用程序时遇到了同样的问题,首先尝试使用Moneta gem,但这对我来说不起作用。 通过使用SqLite解决了这个问题,SqLite能够处理内存中的数据库。 这是一个例子,它使用的是activerecord(没有rails)。
ActiveRecord::Base.establish_connection(:adapter => "sqlite3",:database => "db/words.db")
unless ActiveRecord::Base.connection.table_exists?('words')
ActiveRecord::Schema.define do
create_table :words do |word_table|
word_table.column :word, :string
end
end
end
这里是我的模型的一个类
class Word < ActiveRecord::Base
establish_connection(:adapter => "sqlite3",:database => ":memory:")
has_many :occurances
has_many :filenames, through: :occurances
end
索引部分(写入)使用此技术在几秒钟内写入数千个单词,读取部分(对于网站)使用来自磁盘的普通访问。
不知道你正在使用哪个Ruby实现,但我设法通过使用MRI Ruby 2.3 64位(在Windows上)来解决其他问题,这可以使用更多的内存,也可以使用jRuby,你可以提供额外的记忆管理参数。
由于这类应用程序非常耗费资源,因此性能非常重要,因此最好将第一个解决方案与这些技术结合起来。
Ilya的建议也很好,批量写,可以与我的解决方案结合使用。
无论如何,重新考虑你的算法,通常没有必要通过优化来做那么多的写作。