2011-08-19 46 views
7

Analicé varias preguntas de SO sobre cómo extraer un objeto python y almacenarlo en una base de datos. La información que recopilé es:¿Cómo elegir un diccionario de Python en MySQL?

  • import pickle o import cpickle. Importe este último, si el rendimiento es un problema.
  • Supongamos dict es un diccionario de Python (o cualquier objeto Python): pickled = pickle.dumps(dict).
  • almacene pickled en una columna BLOB de MySQL utilizando el módulo para comunicarse con la base de datos.
  • Sácalo de nuevo. Y use pickle.loads(pickled) para restaurar el diccionario python.

Solo quiero asegurarme de haber entendido bien esto. ¿Me perdí algo crítico? ¿Hay efectos secundarios? ¿Es realmente así de fácil?

Información de fondo: Lo único que quiero hacer es almacenar Googlegeocoder-Responses, que son diccionarios anidados python en mi caso. Solo estoy usando una pequeña parte del objeto de respuesta y no sé si alguna vez necesitaré más de eso más adelante. Es por eso que pensé en almacenar la respuesta para ahorrarme la repetición de un millón de consultas.

+2

+1 Solo Python usaría 'pickle' como palabra clave ... #lulz. –

+0

Sería serializar el objeto como JSON, no como pickle, ya que es legible para los humanos y más fácil de leer en otros lenguajes de programación. La diferencia de rendimiento no es grande. –

Respuesta

2

Es así de fácil ... siempre y cuando no necesite su DB para saber cualquier cosa sobre el diccionario. Si necesita algún tipo de acceso de datos estructurados a los contenidos del diccionario, entonces tendrá que involucrarse más.

Otro problema es lo que intenta poner en el diccionario. La serialización de pepinillos de Python es bastante inteligente y puede manejar la mayoría de los casos sin necesidad de agregar soporte personalizado. Sin embargo, cuando no funciona, puede ser muy difícil entender lo que salió mal. Entonces, si puedes, restringe el contenido del dict a los tipos integrados de Python. Si comienza a agregar instancias de clases personalizadas, guárdelas en clases personalizadas sencillas que no contengan elementos divertidos para el almacenamiento o acceso a los atributos. Y tenga cuidado de agregar instancias de clases o tipos de complementos. En general, si comienza a tener problemas difíciles de entender con el decapado o descosido, observe los tipos no integrados en el dict.

+0

Solo tengo que encargar algunas listas/diccionarios anidados, y la base de datos no tiene que saber nada sobre estos objetos. Entonces creo que estaré bien en este caso. ¡Gracias por tu respuesta! – Aufwind

+0

Saludos posibles, ¿puedo preguntar, cuáles * son * los límites de lo que se puede escabechar? –

+1

@TomKimber Fair point, editado. –

1

Si la velocidad es muy importante, sólo corrió una prueba de carga de un diccionario de gran pitón (35 MB) a partir de un pepinillo contra la selección de una tabla de MySQL con todas las claves y los valores almacenados en filas:

salmuera Método:

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

MySQL método:

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 

de salida: método pickle: 32.0785171704 método mysql: 3,25 916336479

Si una mejora de velocidad de diez veces es suficiente, la estructura de la base de datos probablemente no importe. Tenga en cuenta que estoy dividiendo todos los datos separados por comas en listas como los valores de 36,000 claves y todavía solo toma 3 segundos. Así que he dejado de usar encurtidos para grandes conjuntos de datos, ya que el resto del programa de 400 líneas que estaba usando tomó aproximadamente 3 segundos, y la carga del encurtido tardó 32 segundos.

También tenga en cuenta:

cPickle funciona igual que la salmuera y es más de un 50% más rápido.

No intente extraer una clase llena de diccionarios y guardar en mysql: No se reconstituye correctamente, al menos no lo hizo para mí.

+1

Nota: al eliminar las comillas alrededor de cada cadena en cada lista que estaba almacenando, reduje el tamaño de los datos de 35MB a 24MB, lo que probablemente también ayudó a acelerar el método MYSQL. Python es muy rápido al agregarlos y reconstruir listas a partir de datos separados por comas. –

0

Si tiene diccionarios anidados, debe tener cuidado. La mayoría de los objetos Python no se acumulan (y puedes rellenar cualquier objeto como un valor en un dict). Peor aún, incluso menos objetos Python pueden convertirse a cadenas y almacenarse en SQL.

Sin embargo, si utiliza klepto, la serialización y el almacenamiento en una base de datos es bastante transparente y funciona para la mayoría de los objetos de python.

Vamos a construir algunos objetos típicos de pitón en un dict (o predice):

>>> 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} 

Ahora, vamos a construir un anidado dict, y volcado a un archivo de MySQL.

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

Ahora, eliminamos nuestra interfaz del archivo ... y construimos una nueva. El load carga todos los objetos en la memoria.

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

Ahora accedemos a los objetos en las copias en la memoria.

>>> 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 
>>> 

Salimos de python ... y luego comenzamos una nueva sesión. Esta vez, decidimos usar cached=False, por lo que interactuaremos directamente con la base de datos.

[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 aprovecha sqlalchemy, por lo que funciona a través de varios backends de bases de datos ... y, además, proporciona la misma dict interfaz basada en el almacenamiento en disco (en un archivo o un directorio).

+0

Oh, sí, soy el autor de 'klepto'. –

Cuestiones relacionadas