Является ли вставка в ... где не существует дороже в производительности? - PullRequest
0 голосов
/ 05 февраля 2020

Мы используем Oracle база данных (12 c)

Таблица ABCD имеет структуру ниже примерно с (10 ^ 5) строками

CCOL * - столбец Varchar2

DCOL * - столбец отметки времени

Name   Null?    Type              
----- -------- ----------------- 
CCOL1 NOT NULL VARCHAR2(64 CHAR) 
CCOL2 NOT NULL VARCHAR2(30 CHAR) 
CCOL3 NOT NULL VARCHAR2(64 CHAR) 
DCOL1 NOT NULL TIMESTAMP(6)      
CCOL4 NOT NULL VARCHAR2(64 CHAR) 
DCOL2 NOT NULL TIMESTAMP(6)      
CCOL5          VARCHAR2(32 CHAR)

Первичный ключ в этой таблице (CCOL1, CCOL2)

У нас есть следующий оператор вставки: Вставить 1:

BEGIN
    INSERT INTO abcd (
        ccol1, ccol2, ccol3, dcol1, ccol4, dcol2, ccol5)
        SELECT
            :b1, :b2, :b3, :b4, :b5, :b6, :b7
        FROM
            dual
        WHERE
            NOT EXISTS (
                SELECT 1 FROM abcd  WHERE ccol1 = :b1 AND ccol2 = :b2 );
EXCEPTION
    WHEN dup_val_on_index THEN
        NULL;
    WHEN OTHERS THEN
        RAISE;
END;

И альтернативу этому мы имеем (убрал часть, где не существует)

Вставка 2:

BEGIN
    INSERT INTO abcd (
        ccol1, ccol2, ccol3, dcol1, ccol4, dcol2, ccol5)
        VALUES 
        (:b1, :b2, :b3, :b4, :b5, :b6, :b7);

EXCEPTION
    WHEN dup_val_on_index THEN
        NULL;
    WHEN OTHERS THEN
        RAISE;
END;

Какая из этих вставок лучше?

1 Ответ

2 голосов
/ 05 февраля 2020

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

Лично я, вероятно, написал бы это (как подсказывает @Boneist) как MERGE только с предложением when not matched

MERGE INTO abcd dest
  USING( SELECT :b1 ccol1, :b2 ccol2, :b3 ccol3, ...
           FROM dual ) src
     ON( src.ccol1 = dest.ccol1 AND
         src.ccol2 = dest.ccol2 )
 WHEN NOT MATCHED THEN
    INSERT( ccol1, ccol2, ccol3, ... )
      VALUES( src.ccol1, src.ccol2, src.ccol3, ... )

Отдельно, наличие обработчика исключений WHEN OTHERS, который просто выполняет RAISE, не имеет особого смысла - просто не поймайте исключение, если вы не собираетесь ничего с ним делать. В вашем первом фрагменте кода нет смысла отлавливать и игнорировать проверку dup_val_on_index, потому что у вас уже есть предложение NOT EXISTS. В этот момент dup_val_on_index больше не является ожидаемым исключением, поэтому не стоит его ловить и игнорировать.

...