我怎样才能做一个批量插入到使用Python Oracle数据库?(How can I do a ba

2019-07-19 23:46发布

我有我想要插入到Oracle数据库表中的一些月度天气数据,但我想插入一个批次相应的记录,以便更有效。 任何人都可以提出建议,我怎么会去约在Python这样做呢?

例如,让我们说我的表有四个字段:站号,日期和两个值的字段。 该记录由站ID和日期字段(复合键)唯一地标识。 我必须插入每个站的值将保持在满年的数据X数的列表,因此,例如,如果有两个年值,则值列表将包含24个值。

我认为下面是我应该这样做,如果我想插入记录一次一个方式:

connection_string = "scott/tiger@testdb"
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()

有没有办法做我正在做的事情上面,但,为了提高效率,进行批量插入的方法吗? 顺便说一句我的经验与Java / JDBC / Hibernate的,所以如果有人能给出一个解释/例子进行比较的Java方法,然后它会是特别有帮助。

编辑:也许我需要使用cursor.executemany()所描述的在这里 ?

在此先感谢您的任何建议,意见等。

Answer 1:

下面是我想出这似乎很好地工作(但请评论,如果有改善此问题的方法):

# 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()


Answer 2:

使用Cursor.prepare()Cursor.executemany()

从cx_Oracle文档 :

Cursor.prepare语句 [, 标签 ])

这可以在通话之前被用来执行()来定义将要执行的语句。 当做到这一点,在准备阶段将不被当调用执行进行()与无或相同的字符串对象的发言中。 [...]

Cursor.executemany声明 参数

准备语句用于对数据库执行,然后执行它针对序列参数中找到的所有参数映射或序列。 该声明被以同样的方式管理的execute()方法对其进行管理。

因此,使用上述两个函数,你的代码就变成了:

connection_string = "scott/tiger@testdb"
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()

另请参阅Oracle的精通Oracle + Python的系列文章。



Answer 3:

我会创建一个使用联盟的大SQL插入语句:

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

你可以建立在Python中的字符串,并给它Oracle作为一个语句来执行。



Answer 4:

作为一个评论说,考虑使用INSERT ALL 。 据说这将是比使用显著快executemany()

例如:

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



Answer 5:

仅供参考我的测试结果:

我插入5000行。 每行3列。

  1. 插入运行5000次,它的成本1.24分钟。
  2. 与executemany运行,它的成本0.125秒。
  3. 用插入运行的所有代码:它的成本4.08分钟。

Python代码中,SQL状插入所有成T(A,B,C)选择哪个设置:1,:2,:3从双UNION ALL选择:4,:5:6从道尔·...

在Python代码设置此长SQL,它的成本0.145329秒。

我测试一个非常古老的太阳机器上我的代码。 CPU:1415 MH。

在第三种情况下,我检查了数据库端,等待事件是“从客户的SQL * Net的更多的数据。” 这意味着服务器等待来自客户端更多的数据。

第三种方法的结果是令人难以置信的,我没有测试。

所以从我的短的建议是只使用executemany。



文章来源: How can I do a batch insert into an Oracle database using Python?