2011-06-26 29 views
19

Estoy trabajando con el módulo MySQLdb en Python para interactuar con una base de datos. Tengo una situación en la que hay una lista muy grande (decenas de miles de elementos) que necesito insertar como filas en una tabla.Python + MySQL - Inserción masiva

Mi solución ahora es generar una gran declaración INSERT como una cadena y ejecutarla.

¿Hay alguna manera más inteligente?

Respuesta

16

Hay una manera más inteligente.

El problema con las inserciones masivas es que de forma predeterminada autocommit is enabled hace que cada una de las declaraciones insert se guarde en la tienda estable antes de que se pueda iniciar la próxima inserción.

Como se señala en las páginas de manual

Por defecto, MySQL se ejecuta con el modo de confirmación automática habilitado. Esto significa que tan pronto como ejecute una declaración de que actualiza (modifica) una tabla, MySQL almacena la actualización en el disco para que sea permanente. Para desactivar el modo de confirmación automática, utilizar la siguiente instrucción:

SET autocommit=0; 

Después de desactivar modo de confirmación automática mediante la variable de confirmación automática a cero, cambia a tablas transaccionales (como los de InnoDB , BDB o NDBCLUSTER) no se vuelven permanentes inmediatamente. Debe usar COMMIT para almacenar sus cambios en el disco o ROLLBACK para ignorar los cambios.

Esta es una característica bastante común de los sistemas RDBM que presumen que la integridad de la base de datos es primordial. Hace que las inserciones en bloque tomen del orden de 1 por inserción en lugar de 1 ms. La alternativa de hacer una instrucción de inserción extralarga trata de lograr esta única confirmación con el riesgo de sobrecargar el analizador SQL.

+4

Comenzando con 1.2.0, MySQLdb deshabilita la confirmación automática de forma predeterminada, como lo exige el estándar DB-API (PEP-249). fuente: http://mysql-python.sourceforge.net/FAQ.html – mikewaters

+0

Si sientes que tus insertos son aún más lentos de lo que deberían ser, asegúrate de modificar también la configuración de tu servidor mysql. En mi caso, mi 'innodb_buffer_pool_size' era demasiado pequeño para mis tamaños de transacción y al aumentarlo logré una aceleración de + 40% para inserciones masivas. Ver: https://dev.mysql.com/doc/refman/5.7/en/innodb-buffer-pool.html – jlh

1

Siempre que lo haga como un único INSERT y no miles de los individuales, entonces esta es la mejor manera de hacerlo. Tenga cuidado con no exceder el tamaño máximo de paquete de mysqls, y ajústelo si es necesario. Por ejemplo, esto establece el paquete de servidor máximo a 32Mb. Debe hacer lo mismo en el cliente también.

mysqld --max_allowed_packet=32M 
+0

esto es un truco en torno al mecanismo de transacción que aborda el síntoma y no la causa – msw

+0

¿Podría ampliar un poco sobre eso? ¿O decir qué harías en su lugar? – justinhj

+0

@msw Aún es más rápido para emitir INSERTs * por lotes * con * transacciones ... – Will

11

Si tiene que insertar una gran cantidad de datos, ¿por qué está tratando de insertarlos todos en un solo insert? (Esto cargará innecesariamente su memoria al hacer esta gran cadena insert y también mientras la ejecuta. Tampoco esta es una solución muy buena si los datos que va a insertar son muy grandes)

¿Por qué no hacer? usted pone una fila por comando insert en el DB y pone todas las filas usando un for...loop y compromete todos los cambios al final?

con = mysqldb.connect(
         host="localhost", 
         user="user", 
         passwd="**", 
         db="db name" 
        ) 
cur = con.cursor() 

for data in your_data_list: 
    cur.execute("data you want to insert: %s" %data) 

con.commit() 
con.close() 

(Créanme, esto es muy rápido, pero si usted está consiguiendo resultados más lentos, entonces significa que su autocommit debe haber True.Establecerlo en False como msw dice.)

+0

Si hay una declaración para cada inserción, ¿no sería muy lenta? No me importa usar memoria. Solo serán megabytes, así que no estoy preocupado. – Mike

+0

no, no será lento, eso es lo que quiero decir ... siempre y cuando no estés comprometido entre el ciclo. Pruebe ambos y vea si no me cree ... –

+0

En MyISAM (¿el motor que estoy usando) no se está realizando de forma implícita después de las ejecuciones? – Mike

Cuestiones relacionadas