簡體   English   中英

如何使用 Python 批量插入 Oracle 數據庫?

[英]How can I do a batch insert into an Oracle database using Python?

我有一些每月的天氣數據,我想插入到 Oracle 數據庫表中,但我想批量插入相應的記錄以提高效率。 誰能建議我如何在 Python 中執行此操作?

例如,假設我的表有四個字段:一個站 ID、一個日期和兩個值字段。 記錄由站 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()所描述的在這里

提前感謝您的任何建議、意見等。

這是我想出的似乎效果很好的方法(但如果有改進的方法,請發表評論):

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

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

cx_Oracle 文檔

Cursor.prepare (語句[, tag ])

這可以在調用 execute() 之前使用,以定義將要執行的語句。 完成后,當使用 None 或與語句相同的字符串對象調用 execute() 時,將不會執行准備階段。 [...]

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 的Mastering Oracle+Python系列文章。

僅供參考我的測試結果:

我插入 5000 行。 每行 3 列。

  1. 運行 insert 5000 次,耗時 1.24 分鍾。
  2. 使用 executemany 運行,耗時 0.125 秒。
  3. 使用插入所有代碼運行:花費 4.08 分鍾。

python 代碼,它設置 sql 就像 insert all into t(a,b,c) select :1, :2, :3 from dual union all select :4, :5: :6 from daul ...

設置這個長 sql 的 python 代碼花費了 0.145329 秒。

我在一台非常舊的 sun 機器上測試我的代碼。 中央處理器:1415 兆赫。

在第三種情況下,我檢查了數據庫端,等待事件是“SQL*Net more data from client”。 這意味着服務器正在等待來自客戶端的更多數據。

第三種方法的結果在沒有測試的情況下對我來說是難以置信的。

所以我的簡短建議就是使用executemany。

正如其中一條評論所說,考慮使用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

我將使用聯合創建一個大型 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。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM