Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/83.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优化问题(oracle)_Sql_Oracle_Optimization - Fatal编程技术网

SQL优化问题(oracle)

SQL优化问题(oracle),sql,oracle,optimization,Sql,Oracle,Optimization,编辑:请回答我问的两个答案中的一个。我知道在不同的情况下,还有其他更好的选择。这些其他可能的选项(对表进行分区,作为一个大的delete语句运行,不进行批量提交等)在我的情况下不是选项,因为我无法控制 我有几个非常大的表要删除。它们都具有索引的相同外键。我需要从所有表中删除某些记录 table source id --primary_key import_source --used for choosing the ids to delete table t1 id --forei

编辑:请回答我问的两个答案中的一个。我知道在不同的情况下,还有其他更好的选择。这些其他可能的选项(对表进行分区,作为一个大的delete语句运行,不进行批量提交等)在我的情况下不是选项,因为我无法控制

我有几个非常大的表要删除。它们都具有索引的相同外键。我需要从所有表中删除某些记录

table source
  id --primary_key
  import_source --used for choosing the ids to delete

table t1
  id --foreign key
  --other fields

table t2
  id --foreign key
  --different other fields
通常在执行这样的删除操作时,我会创建一个循环,逐步遍历所有ID:

declare
my_counter integer := 0;
begin
for cur in (
select id from source where import_source = 'bad.txt'
) loop
  begin
    delete from source where id = cur.id;
    delete from t1 where id = cur.id;
    delete from t2 where id = cur.id;
    my_counter := my_counter + 1;
    if my_counter > 500 then
      my_counter := 0;
      commit;
    end if;
    end;
  end loop;
  commit;
end;
然而,在我在别处看到的一些代码中,它被放在单独的循环中,每次删除一个循环

declare
type import_ids is table of integer index by pls_integer;
my_count integer := 0;
begin
select id bulk collect into my_import_ids from source where import_source = 'bad.txt'

for h in 1..my_import_ids.count
  delete from t1 where id = my_import_ids(h);
    --do commit check
end loop;
for h in 1..my_import_ids.count
  delete from t2 where id = my_import_ids(h);
    --do commit check
end loop;

--do commit check will be replaced with the same chunk to commit every 500 rows as the above query
因此,我需要回答以下问题之一:

1) 这些中哪一个更好

2) 我怎样才能找出哪一个更适合我的特殊情况?(如果这取决于我有多少张桌子、桌子有多大等)

编辑:

由于这些表的大小,我必须在循环中执行此操作。我将从包含数亿条记录的表中删除数千条记录。这种情况发生在一个无法承受表被锁定那么长时间的系统上

编辑:

注意:我需要批量提交。数据量太大,无法一批完成。回滚表将使我们的数据库崩溃

如果有一种方法可以成批提交,而不是循环提交,我愿意听听。否则,不要麻烦说我不应该使用循环…

为什么要使用循环

