Tengo algunas mensual de los datos meteorológicos que quiero insertar en una tabla de base de datos Oracle, pero quiero insertar los registros correspondientes en un lote con el fin de ser más eficientes. ¿Alguien puede asesorar en cuanto a cómo me gustaría ir sobre hacer esto en Python?

Por ejemplo, digamos que mi tabla tiene cuatro campos: ID de la estación, una fecha, y dos campos de valor. Los registros se identifican por la ID de la estación y los campos de fecha (clave compuesta). Los valores que voy a tener que insertar para cada estación se guardan en una lista con X número de años completos de datos, así por ejemplo, si hay dos años de valores, a continuación, el valor listas contienen 24 de valores.

Supongo que la de abajo es la forma en que me gustaría hacerlo si quería insertar los registros de uno en uno:

connection_string = "scott/[email protected]"
connection = cx_Oracle.Connection(connection_string)
cursor = cx_Oracle.Cursor(connection)
station_id = 'STATION_1'
start_year = 2000

temps = [ 1, 3, 5, 7, 9, 1, 3, 5, 7, 9, 1, 3 ]
precips = [ 2, 4, 6, 8, 2, 4, 6, 8, 2, 4, 6, 8 ]
number_of_years = len(temps) / 12
for i in range(number_of_years):
    for j in range(12):
        # make a date for the first day of the month
        date_value = datetime.date(start_year + i, j + 1, 1)
        index = (i * 12) + j
        sql_insert = 'insert into my_table (id, date_column, temp, precip) values (%s, %s, %s, %s)', (station_id, date_value, temps[index], precips[index]))
        cursor.execute(sql_insert)
connection.commit()

Hay una manera de hacer lo que estoy haciendo, pero en una forma que realiza un lote de inserción con el fin de aumentar la eficiencia? Por CIERTO mi experiencia con Java/JDBC/Hibernate así que si alguien puede dar una explicación y ejemplo que compara a la de Java enfoque, a continuación, sería especialmente útil.

EDIT: tal vez necesito usar el cursor.executemany() como se describe aquí?

Gracias de antemano por cualquier sugerencia, comentarios, etc.

El uso de la .executemany() llamar en su lugar?
Sí, Martijn, me acabo de enterar de que (y actualizado/modificado la pregunta para incluir éste), y parece ser la solución a este problema. Gracias por tu aporte!
Utilizar una consulta con INSERTAR TODOS para insertar varias filas a la vez.
.executemany() es no una actualización por lotes; que va a hacer como muchas instrucciones DML como han cursor ejecutar… Se me hace que el código de Python más limpia, pero no es más tolerante a la base de datos. Lo que hace que los datos originales; es introducido por un usuario y lo almacena en variables en el código o en un archivo de texto, etc.?
Gracias, Ben. Los datos se calcula y se almacena en la lista de variables. Así, en el sencillo ejemplo anterior, el temps y precips listas en realidad iba a ser computada en mi código de Python antes de llegar a esta sección, en lugar de asignar como en el ejemplo de código.

OriginalEl autor James Adams | 2013-02-15

