Oracle SQL - 如何更高效、更快速地进行海量更新?
Oracle SQL - How to do massive updates more efficient and faster?
我正在尝试一次更新 500.000 行。我有一个 table 产品是这样的:
+------------+----------------+--------------+-------+
| PRODUCT_ID | SUB_PRODUCT_ID | DESCRIPTION | CLASS |
+------------+----------------+--------------+-------+
| A001 | ACC1 | coffeemaker | A |
| A002 | ACC1 | toaster | A |
| A003 | ACC2 | coffee table | A |
| A004 | ACC5 | couch | A |
+------------+----------------+--------------+-------+
我有几组单独的陈述,例如:
update products set class = 'A' where product_id = 'A001';
update products set class = 'B' where product_id = 'A005';
update products set class = 'Z' where product_id = 'A150';
我正在做一个查询,将一个更新语句放在另一个更新语句下面,并每 1.000 行放置一个提交语句。
它工作正常(慢,但很好)但如果可能的话,我想做得更好。
有没有更好的方法可以更高效、更快速地执行此操作?
一种方法是创建一个临时 table 来保存您的更新信息:
new_product_class:
product_id class
========== =====
A A001
B A005
Z A150
product_id
应该是这个新 table 上的索引主键。然后你可以在加入这个临时 table:
的旧 table 上做一个 UPDATE
或 MERGE
UPDATE (SELECT p.product_id, p.class, n.product_id, n.class
FROM product p
JOIN new_product_class n ON (p.product_id = n.product_id)
SET p.class = n.class
或
MERGE INTO product p
USING new_product_class n
ON (p.product_id = n.product_id)
WHEN MATCHED THEN
UPDATE SET p.class = n.class
合并应该很快。根据您的环境,您可以考虑的其他事项:基于旧的 table 和 nologging
创建一个新的 table,然后进行一些重命名(应该在前后备份),批量更新。
除非您有索引,否则您的每个更新语句都会扫描整个 table。即使您有索引,编译和执行每个语句也会产生成本。
如果您有很多条件,并且这些条件可能会有所不同,那么我认为 Glenn 的解决方案显然是可行的方法。这会在单个事务中完成所有操作,没有理由 运行 批量处理 1,000 行 - 一次完成所有操作即可。
如果条件的数量相对有限(如你的例子),而且它们不会经常改变,那么你也可以作为一个简单的例子来做:
update products
set class =
case product_id
when 'A001' then 'A'
when 'A005' then 'B'
when 'A150' then 'C'
end
where
product_id in ('A001', 'A005', 'A150')
如果您的 class
字段可能已设置为正确的值,那么添加条件以确保您不会将某些内容更新为相同的值也很有价值。例如,如果这样:
update products set class = 'A' where product_id = 'A001';
更新 5,000 条记录,其中 4,000 条已设置为 'A',这样效率会高得多:
update products
set class = 'A'
where
product_id = 'A001' and
(class is null or class != 'A')
我正在尝试一次更新 500.000 行。我有一个 table 产品是这样的:
+------------+----------------+--------------+-------+ | PRODUCT_ID | SUB_PRODUCT_ID | DESCRIPTION | CLASS | +------------+----------------+--------------+-------+ | A001 | ACC1 | coffeemaker | A | | A002 | ACC1 | toaster | A | | A003 | ACC2 | coffee table | A | | A004 | ACC5 | couch | A | +------------+----------------+--------------+-------+
我有几组单独的陈述,例如:
update products set class = 'A' where product_id = 'A001';
update products set class = 'B' where product_id = 'A005';
update products set class = 'Z' where product_id = 'A150';
我正在做一个查询,将一个更新语句放在另一个更新语句下面,并每 1.000 行放置一个提交语句。 它工作正常(慢,但很好)但如果可能的话,我想做得更好。
有没有更好的方法可以更高效、更快速地执行此操作?
一种方法是创建一个临时 table 来保存您的更新信息:
new_product_class:
product_id class
========== =====
A A001
B A005
Z A150
product_id
应该是这个新 table 上的索引主键。然后你可以在加入这个临时 table:
UPDATE
或 MERGE
UPDATE (SELECT p.product_id, p.class, n.product_id, n.class
FROM product p
JOIN new_product_class n ON (p.product_id = n.product_id)
SET p.class = n.class
或
MERGE INTO product p
USING new_product_class n
ON (p.product_id = n.product_id)
WHEN MATCHED THEN
UPDATE SET p.class = n.class
合并应该很快。根据您的环境,您可以考虑的其他事项:基于旧的 table 和 nologging
创建一个新的 table,然后进行一些重命名(应该在前后备份),批量更新。
除非您有索引,否则您的每个更新语句都会扫描整个 table。即使您有索引,编译和执行每个语句也会产生成本。
如果您有很多条件,并且这些条件可能会有所不同,那么我认为 Glenn 的解决方案显然是可行的方法。这会在单个事务中完成所有操作,没有理由 运行 批量处理 1,000 行 - 一次完成所有操作即可。
如果条件的数量相对有限(如你的例子),而且它们不会经常改变,那么你也可以作为一个简单的例子来做:
update products
set class =
case product_id
when 'A001' then 'A'
when 'A005' then 'B'
when 'A150' then 'C'
end
where
product_id in ('A001', 'A005', 'A150')
如果您的 class
字段可能已设置为正确的值,那么添加条件以确保您不会将某些内容更新为相同的值也很有价值。例如,如果这样:
update products set class = 'A' where product_id = 'A001';
更新 5,000 条记录,其中 4,000 条已设置为 'A',这样效率会高得多:
update products
set class = 'A'
where
product_id = 'A001' and
(class is null or class != 'A')