4

我将腌制对象存储在 PostgreSQL 数据库中。最初我认为这是一个坏主意,但它们很少被访问,并且从我所学到的显然 TOAST 使得在关系数据库中存储大 blob 的性能影响最小。

当你INSERTUPDATEbytea列它很简单。只需构造 apsycopg2.Binary并将其传递给execute游标对象上的调用。就我而言,它是一个腌制的物体。

每当您执行 aSELECT并取回一bytea列时,您都会得到一个 pythonbuffer对象。换句话说,你不能只做 apickle.loads或 a pickle.load。我想出的最好的方法是使用StringIO

import psycopg2
import cPickle as pickle
import cStringIO as StringIO

conn = psycopg2.connect(user='postgres',database='postgres')

cur = conn.cursor()

cur.execute('Select %s', (psycopg2.Binary(pickle.dumps({'foo':'bar'},-1)), ))

result, = cur.fetchone()

cur.close()
conn.rollback()

result = StringIO.StringIO(result)

print pickle.load(result)

这样做的代价是什么?StringIO对象只是原始对象的浅拷贝吗buffer?有没有更实用的方法来做到这一点?

如果重要的话,我正在使用 Stackless 2.7.5。

4

2 回答 2

2

事实证明,使用 cStringIO 和 cPickle 会快很多倍,是这种情况下的最佳选择。完整的文章在这里http://www.hydrogen18.com/blog/unpickling-buffers.html

于 2013-09-01T04:15:12.237 回答
1

我认为你不需要创建StringIO对象,你可以str从你的创建result然后阅读它:

>>> pickle.loads(str(result))
{'foo': 'bar'}

不知道cStringIO,但StringIO无论如何都要这样做(取自StringIO):

def __init__(self, buf = ''):
    # Force self.buf to be a string or unicode
    if not isinstance(buf, basestring):
        buf = str(buf)

更新:测试它timeit

>>> timeit('s = pickle.loads(str(result))', 'import cPickle as pickle;from __main__ import result', number=100000)
1.2336693825245675
>>> timeit('s = pickle.load(StringIO.StringIO(result))', 'import cPickle as pickle; import cStringIO as StringIO;from __main__ import result', number=100000)
1.0089504222504786

所以你的方法比从缓冲区创建字符串快一点

于 2013-08-31T17:36:02.873 回答