5 Comentarios

  1. 16

    He aquí lo que he llegado con la que parece funcionar bien (pero por favor comente si hay una manera de mejorar este):

    # build rows for each date and add to a list of rows we'll use to insert as a batch 
    rows = [] 
    numberOfYears = endYear - startYear + 1
    for i in range(numberOfYears):
        for j in range(12):
            # make a date for the first day of the month
            dateValue = datetime.date(startYear + i, j + 1, 1)
            index = (i * 12) + j
            row = (stationId, dateValue, temps[index], precips[index])
            rows.append(row)
    
    # insert all of the rows as a batch and commit
    ip = '192.1.2.3' 
    port = 1521
    SID = 'my_sid'
    dsn = cx_Oracle.makedsn(ip, port, SID)
    connection = cx_Oracle.connect('username', 'password', dsn)
    cursor = cx_Oracle.Cursor(connection)
    cursor.prepare('insert into ' + database_table_name + ' (id, record_date, temp, precip) values (:1, :2, :3, :4)')
    cursor.executemany(None, rows)
    connection.commit()
    cursor.close()
    connection.close()

    OriginalEl autor James Adams

  2. 8

    Uso Cursor.prepare() y Cursor.executemany().

    De la cx_Oracle documentación:

    Cursor.prepare(declaración[, etiqueta])

    Esto puede ser usado antes de una llamada a execute() para definir la instrucción que será ejecutada. Cuando esto se hace, la fase de preparación no debe realizarse cuando la llamada a execute() está hecho con Ninguno o con el mismo objeto string como la declaración. […]

    Cursor.executemany(declaración, parámetros)

    Preparar una declaración para la ejecución en contra de una base de datos y, a continuación, ejecutarlo en contra de todas las asignaciones de parámetros o secuencias que se encuentran en los parámetros de la secuencia. La declaración se gestiona de la misma manera que el método execute (), que la administra.

    Por lo tanto, el uso de los dos anteriores funciones, el código se convierte en:

    connection_string = "scott/[email protected]"
    connection = cx_Oracle.Connection(connection_string)
    cursor = cx_Oracle.Cursor(connection)
    station_id = 'STATION_1'
    start_year = 2000
    
    temps = [ 1, 3, 5, 7, 9, 1, 3, 5, 7, 9, 1, 3 ]
    precips = [ 2, 4, 6, 8, 2, 4, 6, 8, 2, 4, 6, 8 ]
    number_of_years = len(temps) / 12
    
    # list comprehension of dates for the first day of the month
    date_values = [datetime.date(start_year + i, j + 1, 1) for i in range(number_of_years) for j in range(12)]
    
    # second argument to executemany() should be of the form:
    # [{'1': value_a1, '2': value_a2}, {'1': value_b1, '2': value_b2}]
    dict_sequence = [{'1': date_values[i], '2': temps[i], '3': precips[i]} for i in range(1, len(temps))]
    
    sql_insert = 'insert into my_table (id, date_column, temp, precip) values (%s, :1, :2, :3)', station_id)
    cursor.prepare(sql_insert)
    cursor.executemany(None, dict_sequence)
    connection.commit()

    También consulte Oracle Dominar Oracle+Python serie de artículos.

    Gracias por este. He probado el de arriba pero no funciona debido al hecho de que executemany() sólo toma dos argumentos. Y parece que aún tiene que crear una lista de filas para el uso como los parámetros de la secuencia argumento, como se describe en la sección titulada «Muchos a la Vez» aquí: oracle.com/technetwork/articles/dsl/… y las secciones que describen el uso de executemany() aquí: oracle.com/technetwork/articles/dsl/…
    También no está claro cómo el uso de un prepare (), obtiene nada, puesto que de acuerdo a la cx_Oracle.Cursor.execute() de la documentación: «Una referencia a la declaración será retenido por el cursor. Si Ninguno o el mismo objeto string se pasa de nuevo, el cursor se va a ejecutar de que la declaración de nuevo sin la realización de una de preparar o de reenlace y redefinición.» Pero yo puede ser malentendido algo aquí…
    El uso de prepare() no ganar nada, sólo hace el código más claro; la C subyacente código para el método es el mismo. En cuanto a tu primer comentario, he actualizado mi respuesta a la dirección: executemany() toma una secuencia de diccionarios como el segundo argumento.

    OriginalEl autor alldayremix

  3. 3

    Me gustaría crear una gran instrucción SQL insert con union:

    insert into mytable(col1, col2, col3)
    select a, b, c from dual union
    select d, e, f from dual union
    select g, h, i from dual

    Usted puede construir la cadena en python y darle a oracle como uno instrucción a ejecutar.

    Esta es una respuesta correcta. Varias inserciones son manejados con un viaje ida y vuelta a la base de datos. Un problema – Usted probablemente querrá hacer un UNION ALL en lugar de regular UNION.

    OriginalEl autor Derrick

  4. 3

    Como uno de los comentarios dice, considere el uso de INSERT ALL. Supuestamente va a ser significativamente más rápido que usando executemany().

    Por ejemplo:

    INSERT ALL
      INTO mytable (column1, column2, column_n) VALUES (expr1, expr2, expr_n)
      INTO mytable (column1, column2, column_n) VALUES (expr1, expr2, expr_n)
      INTO mytable (column1, column2, column_n) VALUES (expr1, expr2, expr_n)
    SELECT * FROM dual;

    http://www.techonthenet.com/oracle/questions/insert_rows.php

    Esta es una respuesta correcta. Varias inserciones son manejados con un viaje ida y vuelta a la base de datos.

    OriginalEl autor ragerdl

  5. 2

    fyi mi resultado de la prueba:

    Me insertar en 5000 filas. 3 columnas por fila.

    1. ejecutar insertar 5000 veces, cuesta 1.24 minutos.
    2. ejecutar con executemany, los costos de 0,125 segundos.
    3. ejecutar con insertar todo el código: cuesta 4.08 minutos.

    el código de python, que el programa de instalación de sql como
    insertar todos en t(a,b,c)
    seleccione :1, :2, :3 de doble union all select :4 de :5: :6 de daul…

    El código en python para la instalación de este largo sql, es el costo 0.145329 segundos.

    Puedo probar mi código en un muy viejo sol de la máquina. cpu: 1415 MH.

    en el tercer caso, he comprobado la base de datos secundarios, la espera del evento es «SQL*Net más datos de cliente». lo que significa que el servidor está a la espera de más datos desde el cliente.

    El resultado de la tercer método es increíble para mí, sin la prueba.

    tan corto sugerencia de mí es sólo para uso executemany.

    OriginalEl autor zhihuifan

Dejar respuesta

Please enter your comment!
Please enter your name here