Производительность обновления одной большой таблицы с использованием значений из одной маленькой таблицы - PullRequest
1 голос
/ 06 января 2010

Во-первых, я знаю, что SQL-оператор для обновления table_a с использованием значений из table_b имеет вид:

Oracle:

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.

Итак, если у меня есть 10 миллионов записей в table_a и только 10 записей в table_b:

  1. Означает ли это, что механизм будет выполнять 10 миллионов итераций в течение table_a только для обновления 10 записей? Являются ли Oracle / MySQL / etc достаточно умными, чтобы выполнять только 10 итераций через table_b?

  2. Есть ли способ заставить движок фактически выполнять итерации по записям в table_b вместо table_a для обновления? Есть ли альтернативный синтаксис для оператора SQL?

Предположим, что table_a.key и table_b.key проиндексированы.

Ответы [ 2 ]

3 голосов
/ 06 января 2010

Любой механизм должен быть достаточно умным, чтобы оптимизировать запрос, основываясь на том факте, что в таблице b всего десять строк. То, как движок определяет, что делать, зависит от таких факторов, как индексы и статистика.

Если столбец «ключ» является первичным ключом и / или проиндексирован, движку потребуется выполнить очень мало работы для выполнения этого запроса. По сути, он уже «знает», где находятся совпадающие строки, и очень быстро их ищет. Это не должно будет "повторяться" вообще.

Если в ключевом столбце нет индекса, движок должен будет выполнить «сканирование таблицы» (примерно эквивалент «итерации»), чтобы найти правильные значения и сопоставить их. Это означает, что ему придется сканировать 10 миллионов строк.

Прочитайте немного о том, что называется планом выполнения. Это в основном объяснение того, какую работу должен был выполнить движок для выполнения вашего запроса (некоторые базы данных отображают его только в текстовом виде, некоторые имеют возможность увидеть его графически). Изучение интерпретации плана выполнения позволит вам лучше понять, как добавить индексы в ваши таблицы и оптимизировать ваши запросы.

Посмотрите их, если они не работают (это было давно), но это что-то вроде:

  • В MySQL поместите работу "EXPLAIN" перед оператором SELECT
  • В Oracle запустите «SET AUTOTRACE ON» перед выполнением оператора SELECT

Я думаю, что первый (Oracle) запрос лучше написать с помощью JOIN, а не WHERE EXISTS. Двигатель может быть достаточно умным, чтобы оптимизировать его в любом случае. Как только вы освоите интерпретацию плана выполнения, вы можете запустить его в обоих направлениях и убедиться в этом сами. :)

1 голос
/ 12 января 2010

Хорошо, я знаю, что отвечать на собственный вопрос обычно не одобряется, но я уже принял другой ответ и не откажусь от него, так что вот оно ...

Я обнаружил гораздо лучшую альтернативу, которую я хотел бы поделиться ею со всеми, кто сталкивается с тем же сценарием: 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);

Этот новый тип утверждения сделал мой день в день, когда я его обнаружил:)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...