Ruby PStore vs Postgres

时间:2016-07-10 16:06:03

标签: ruby postgresql serialization bigdata

目前我正在使用Ruby PStore在磁盘上保存大对象(> 1GB)。不幸的是,PStore的大小似乎限制在2GB左右,这对我的应用来说还不够。

然后我开始尝试使用Postgres 9.5 + PostGIS。这将允许存储更多数据,并且还可以执行将来需要的一些空间操作。我在Yosemite的macbook pro(16GB)上使用pg-0.18.4

令我惊讶的是(我不是数据库专家),性能损失是巨大的。举个例子:

  • PStore写在磁盘上:130.428481s
  • 数据库插入:4280.366986s

为了提供更多信息,这是我创建表格的脚本:

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会有什么不同吗?

2 个答案:

答案 0 :(得分:2)

您可能想尝试两件事:

  1. 在一个交易中执行所有INSERT

    BEGIN;
    INSERT ...;
    INSERT ...;
    COMMIT;
    
  2. 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的建议也很好,批量写,可以与我的解决方案结合使用。

无论如何,重新考虑你的算法,通常没有必要通过优化来做那么多的写作。