Стоит ли накладных расходов использовать временную таблицу для копирования строки? - PullRequest
3 голосов
/ 29 октября 2010

Когда я сталкиваюсь с задачей копирования записи в базу данных и изменения только нескольких значений, я склонен использовать временную таблицу, чтобы избежать выписывания всех неизмененных столбцов. Кто-нибудь знает, как это повлияет на производительность в крупномасштабной системе?

Быстрый пример (который также показывает, почему я предпочитаю метод временной таблицы):

Допустим, у меня есть таблица mytbl с 50 столбцами col1 ... col50. Я хочу вставить новую запись, которая является точной копией строки, в которой col5 = 'Some Value' за исключением того, что col45 будет установлено в 'Some other value'.

Метод 1

CREATE GLOBAL TEMPORARY TABLE tmptbl AS
  SELECT * FROM myschema.mytbl;

INSERT INTO tmptbl
  (SELECT *
   FROM myschema.mytbl
   WHERE mytbl.col5 = 'Some Value');

UPDATE tmptbl
SET col45 = 'Some Other Value';

INSERT INTO myschema.mytbl
  (SELECT * FROM tmptbl);

DROP TABLE tmptbl;

Метод 2

INSERT INTO myschema.mytbl (col1,
                            col2,
                            col3,
                            col4,
                            col5,
                            col6,
                            col7,
                            col8,
                            col9,
                            col10,
                            col11,
                            col12,
                            col13,
                            col14,
                            col15,
                            col16,
                            col17,
                            col18,
                            col19,
                            col20,
                            col21,
                            col22,
                            col23,
                            col24,
                            col25,
                            col26,
                            col27,
                            col28,
                            col29,
                            col30,
                            col31,
                            col32,
                            col33,
                            col34,
                            col35,
                            col36,
                            col37,
                            col38,
                            col39,
                            col40,
                            col41,
                            col42,
                            col43,
                            col44,
                            col45,
                            col46,
                            col47,
                            col48,
                            col49,
                            col50)
SELECT col1,
       col2,
       col3,
       col4,
       col5,
       col6,
       col7,
       col8,
       col9,
       col10,
       col11,
       col12,
       col13,
       col14,
       col15,
       col16,
       col17,
       col81,
       col19,
       col20,
       col21,
       col22,
       col23,
       col24,
       col25,
       col26,
       col27,
       col28,
       col29,
       col30,
       col31,
       col32,
       col33,
       col34,
       col35,
       col36,
       col37,
       col38,
       col39,
       col40,
       col41,
       col42,
       col43,
       col44,
       'Some Other Value',
       col46,
       col47,
       col48,
       col49,
       col50
FROM myschema.mytbl
WHERE col5 = 'Some Value';

Сколько накладных расходов создает создание / удаление временной таблицы? Если, например, это было частью ежедневного процесса в системе промышленного размера, будут ли заметны дополнительные издержки? Я понимаю, что многое зависит от специфики системы, но общая идея была бы фантастической.

Ответы [ 6 ]

10 голосов
/ 30 октября 2010

Прежде всего, это не то, как временные таблицы работают в Oracle. Глобальные временные таблицы - это постоянные структуры , это просто данные в них, которые являются временными. Таким образом, нет необходимости создавать и удалять таблицы для каждой операции. Это просто добавляет накладные расходы.

Во-вторых, ситуации, когда временные таблицы оправданы, на самом деле довольно редки. В большинстве сценариев достаточно простой переменной. Этот синтаксис, который вставляет одну строку, действителен с 9iR2 и далее:

declare
    lrec emp%rowtype;
begin
    select *
    into lrec
    from emp
    where empno = 1234;

    lrec.empno = 9999;
    lrec.sal = 5000;

    insert into emp values lrec;
end;

Обратите внимание, что в этой формулировке скобки не требуются.

4 голосов
/ 29 октября 2010

Я не понимаю, как это может быть быстрее с временной таблицей.

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

В конечном счете, я думаю, что метод 1 имеет на намного больше накладных расходов, чем метод 2, даже не учитывая даже немаловажную стоимость создания / уничтожения временной таблицы.

3 голосов
/ 29 октября 2010

Боюсь, это может быть причиной преждевременной оптимизации. Похоже, что этот подход «решает» проблему, которая может существовать или не существовать, но, безусловно, добавляет значительную степень сложности системе. Мое предложение

  1. Сделайте самое простое, что могло бы сработать (в данном случае, вероятно, комбинацию INSERT-SELECT).
  2. Измерьте результаты.
  3. Если решение № 1 работает, хорошо. Вы сделали самое простое, что могли, и это решило вашу проблему.
  4. Если решение № 1 не работает (или работает недостаточно хорошо), тоже хорошо - перейдите к следующей простейшей вещи, которая могла бы работать.
  5. Повторять до тех пор, пока проблема не будет достаточно "решена" или пока не будет исчерпан бюджет времени или денег.

Делись и наслаждайся.

2 голосов
/ 30 октября 2010

Вы можете сделать это следующим образом.

ВСТАВИТЬ INTO myschema.mytbl (ВЫБРАТЬ * ИЗ myschema.mytbl ГДЕ mytbl.col5 = 'Some Value');

ОБНОВИТЬ myschema.mytbl SETcol45 = 'Some Other Value', WHERE col5 = 'Some Value' И rownum <= 1; </p>

Это даже короче, чем использование временной таблицы, и не имеет ни одного из недостатков временных таблиц.Конечно, если ваша реальная проблема сложнее, чем вы показали, это может не сработать.

2 голосов
/ 30 октября 2010

Я предполагаю, что основная цель вашего подхода состоит в том, чтобы избежать необходимости записывать все 50 столбцов дважды, что, как я полагаю, имеет тот недостаток, что вам приходится вносить изменения, если в таблицу добавляется другой столбец.Другие прокомментировали структуру исходной таблицы, накладные расходы на временные таблицы и преждевременную оптимизацию и т. Д. На самом деле это был не ваш вопрос, но в этом предположении я вижу третий метод, который может работать:

declare
    type tmptbl_type is table of mytbl%rowtype;
    cursor c is
        select * from mytbl where col5 = 'Some Value';
    tmptbl tmptbl_type;
begin
    open c;
    loop
        fetch c bulk collect into tmptbl limit 1000;
        for i in 1..tmptbl.count loop
            tmptbl(i).col45 := 'Some Other Value';
        end loop;
        forall i in 1..tmptbl.count
            insert into mytbl values tmptbl(i);
        exit when c%notfound;
    end loop;
    close c;
end;
/
1 голос
/ 29 октября 2010

Если ваша процедура будет работать с менее чем 250 строками, вы можете рассмотреть возможность использования табличной переменной вместо временной таблицы, поскольку табличная переменная использует память вместо физической записи в базу данных tempdb.

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