使用Python批量更新SQL(Oracle)

时间:2014-01-04 00:40:19

标签: python sql oracle

我正在寻找一些关于如何批量更新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:非法变量名称/号码”。我确信这是非常明显的事情,但我已经检查过并且重新检查了但是在我的生活中不能看到我哪里出错了!

从对这种方法的所有研究中,它似乎是正确的方法......如果我能让它正在进行测试! 请帮忙。

2 个答案:

答案 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
     """

再次感谢