以下是我正在运行32k次的更新语句,并且运行时间超过15小时。 我必须更新表2中的32k不同M_DISPLAY值的值。
UPDATE TABLE_2 T2 SET T2.M_VALUE = 'COL_ANC'
WHERE EXISTS (SELECT 1 FROM TABLE_2 T1 WHERE TRIM(T1.M_DISPLAY) = 'ANCHORTST' AND T1.M_LABEL=T2.M_LABEL );
我不确定为什么我花了这么长时间调整查询,
我在Update.sql文件中复制了32000个更新语句,并在命令行中运行SQL。 虽然它正在更新表格,但这是一个无休止的过程
如果我在任何地方出错,请提供建议
此致
答案 0 :(得分:2)
如果您无法重写查询以运行单个批量更新而不是32k个人更新,那么使用PL / SQL的FORALL
仍然可以获得幸运。一个例子:
DECLARE
TYPE rec_t IS RECORD (
m_value table_2.m_value%TYPE,
m_display table_2.m_display%TYPE
);
TYPE tab_t IS TABLE OF rec_t;
data tab_t := tab_t();
BEGIN
-- Fill in data object. Replace this by whatever your logic for matching
-- m_value to m_display is
data.extend(1);
data(1).m_value := 'COL_ANC';
data(1).m_display := 'ANCHORTST';
-- Then, run the 32k updates using FORALL
FORALL i IN 1 .. data.COUNT
UPDATE table_2 t2
SET t2.m_value = data(i).m_value
WHERE EXISTS (
SELECT 1
FROM table_2 t1
WHERE trim(t1.m_display) = data(i).m_display
AND t1.m_label = t2.m_label
);
END;
/
如果您不是系统中的唯一进程,则单个事务中的32k更新可能会受到影响。绝对值得在子事务中提交几千行,以减少在您更新时可能读取同一个表的其他进程的并发效应。
实际上,任何改进的目标都应该是一次性批量更新整个数据集(或者可能分成几个批量,请参见并发)。
如果您有一个包含更新说明的登台表:
CREATE TABLE update_instructions (
m_value VARCHAR2(..),
m_display VARCHAR2(..)
);
然后你可以按照以下方式取消:
MERGE INTO table_2 t2
USING (
SELECT u.*, t1.m_label
FROM update_instructions u
JOIN table_2 t1 ON trim(t1.m_display) = u.m_display
) t1
ON t2.m_label = t1.m_label
WHEN MATCHED THEN UPDATE SET t2.m_value = t1.m_value;
这应该比FORALL
更快(但可能会有更多的并发影响)。
当然,运行32k个别更新语句时可能会对您造成伤害的一件事是TRIM()
函数,它会阻止M_DISPLAY
上的索引有效使用。如果你可以清理你的数据,所以它不需要先修剪,这肯定会有所帮助。否则,您可以仅为更新添加基于函数的索引(然后再将其删除):
CREATE INDEX i ON table_2 (trim (m_display));
答案 1 :(得分:0)
查询和子查询查询同一个表:TABLE_2。假设M_LABEL是唯一的,子查询为TABLE_2中的所有行返回1,其中M_DISPLAY是ANCHORTST。然后更新查询为子查询返回的所有1更新相同的(!)TABLE_2 - 因此对于M_DISPLAY为ANCHORTST的所有行。
因此,可以简化查询,利用更新和选择工作在同一个表上的事实 - TABLE_2:
UPDATE TABLE_2 T2 SET T2.M_VALUE = 'COL_ANC' WHERE TRIM(T2.M_DISPLAY) = 'ANCHORTST'
如果M_LABEL不是唯一的,那么以上就不会起作用 - 感谢评论员指出这一点!
答案 2 :(得分:0)
为了显着加快执行速度:
确保您已在WHERE子句中的M_DISPLAY和M_LABEL列上创建索引。
确保M_DISPLAY具有基于函数的索引。如果没有,则不要将其传递给TRIM函数,因为该函数将阻止数据库使用您为M_DISPLAY列创建的索引。在存储到表格中之前对数据进行TRIM。
多数民众赞成。
顺便说一句,正如已经提到的,您不应该需要32k查询来实现您的目标。一个人可能就够了。查看基于查询的更新。例如,请在此处查看已接受的答案: Oracle SQL: Update a table with data from another table