我需要从包含900万条记录的表中删除10 000条记录。要删除的ID将从复杂查询中获取并存储在Java集合中。
我有3种方法来实现这个
1)创建一个预准备语句并向批处理添加10000个语句并执行它。
语句将如下所示
Delete from <table_name> where id=?;
2)写一个'in'查询而不是批量使用'='。 像
在此下,可以在Java代码中将10 000个ID创建为逗号分隔值并添加到查询中。或者,将10000个ID插入临时表中,并在子查询中从该表中进行选择。
Delete from <table_name> where id in (<CSV>);
or
Delete from <table_name> where id in (select id from <temp_table>);
表中没有约束和索引。而且我无法添加一个,因为我正在使用现有的桌子。
第一个选择是需要很长时间才能完成。它运行了15个小时但仍未完成。
答案 0 :(得分:2)
您的第一个版本的限制值为1000,并且往往效果不佳。第二种方法可能表现更好,但你必须有一个全局临时表,并填充它是一个额外的步骤。
您可以将Java集合转换为Oracle集合。您可以为此创建自己的表类型,但有一些内置的类型,如ODCINUMBERLIST,您可以在此处使用。你可以把它作为一个表格收集exprssion。
根据您的Java集合类型,细节可能略有不同,但大纲如下:
ArrayDescriptor aDesc = ArrayDescriptor.createDescriptor("SYS.ODCINUMBERLIST",
conn);
oracle.sql.ARRAY oraIDs = new oracle.sql.ARRAY(aDesc, conn, yourJavaCollectinOfIDs);
cStmt = (OracleCallableStatement) conn.prepareCall(
"Delete from <table_name>
where id in (select column_value from table(?))");
cStmt.setArray(1, oraIDs);
cStmt.execute();
除非它已经是一个简单的数组,否则您需要将Java集合转换为调用中的数组;例如如果你正在使用名为yourArrayList的ArrayList,你可以这样做:
oracle.sql.ARRAY oraIDs = new oracle.sql.ARRAY(aDesc, conn, yourArrayList.toArray());
您仍然会遇到缺少主键或索引的问题,但它会让Oracle有更好的机会来优化它而不是CSV列表(或者多个CSV列表一起OR'd,因为您有超过1000个ID)。 / p>
答案 1 :(得分:1)
您不应该通过从java代码执行10000语句来使用第一个选项。
创建临时表是个好主意。但大多数情况下,您不能拥有超过1000个项目的IN (...)
子句。因此,使用CSV
的方法可能不会成功。
你可以去
Delete from <table_name> where id in (select id from <temp_table>);
但这种方式也没有优化。最好将delete
语句更改为:
Delete from <table_name> m where exists (select id from <temp_table> t where m.id = t.id);
但是,如果您经常进行此类操作,强烈建议您向<table_name>
甚至是<temp_table>
添加一些约束和索引。它会像魅力一样提升您的运营执行时间。
答案 2 :(得分:0)
WHERE ... IN(...)是要走的路。
IN子句可以引用您已填充的临时表(您的原始想法),或者它可以包含任何选定(固定)的数量?参数。它会将db往返的数量减少一个等于所选数字的因子,但不一定是一个。迭代你的集合并以块的形式处理它。
答案 3 :(得分:0)
试试这样。
Delete from <table_name> where
id in (1, 2, 3, ... ,1000)
or id in (1001, 1002, ... , 2000)
....