Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/oracle/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 选择和更新大型表的优化方法_Sql_Oracle_Plsql_Oracle11g_Query Performance - Fatal编程技术网

Sql 选择和更新大型表的优化方法

Sql 选择和更新大型表的优化方法,sql,oracle,plsql,oracle11g,query-performance,Sql,Oracle,Plsql,Oracle11g,Query Performance,我必须通过连接一组大表来选择一组值,然后根据所选值更新另一个大表。我目前正在遵循以下方法。但我看到了一个性能缺陷。做上述工作的替代方法有哪些 数据库服务器:Oracle EE DECLARE CURSOR c1 IS SELECT update_data FOR UPDATE OF abc; BEGIN FOR update_data IN c1 LOOP UPDATE klm SET klm.xyz = update_data.cdf WHER

我必须通过连接一组大表来选择一组值,然后根据所选值更新另一个大表。我目前正在遵循以下方法。但我看到了一个性能缺陷。做上述工作的替代方法有哪些

数据库服务器:Oracle EE

DECLARE
  CURSOR c1
  IS
    SELECT update_data FOR UPDATE OF abc;
BEGIN
  FOR update_data IN c1
  LOOP
    UPDATE klm
    SET klm.xyz  = update_data.cdf
    WHERE update_data.abc = klm.abc;
  END LOOP;
  COMMIT;
END; 

最有可能的是,简单的更新将执行得更好

您可以尝试以下方法:

update klm t1
set xyz = ( select cdf from update_data t2 where t2.abc = t1.abc ) 
where exists ( select 1 from update_data t2 where t2.abc = t2.abc );

commit;
或者如果可能,在update_data.abc上有PK或唯一索引

update ( select t1.xyz, t2.cdf from klm t1, update_data t2 where t1.abc = t2.abc ) 
) set xyz = cdf; 

commit;

如果在每个记录上都有循环问题,但是对于单个更新来说表太大,您可以考虑批量使用批处理来更新…限制和限制

CREATE TABLE klm (abc INTEGER, xyz INTEGER);
CREATE TABLE update_data (abc INTEGER, cdf INTEGER);

-- Have pairs of numbers (1000 rows)
INSERT INTO klm SELECT rownum, rownum FROM dual CONNECT BY level <= 1000;
-- Update every second row with 9999
INSERT INTO update_data SELECT rownum * 2, 9999 FROM dual CONNECT BY level <= 500;

DECLARE
  CURSOR c1
  IS
    -- Select the key to be updated and the new value
    SELECT abc, cdf FROM update_data;
  -- Table type and table variable to store rows fetched from the cursor
  TYPE t_update IS TABLE OF c1%rowtype;
  update_tab t_update;
BEGIN
  OPEN c1;
  LOOP
    -- Fetch next 30 rows into update table
    FETCH c1 BULK COLLECT INTO update_tab LIMIT 30;
    -- Exit when there were no more rows fetched
    EXIT WHEN update_tab.count = 0;
    -- This is the key point; uses update_tab to bulk-bind UPDATE statement
    -- and run it for 30 rows in a single context switch
    FORALL i IN 1..update_tab.count
      UPDATE klm
      SET klm.xyz  = update_tab(i).cdf
      WHERE update_tab(i).abc = klm.abc;
    COMMIT;
  END LOOP;
  CLOSE c1;
END;
/
这背后的理由是Oracle实际上有单独的引擎运行SQL语句和PL/SQL程序。每当过程遇到SQL语句时,它都会将其交给SQL引擎执行。这称为上下文切换,需要花费大量时间,尤其是在循环中完成时

大容量绑定旨在通过每[Bulk size]记录只进行一次上下文切换来减少此开销。同样,这肯定不如单个DML操作有效,但对于大型表或复杂查询,这可能是最佳可行的解决方案


我使用上述方法更新了100M-500M记录的表格,批量大小为10K-100K,效果很好。但您需要在您的环境中试验批量大小以获得最佳性能。

谢谢您的回答。我尝试了第二种方法,但得到了一个错误SQL错误:ORA-01779:无法修改映射到非键保留表的列,而且我也无法理解第一种解决方案的where exists部分。为什么选择t2.abc=t2.abc?感谢与第一个答案有关;更新_数据也是生成的数据。我不认为在SET部分和WHERE EXIST中执行两次update_data SELECT查询是最好的选择。谢谢当我尝试我得到的第一个解决方案ORA-01427时:单行子查询返回多行。update\u data返回要更新的一千行。集合中的thanksselect应该只返回一行-您只能从一行更改值。Thx Kombajn。我能理解这个循环。但不清除选择的零件。你能解释一下选择逻辑吗?SELECT语句只要从update_数据表中选择关键abc和新值cdf,如果这是你的意思的话。无论如何,我添加了一些评论,我希望现在它会更清楚。也来看看