delete from t1 where id IN (select id from source where import_source = 'bad.txt';
delete from t2 where id IN (select id from source where import_source = 'bad.txt';
delete from source where import_source = 'bad.txt'
这是使用标准SQL。我对Oracle不太了解,但许多DBMS还具有基于多表联接的删除功能,可以让您在一条语句中完成整个操作。

为什么要循环

delete from t1 where id IN (select id from source where import_source = 'bad.txt';
delete from t2 where id IN (select id from source where import_source = 'bad.txt';
delete from source where import_source = 'bad.txt'

这是使用标准SQL。我不知道Oracle的具体情况,但许多DBMS还具有基于多表联接的删除功能,这可以让您在一条语句中完成整个操作。

首先,您不应该在循环中提交
commit
,它效率不高(会生成大量重做),如果发生错误,您就无法回滚

正如前面的回答中所提到的,您应该发出一个
delete
s,或者,如果您要删除大多数记录,那么最好创建带有剩余行的新表,删除旧表,并将新表重命名为旧表名

大概是这样的:

CREATE TABLE new_table as select * from old_table where <filter only remaining rows>;

index new_table
grant on new table
add constraints on new_table
etc on new_table

drop table old_table
rename new_table to old_table;
createtablenew\u TABLE as select*from old\u TABLE where;
索引新表
格兰特在新桌子上
在新表上添加约束
新桌子上的etc
放下旧桌子
将新_表重命名为旧_表;

另请参见

首先,您不应该在循环中提交——它效率不高(会生成大量重做),如果发生错误,则无法回滚

正如前面的回答中所提到的,您应该发出一个
delete
s,或者,如果您要删除大多数记录,那么最好创建带有剩余行的新表,删除旧表,并将新表重命名为旧表名

大概是这样的:

CREATE TABLE new_table as select * from old_table where <filter only remaining rows>;

index new_table
grant on new table
add constraints on new_table
etc on new_table

drop table old_table
rename new_table to old_table;
createtablenew\u TABLE as select*from old\u TABLE where;
索引新表
格兰特在新桌子上
在新表上添加约束
新桌子上的etc
放下旧桌子
将新_表重命名为旧_表;

另请参见Larry Lustig关于不需要循环的观点是正确的。尽管如此,在较小的块中进行删除可能会有一些好处。在这里,PL/SQL批量绑定可以大大提高速度:

declare
type import_ids is table of integer index by pls_integer;
my_count integer := 0;
begin
select id bulk collect into my_import_ids from source where import_source = 'bad.txt'

forall h in 1..my_import_ids.count
  delete from t1 where id = my_import_ids(h);
forall h in 1..my_import_ids.count
  delete from t2 where id = my_import_ids(h);
我写它的方式是一次完成所有工作,在这种情况下,单一SQL更好。但您可以更改循环条件,将其分解为块。重点是

  • 不要在每一行都承诺。如果有任何问题,请仅每N行提交一次
  • 当使用N块时,不要在普通循环中运行delete。使用
    forall
    将delete作为大容量绑定运行,速度要快得多

除了提交的开销之外,原因是每次在PL/SQL代码中执行SQL语句时,它实际上都会进行上下文切换。批量绑定可以避免这种情况。

Larry Lustig说得对,您不需要循环。尽管如此,在较小的块中进行删除可能会有一些好处。在这里,PL/SQL批量绑定可以大大提高速度:

declare
type import_ids is table of integer index by pls_integer;
my_count integer := 0;
begin
select id bulk collect into my_import_ids from source where import_source = 'bad.txt'

forall h in 1..my_import_ids.count
  delete from t1 where id = my_import_ids(h);
forall h in 1..my_import_ids.count
  delete from t2 where id = my_import_ids(h);
我写它的方式是一次完成所有工作,在这种情况下,单一SQL更好。但您可以更改循环条件,将其分解为块。重点是

  • 不要在每一行都承诺。如果有任何问题,请仅每N行提交一次
  • 当使用N块时,不要在普通循环中运行delete。使用
    forall
    将delete作为大容量绑定运行,速度要快得多

除了提交的开销之外,原因是每次在PL/SQL代码中执行SQL语句时,它实际上都会进行上下文切换。大容量绑定可以避免这种情况。

您可以尝试分区,以使用并行执行,而不仅仅是删除一个分区。可能会证明在设置此项时很有用。在这种情况下,每个分区都将使用自己的回滚段。

您可以尝试分区来使用并行执行,而不仅仅是删除一个分区。可能会证明在设置此项时很有用。在这种情况下,每个分区将使用自己的回滚段。

David, 如果您坚持提交,您可以使用以下代码:

declare
  type import_ids is table of integer index by pls_integer;
  my_import_ids import_ids;
  cursor c is select id from source where import_source = 'bad.txt';
begin
  open c;
  loop
    fetch c bulk collect into my_import_ids limit 500;
    forall h in 1..my_import_ids.count
      delete from t1 where id = my_import_ids(h);
    forall h in 1..my_import_ids.count
      delete from t2 where id = my_import_ids(h);
    commit;
    exit when c%notfound;
  end loop;
  close c;
end;
这个程序以500行为单位获取ID,删除并提交每个ID。它应该比逐行处理快得多,因为
bulk collect
forall
作为单个操作(在往返数据库的单个往返过程中)工作,从而最大限度地减少了上下文切换的数量。有关详细信息,请参见。

David, 如果您坚持提交,您可以使用以下代码:

declare
  type import_ids is table of integer index by pls_integer;
  my_import_ids import_ids;
  cursor c is select id from source where import_source = 'bad.txt';
begin
  open c;
  loop
    fetch c bulk collect into my_import_ids limit 500;
    forall h in 1..my_import_ids.count
      delete from t1 where id = my_import_ids(h);
    forall h in 1..my_import_ids.count
      delete from t2 where id = my_import_ids(h);
    commit;
    exit when c%notfound;
  end loop;
  close c;
end;
这个程序以500行为单位获取ID,删除并提交每个ID。它应该比逐行处理快得多,因为
bulk collect
forall
作为单个操作(在单个往返t中)工作