2008-11-17 9 views
3

Мы имеем дело с очень медленным оператором обновления в проекте Oracle.Заявление о медленном обновлении

Вот небольшой скрипт replciate вопроса:

drop table j_test; 

CREATE TABLE J_TEST 
(
    ID NUMBER(10) PRIMARY KEY, 
    C1 VARCHAR2(50 BYTE), 
    C2 VARCHAR2(250 BYTE), 
    C3 NUMBER(5), 
    C4 NUMBER(10) 
); 

-- just insert a bunch of rows 
insert into j_test (id) 
select rownum 
from <dummy_table> 
where rownum < 100000; 

-- this is the statement that runs forever (longer than my patience allows) 
update j_test 
set C3 = 1, 
    C1 = 'NEU';  

Есть несколько сред, где Update-заявление занимает всего около 20 секунд, некоторые, где оператор работает в течение нескольких минут. При использовании большего количества строк проблема становится еще хуже.

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

Любые идеи и предложения? Благодаря Торстен

+0

«C4 ЧИСЛО (10)» по сравнению с «SET C4 =« NEU »заставляет меня почесывать голову. Это намерение или я не хватает захватывающей функции Oracle? – Tomalak 2008-11-17 16:44:51

+0

Tomalak, такой же мысль здесь. – 2008-11-17 16:59:12

ответ

12

Одной из возможных причин низкой производительности является цепочка строк. Все ваши строки изначально имеют столбцы C3 и C4 null, а затем вы обновляете их все, чтобы иметь значение. Новые данные не будут вписываться в существующие блоки, поэтому Oracle должен привязать строки к новым блокам.

Если вы знаете заранее, что вы будете делать это, вы можете предварительно выделить достаточное количество свободного пространства, как это:

CREATE TABLE J_TEST 
(
    ID NUMBER(10) PRIMARY KEY, 
    C1 VARCHAR2(50 BYTE), 
    C2 VARCHAR2(250 BYTE), 
    C3 NUMBER(5), 
    C4 NUMBER(10) 
) PCTFREE 40; 

... где PCTFREE указывает процент пространства, чтобы сохранить свободный обновлений. Значение по умолчанию - 10, чего недостаточно для этого примера, где строки более или менее удваиваются по размеру (от средней длины от 8 до 16 байт в соответствии с моим db).

Этот тест показывает разницу он делает:

SQL> CREATE TABLE J_TEST 
    2 (
    3 ID NUMBER(10) PRIMARY KEY, 
    4 C1 VARCHAR2(50 BYTE), 
    5 C2 VARCHAR2(250 BYTE), 
    6 C3 NUMBER(5), 
    7 C4 NUMBER(10) 
    8 ); 

Table created. 

SQL> insert into j_test (id) 
    2 select rownum 
    3 from transactions 
    4 where rownum < 100000; 

99999 rows created. 

SQL> update j_test 
    2 set C3 = 1, 
    3  C2 = 'NEU' 
    4/

99999 rows updated. 

Elapsed: 00:01:41.60 

SQL> analyze table j_test compute statistics; 

Table analyzed. 

SQL> select blocks, chain_cnt from user_tables where table_name='J_TEST'; 

    BLOCKS CHAIN_CNT 
---------- ---------- 
     694  82034 

SQL> drop table j_test; 

Table dropped. 

SQL> CREATE TABLE J_TEST 
    2 (
    3 ID NUMBER(10) PRIMARY KEY, 
    4 C1 VARCHAR2(50 BYTE), 
    5 C2 VARCHAR2(250 BYTE), 
    6 C3 NUMBER(5), 
    7 C4 NUMBER(10) 
    8 ) PCTFREE 40; 

Table created. 

SQL> insert into j_test (id) 
    2 select rownum 
    3 from transactions 
    4 where rownum < 100000; 

99999 rows created. 

SQL> update j_test 
    2 set C3 = 1, 
    3  C2 = 'NEU' 
    4/

99999 rows updated. 

Elapsed: 00:00:27.74 

SQL> analyze table j_test compute statistics; 

Table analyzed. 

SQL> select blocks, chain_cnt from user_tables where table_name='J_TEST'; 

    BLOCKS CHAIN_CNT 
---------- ---------- 
     232   0 

Как вы можете видеть, с PCTFREE 40 обновление занимает 27 секунд, а не 81 секунд, а результирующая таблица потребляет 232 блоков, без скованных строк вместо 694 блоков с 82034 цепочками!

3

Попробуйте это:

insert into j_test (id, C3, C4) 
select rownum, 1, 'NEU' 
from <dummy_table> 
where rownum < 100000; 
3

Вы действительно пытаетесь обновить числовое поле C4 NUMBER (10) со значением символа 'Neu'?

Предполагая, что вы пытаетесь сделать следующее:

UPDATE j_test 
    SET c3 = 3 
WHERE c1 = 'NEU' 

Вы, возможно, потребуется создать индекс на поле поиска и анализа таблицы, чтобы ускорить процесс обновления. Если вы действительно пытаетесь обновить всю таблицу, скорость обновления может отличаться. Это зависит от памяти, скорости доступа к диску, создания повторных журналов и т. Д.

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

0

Это очень похоже на вопрос и мой ответ here.

Никогда не обновляйте 100% строк в таблице. Просто следуйте процедуре в этой ссылке. постройте «правильный ответ» в качестве новой таблицы, а затем замените новую таблицу на старую. То же самое с удалением большого процента строк. Это гораздо эффективнее, чем использовать описанный мной сценарий.

EDIT: Если это кажется плохой идеей для некоторых из вас, просто знайте, что это техника, рекомендованная Томом Китом.

2

Уверена, что проблема не в том, что вы вставляете 'NEU' в поле Number (10)? Перед вставкой он выполняет преобразование «NEU» в «на лету» на номер (??).

Я имею в виду серьезно, другие ответы - хорошая и полезная информация, но 100k строк при полном обновлении должны быть быстрыми.

Помните - индексы имеют тенденцию к ускорению, выбирают и замедляют вставки/обновления.

0

Другая возможность состоит в том, что один UPDATE ждет, потому что таблица заблокирована (например, есть еще один незавершенных UPDATE на столе)
This link имеет SQL заявление, чтобы показать замки

Смежные вопросы