Sql 慢速更新语句

Sql 慢速更新语句,sql,oracle,Sql,Oracle,我们正在处理Oracle项目中一个非常缓慢的update语句 这里有一个小脚本来回答这个问题: drop table j_test; CREATE TABLE J_TEST ( ID NUMBER(10) PRIMARY KEY, C1 VARCHAR2(50 BYTE), C2 VARCHAR2(250 BYTE), C3 NUMBER(5), C4 NUMBER(10) ); -- just insert a bunch of rows insert

我们正在处理Oracle项目中一个非常缓慢的update语句

这里有一个小脚本来回答这个问题:

drop table j_test;

CREATE TABLE J_TEST
(
  ID  NUMBER(10) PRIMARY KEY,
  C1   VARCHAR2(50 BYTE),
  C2   VARCHAR2(250 BYTE),
  C3   NUMBER(5),
  C4   NUMBER(10)
);

-- just insert a bunch of rows
insert into j_test (id)
select rownum 
from <dummy_table>
where rownum < 100000;

-- this is the statement that runs forever (longer than my patience allows)
update j_test
set C3 = 1,
    C1 = 'NEU';    
有些环境中,Update语句只需20秒,有些环境中语句运行几分钟。当使用更多行时,问题会变得更糟

我们不知道是什么导致了这种行为,并且希望在提出解决方案之前了解发生了什么

有什么想法和建议吗? 谢谢 Thorsten

试试这个:

insert into j_test (id, C3, C4)
select rownum, 1, 'NEU'
from <dummy_table>
where rownum < 100000;

您真的要用“NEU”字符值更新数字字段C4 NUMBER10吗

假设您正在尝试执行以下操作:

UPDATE j_test
   SET c3 = 3
 WHERE c1 = 'NEU'
您可能需要在搜索字段上创建索引并分析表以加快更新过程。 如果您确实试图更新整个表,那么更新速度可能会有所不同。它取决于内存、磁盘访问速度、重做日志创建等


另外,正如在另一个答案中提到的,您需要为使用PCTFREE的更新保留一些空间,否则您将在表中获得大量链接行,从而影响更新速度。

性能不佳的一个可能原因是行链接。您的所有行最初都有C3和C4列null,然后您将它们全部更新为有值。新数据无法放入现有块中,因此Oracle必须将行链接到新块

如果您事先知道要这样做,您可以像这样预先分配足够的可用空间:

CREATE TABLE J_TEST
(
  ID  NUMBER(10) PRIMARY KEY,
  C1   VARCHAR2(50 BYTE),
  C2   VARCHAR2(250 BYTE),
  C3   NUMBER(5),
  C4   NUMBER(10)
) PCTFREE 40;
。。。其中,PCTFREE指定用于更新的可用空间百分比。默认值是10,这对于本例来说是不够的,根据我的数据库,行的大小从平均长度8到16字节增加了一倍

此测试显示了它的不同之处:

SQL> CREATE TABLE J_TEST
  2  (
  3    ID  NUMBER(10) PRIMARY KEY,
  4    C1   VARCHAR2(50 BYTE),
  5    C2   VARCHAR2(250 BYTE),
  6    C3   NUMBER(5),
  7    C4   NUMBER(10)
  8  );

Table created.

SQL> insert into j_test (id)
  2  select rownum 
  3  from transactions
  4  where rownum < 100000;

99999 rows created.

SQL> update j_test
  2  set C3 = 1,
  3      C2 = 'NEU'
  4  /

99999 rows updated.

Elapsed: 00:01:41.60

SQL> analyze table j_test compute statistics;

Table analyzed.

SQL> select blocks, chain_cnt from user_tables where table_name='J_TEST';

    BLOCKS  CHAIN_CNT
---------- ----------
       694      82034

SQL> drop table j_test;

Table dropped.

SQL> CREATE TABLE J_TEST
  2  (
  3    ID  NUMBER(10) PRIMARY KEY,
  4    C1   VARCHAR2(50 BYTE),
  5    C2   VARCHAR2(250 BYTE),
  6    C3   NUMBER(5),
  7    C4   NUMBER(10)
  8  ) PCTFREE 40;

Table created.

SQL> insert into j_test (id)
  2  select rownum 
  3  from transactions
  4  where rownum < 100000;

99999 rows created.

SQL> update j_test
  2  set C3 = 1,
  3      C2 = 'NEU'
  4  /

99999 rows updated.

Elapsed: 00:00:27.74

SQL> analyze table j_test compute statistics;

Table analyzed.

SQL> select blocks, chain_cnt from user_tables where table_name='J_TEST';

    BLOCKS  CHAIN_CNT
---------- ----------
       232          0

如您所见,使用PCTFREE 40,更新需要27秒而不是81秒,结果表消耗232个没有链接行的块,而不是694个有82034个链接行的块

这与问题和我的答案非常相似

永远不要100%更新表中的行。只需按照链接中的步骤操作即可。将正确答案构建为新表,然后将新表替换为旧表。删除大部分行时也是如此。使用我概述的场景更有效


编辑:如果这对你们中的一些人来说是个坏主意,只需知道这是Tom Kyte推荐的技术

您确定问题不是因为您正在将“NEU”插入数字10字段吗?在插入之前,它正在进行从“NEU”到数字的动态转换

我的意思是说,认真地说,其他答案都是很好和有用的信息,但是一个完整更新的10万行应该很快


请记住-索引往往会加快选择速度,减慢插入/更新速度。

另一种可能是由于表被锁定,一个更新正在等待,例如表上有另一个未提交的更新
有一个SQL语句来显示锁

C4 NUMBER10,与SET C4='NEU'相比,这让我抓狂。这是意图还是我错过了一个令人兴奋的甲骨文特征?请考虑不要更新每一行。通过CTAS Create table as select执行此操作-请参见下文。抱歉,伙计们,希望我解决了此问题。很好的演示,但建议更新100%的行只会带来坏主意。Mark,我认为这是一个人为的示例,并且真正的更新是出于某些业务原因而稍后进行的。显然,如果行需要立即具有thise值,那么应该将它们与它们一起插入!