使用一个小表中的值更新一个大表的性能

时间:2010-01-06 01:35:59

标签: sql mysql performance oracle

首先,我知道使用table_a中的值更新table_b的sql语句采用以下形式:

甲骨文:

UPDATE table_a 
  SET (col1, col2) = (SELECT cola, colb 
                        FROM table_b 
                       WHERE table_a.key = table_b.key) 
WHERE EXISTS (SELECT * 
                FROM table_b 
               WHERE table_a.key = table_b.key)

MySQL的:

UPDATE table_a 
INNER JOIN table_b ON table_a.key = table_b.key 
SET table_a.col1 = table_b.cola, 
    table_a.col2 = table_b.colb

据我所知,数据库引擎将遍历table_a中的记录,并使用table_b中匹配记录的值更新它们。

因此,如果table_a中有1千万条记录,table_b中只有10条记录:

  1. 这是否意味着引擎将通过table_a进行1000万次迭代只更新10条记录? Oracle / MySQL / etc是否足够聪明,只能通过table_b进行10次迭代?

  2. 有没有办法强制引擎实际迭代table_b而不是table_a中的记录来进行更新?是否有sql语句的替代语法?

  3. 假设table_a.keytable_b.key被编入索引。

2 个答案:

答案 0 :(得分:3)

基于表b中只有十行的事实,任何一个引擎都应该足够聪明以优化查询。引擎如何确定要做的是基于索引和统计等因素。

如果“key”列是主键和/或已编制索引,则引擎必须执行很少的工作才能运行此查询。它基本上已经是“知道”匹配行的位置,并且非常快速地查找它们。它根本不需要“迭代”。

如果键列上没有索引,引擎将不得不进行“表扫描”(大致相当于“迭代”)以找到正确的值并匹配它们。这意味着它必须扫描1000万行。

对所谓的执行计划进行一些阅读。这基本上解释了引擎为了运行查询而必须做的工作(一些数据库仅在文本中显示,有些数据库可以选择以图形方式查看)。学习如何解释执行计划将使您深入了解如何向表中添加索引并优化查询。

如果它们不起作用(这已经有一段时间了),请查看这些内容,但它类似于:

  • 在MySQL中,将工作“EXPLAIN”放在SELECT语句前面
  • 在Oracle中,在运行SELECT语句之前运行“SET AUTOTRACE ON”

我认为第一个(Oracle)查询最好使用JOIN而不是WHERE EXISTS编写。引擎可能足够智能,无论哪种方式都能正确优化。一旦掌握了执行计划的解释,您就可以双向运行并亲眼看看。 :)

答案 1 :(得分:1)

好的,我知道回答自己的问题通常是不满意的,但我已经接受了另一个答案,并且不会接受它,所以在这里它就是......

我发现了一个更好的选择,我想与遇到相同场景的任何人分享:MERGE声明。

显然,较新的Oracle版本引入了这个MERGE声明,这个声明很简单!在大多数情况下,不仅性能好得多,语法也很简单,因此使用UPDATE语句让我觉得很愚蠢!来了..

MERGE INTO table_a
USING table_b
ON (table_a.key = table_b.key)
WHEN MATCHED THEN UPDATE SET
  table_a.col1 = table_b.cola,
  table_a.col2 = table_b.colb;

INSERT没有table_a中某些记录的匹配记录时,我还可以扩展声明以包含table_b操作:

MERGE INTO table_a
USING table_b
ON (table_a.key = table_b.key)
WHEN MATCHED THEN UPDATE SET
  table_a.col1 = table_b.cola,
  table_a.col2 = table_b.colb
WHEN NOT MATCHED THEN INSERT
  (key, col1, col2)
  VALUES (table_b.key, table_b.cola, table_b.colb);

这个新的声明类型让我在发现它的那一天:)