从Psycopg2中取消选择bytea列

时间:2013-08-31 17:03:50

标签: python postgresql pickle psycopg2

我将pickled对象存储在PostgreSQL数据库中。最初我认为这是一个坏主意,但它们很少被访问,而且我从中学到的东西很明显TOAST使得性能影响最小化,无法在关系数据库中存储大blob。

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

每当您执行SELECT并返回bytea列时,您最终会得到一个python buffer对象。换句话说,您不能只执行pickle.loadspickle.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。

2 个答案:

答案 0 :(得分:2)

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

答案 1 :(得分: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

所以你的方法比从缓冲区

创建字符串要快一些