2011-08-19 53 views
7

我翻阅了几篇关于如何腌制python对象并将其存储到数据库中的问题。我收集的信息是:如何将python字典腌成MySQL?

  • import pickleimport cpickle。如果性能是一个问题,则导入后者。
  • 假设dict是一个python字典(或者python对象):pickled = pickle.dumps(dict)
  • pickled存储到MySQL BLOB列中,使用与数据库进行通信的模块。
  • 再次出来。并使用pickle.loads(pickled)来恢复python字典。

我只是想确保我明白这个权利。我错过了关键的事情吗?有副作用吗?这真的很简单吗?

背景信息:我想要做的唯一事情就是存储Googlegeocoder-Responses,它是嵌套的python字典在我的情况。我只使用响应对象的一小部分,我不知道以后我是否会需要更多。这就是为什么我想存储响应以节省我重复数百万个查询的原因。

+2

+1只有Python会使用'pickle'作为关键字... #lulz。 –

+0

我将对象序列化为JSON,而不是pickle,因为这是人类可读的,并且更容易在其他编程语言中读取。性能差异并不大。 –

回答

2

这真的很容易...只要你不需要你的数据库知道什么关于字典。如果你需要任何形式的结构化数据访问字典的内容,那么你将不得不更多地参与。

另一个问题可能是你打算在字典中放置什么。 Python的pickle序列化非常聪明,可以处理大多数情况,而无需添加任何定制支持。但是,当它不起作用时,可能很难理解出了什么问题。所以如果可以的话,将dict的内容限制在Python的内置类型中。如果您开始添加自定义类的实例,请将它们保留为简单的自定义类,这些类不会使用任何有趣的属性存储或访问。并且要小心从插件中添加类或类型的实例。一般来说,如果您开始在酸洗或拆卸时遇到难以理解的问题,请查看字典中的非内置类型。

+0

我只有一些嵌套的列表/字典需要照顾,并且数据库不必知道任何有关这些对象的信息。所以我认为在这种情况下我会好起来的。感谢您的回答! – Aufwind

+0

关注可能的疑难杂症,请问这个问题,可以腌制什么样的限制? –

+1

@TomKimber公平点,编辑。 –

1

如果速度是非常重要的,我只是跑从MySQL表从泡菜装载大蟒蛇词典(35MB)VS选择与存储在行中的所有键和值的测试:

味酸方法:

import time, pickle 
t1 = time.clock() 
f = open('story_data.pickle','rb') 
s = pickle.load(f) 
print time.clock() - t1 

MySQL的方法:

import database as db 
t1 = time.clock() 
data,msg = db.mysql(""" SELECT id,story from story_data;""") 
data_dict = dict([(int(x),y.split(',')) for x,y in data]) 
print time.clock() - t1 

输出: 泡菜方法:32.0785171704 MySQL的方法:3.25 916336479

如果十倍速度增强就足够了,数据库的结构可能并不重要。注意我将所有逗号分隔的数据拆分为36,000个键的值,并且只需要3秒。所以我已经不再使用大量数据集的酱菜了,因为我使用的400行程序的其余部分花费了大约3秒,而咸菜加载花费了32秒。

还要注意:

cPickle的作品就像泡菜和超过50%的速度。

不要试图腌一个充满字典的类并保存在mysql中:它不能正确重构自己,至少它不适合我。

+1

注 - 通过剥离每个列表中每个字符串的引号,我将数据大小从35MB缩小到24MB,这可能也会加快MYSQL方法的速度。 Python在将它们添加回来以及从逗号分隔数据重建列表方面速度非常快。 –

0

如果你有嵌套字典,你必须小心。大多数python对象不会使用pickle(并且可以将任何对象填充为dict中的值)。更糟糕的是,甚至更少的python对象可以转换为字符串并存储在SQL中。

但是,如果您使用klepto,数据库中的序列化和存储非常透明,并且适用于大多数python对象。

让我们建立一个dict(或类型的字典)一些典型的Python对象:

>>> class Foo(object):         
... def bar(self, x): 
...  return self.y + x 
... y = 1 
... 
>>> d1 = {'a': min, 'b': lambda x:x**2, 'c': [1,2,3], 'd': Foo()} 
>>> f = Foo(); f.y = 100 
>>> d2 = {'a': max, 'b': lambda x:x**3, 'c': [2,1,3], 'd': f} 

现在,让我们构建一个嵌套dict,并转储到MySQL存档。

>>> import klepto 
>>> a = klepto.archives.sql_archive('mysql://user:[email protected]/foo', dict={'d1':d1, 'd2':d2}) 
>>> a.dump() 

现在,我们删除我们的存档界面...并构建一个新的界面。 load将所有对象加载到内存中。

>>> del a 
>>> b = klepto.archives.sql_archive('mysql://user:[email protected]/foo') 
>>> b.load() 

我们现在访问内存中副本的对象。

>>> b['d1'] 
{'a': <built-in function min>, 'c': [1, 2, 3], 'b': <function <lambda> at 0x1037ccd70>, 'd': <__main__.Foo object at 0x103938ed0>} 
>>> b['d1']['b'](b['d1']['d'].bar(1)) 
4 
>>> b['d2']['b'](b['d2']['d'].bar(1)) 
1030301 
>>> 

我们退出python ...然后启动一个新的会话。这一次,我们决定使用cached=False,所以我们会直接与数据库交互。

[email protected]>$ python 
Python 2.7.10 (default, May 25 2015, 13:16:30) 
[GCC 4.2.1 Compatible Apple LLVM 5.1 (clang-503.0.40)] on darwin 
Type "help", "copyright", "credits" or "license" for more information. 
>>> import klepto 
>>> b = klepto.archives.sql_archive('mysql://user:[email protected]/foo', cached=False) 
>>> b['d2']['b'](b['d2']['d'].bar(1)) 
1030301 
>>> b['d1']['b'](b['d1']['d'].bar(1)) 
4 
>>> 

klepto利用sqlalchemy,因此它可以在多个后端数据库......,另外,提供了相同的基于dict接口,磁盘存储(在一个文件或目录)。

+0

哦,是的,我是'klepto'的作者。 –