我将pickled对象存储在PostgreSQL数据库中。最初我认为这是一个坏主意,但它们很少被访问,而且我从中学到的东西很明显TOAST使得性能影响最小化,无法在关系数据库中存储大blob。
当您INSERT
或UPDATE
列bytea
时,这很简单。只需构造一个psycopg2.Binary
并将其传递给游标对象上的execute
调用。就我而言,它是一个腌制对象。
每当您执行SELECT
并返回bytea
列时,您最终会得到一个python buffer
对象。换句话说,您不能只执行pickle.loads
或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。
答案 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
所以你的方法比从缓冲区
创建字符串要快一些