我正在寻找一些关于如何批量更新Oralce SQL表的帮助,记录最多为250,000。
基本上我有一个传递给函数的键列表,然后需要更新Oracle表。该列表最多可以包含250,000行,我可以使用普通更新语句或使用'executemany'来执行此操作,但这两种方法效率都太低,因此我需要进行批量更新,但我不熟悉如何执行此操作。我已经搜索了几个小时,但我无法解决这个问题!
todays_date = datetime.now().strftime("%d-%b-%Y")
status = str("DONE")
try:
bind_values = {"status" : str(status),
"todays_date" : todays_date,
"keys_list" : list_of_keys}
query = ("""FORALL i IN :keys_list.FIRST .. :keys_list.LAST
UPDATE TABLE_NAME
SET COLUMN1 = :status,
UPDATE_DATE = :todays_date
WHERE KEY = :i""")
cursor.execute(query, bind_values)
conn.commit()
self.CloseConnection(conn)
except cx_Oracle.DatabaseError, e:
error, = e.args
print(" >> Database error: %s" % format(e))
conn.rollback()
return False
任何帮助将不胜感激。
更新 @abarnert - 非常感谢你的建议,你肯定在这里做点什么,我设法得到这个目标
cursor.execute("""CREATE GLOBAL TEMPORARY TABLE TodaysKeys
(key STRING PRIMARY KEY)
on commit delete rows
AS (INSERT INTO TodaysKeys VALUES (:i))
UPDATE TABLE_NAME
SET COLUMN1 = :status,
UPDATE_DATE = :todays_date
WHERE KEY IN (SELECT * FROM TodaysKeys)
TABLE TodaysKeys""", i=keys_list,
status=str(updatestatus),
todays_date=todays_date)
但现在我得到的只是一个错误:“ORA-01036:非法变量名称/号码”。我确信这是非常明显的事情,但我已经检查过并且重新检查了但是在我的生活中不能看到我哪里出错了!
从对这种方法的所有研究中,它似乎是正确的方法......如果我能让它正在进行测试! 请帮忙。
答案 0 :(得分:0)
你需要找到一些方法在250K行上进行1次操作,而不是250K单独的1行操作,因为很明显,考虑到你的数据模型设计(我猜你既不控制也不理解)后者太慢了。
那么,你是怎么做到的?
一种方法是创建一个简单的临时表,将所有今天的密钥转储到它中(使用executemany
时速度要快得多 - 或者,如果没有,至少要更加简单LOAD DATA
...),然后执行一个引用该临时表中的键的UPDATE
。像这样(伪代码,基于使用sqlite3测试内容然后从距离内存转换为Oracle ...):
CREATE TEMPORARY TABLE TodaysKeys (key INT PRIMARY KEY)
INSERT INTO TodaysKeys VALUES (:i)
UPDATE TABLE_NAME
SET COLUMN1 = :status,
UPDATE_DATE = :todays_date
WHERE KEY IN (SELECT * FROM TodaysKeys)
DROP TABLE TodaysKeys
如果这个很慢,这意味着你没有KEY
列的索引,在这种情况下......真的没有办法加快这一点而不修复它。
答案 1 :(得分:0)
感谢大家提出的建议,我终于使用了这种方法,希望这可能会在未来类似的情况下帮助其他人。
query = """
DECLARE
CURSOR rec_cur IS
SELECT UNQ_KEY
FROM TABLE_NAME
WHERE COLUMN1 = 'NEW';
TYPE updated_keys IS TABLE OF VARCHAR(100);
pk_tab updated_keys;
BEGIN
OPEN rec_cur;
LOOP
FETCH rec_cur BULK COLLECT INTO pk_tab LIMIT 5000;
EXIT WHEN pk_tab.COUNT() = 0;
FORALL i IN pk_tab.FIRST .. pk_tab.LAST
UPDATE TABLE_NAME
SET COLUMN1 = :status,
UPDATE_DATE = :todays_date
WHERE unq_key = pk_tab(i);
END LOOP;
CLOSE rec_cur;
END
"""
再次感谢