Простое обновление Oracle, плохая производительность - PullRequest
1 голос
/ 21 декабря 2011

У меня есть таблица с большими данными (около 10 миллионов записей), так что простейший оператор обновления будет длиться вечно.

Например:

update mesg 
set archived = 1
    , last_update = SYSDATE 
where id = 0 
and crea_date_time < '07/27/2011 13:53:36'  
and archived = 0;

Это утверждение занимает около 3 часов. хотя у нас есть индекс по id и составной индекс по crea_date_time, а триггеров нет.

Могу ли я улучшить работу, чтобы улучшить производительность?

Я пытался добавить индекс в архив, но безрезультатно.


вот дополнительная информация.

CREATE TABLE "MESG"
  (
    "ID"                        NUMBER(3,0) NOT NULL ENABLE,
    "UMIDL"                     NUMBER(10,0) NOT NULL ENABLE,
    "UMIDH"                     NUMBER(10,0) NOT NULL ENABLE,
    .
    .
    .
    "ARCHIVED"          NUMBER(1,0) NOT NULL ENABLE,
    "LAST_UPDATE" DATE,
    "CREA_DATE_TIME" DATE NOT NULL ENABLE,
    .
    .
    .
    CONSTRAINT "PK_RMESG" PRIMARY KEY ("AID", "UMIDH", "UMIDL") USING INDEX PCTFREE 10 INITRANS 2 MAXTRANS 255 COMPUTE STATISTICS STORAGE(INITIAL 524288 NEXT 524288 MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT) TABLESPACE "XXXX_IDX" ENABLE
  )

  SEGMENT CREATION IMMEDIATE PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255 NOCOMPRESS LOGGING STORAGE
  (
    INITIAL 524288 NEXT 524288 MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT
  )
  TABLESPACE "XXXX_MESG" ;

Индексы:

CREATE INDEX "E_RCREATIONDATE" ON "RMESG"
  (
    "CREA_DATE_TIME"
  )
  PCTFREE 10 INITRANS 2 MAXTRANS 255 COMPUTE STATISTICS STORAGE
  (
    INITIAL 524288 NEXT 524288 MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT
  )

  TABLESPACE "XXXX_IDX" ;
CREATE UNIQUE INDEX "PK_RMESG" ON "RMESG"
  (
    "ID", "UMIDH", "UMIDL"
  )
  PCTFREE 10 INITRANS 2 MAXTRANS 255 COMPUTE STATISTICS STORAGE
  (
    INITIAL 524288 NEXT 524288 MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT
  )
  TABLESPACE "XXXX_IDX" ;

И план запроса для моей локальной машины с записями 180K

ID   PID   Operation   Name   Rows   Bytes   Cost   CPU Cost   IO Cost   Temp space   IN-OUT   PQ Dist   PStart   PStop
0      UPDATE STATEMENT      1    44    877    6245703    877                       
1   0     UPDATE   MESG                                           
2   1       TABLE ACCESS BY INDEX ROWID   MESG   1    44    877    6245703    877                       
3   2         INDEX RANGE SCAN   IX_MESG_CREATIONDATE   158K       877    6245703    877                       

Ответы [ 6 ]

2 голосов
/ 21 декабря 2011

Я предполагаю, что заархивированный является псевдо -булевым, который может быть либо 0, либо 1. В таком случае оптимизатор может выбрать игнорирование индекса.

Чтобы проверить,индекс используется, вы можете попробовать

explain plan for
   update mesg set archived = :a, 
                   last_update = :b 
     where id = :c and 
            crea_date_time < :d and 
            archived = :e;  

, а затем

select * from table(dbms_xplan.display);
1 голос
/ 22 декабря 2011

Индексы не проблема. Это обновление.

Я думаю, вам придется погрузиться в анализ ожиданий, словарную таблицу v $ session_waits. Если у вас есть контроль базы данных Enterprise Manager, вы можете использовать инструменты производительности, чтобы увидеть, что вызывает задержку. Я предполагаю, что это как-то связано с производительностью ввода-вывода журналов повторов ИЛИ, как другие упоминали проблему блокировки.

Для начала:

select
 seq#, event, p1, p2, p3
from
 v$session_wait_history
where
sid = <yoursid>
order by seq#
;   

Google по анализу ожидания оракула, вы найдете много материала.

1 голос
/ 22 декабря 2011

Сначала вы действительно хотите запустить:

update mesg  
set archived = 1     
, last_update = SYSDATE  
where id = 0  and crea_date_time < '07/27/2011 13:53:36'  
and archived <>1

(это <> правильный код для ORacle? Или это использовать! =? Или, может быть, где заархивировано нулевое значение или где заархивировано = 0, отмена накак вы храните данные)

Сейчас вы изменяете дату last_update и архивное поле для всех уже заархивированных записей.Таким образом, вы можете обновлять миллионы уже заархивированных записей.Поэтому вместо того, чтобы обновлять 120 000 записей, которые должны быть заархивированы с тех пор, как вы в последний раз делали это, вы обновляете 35 000 000 записей, большинство из которых уже заархивированы.Может иметь большое значение для производительности только для обновления записей, которые должны быть обновлены.

Далее я не знаю об Oracle, но иногда быстрее запускать большие обновления / вставки / удаления в пакетах на SQl Server.Итак, вы пробовали циклически проходить через 1000 (или 50000, возможно, вам придется протестировать, чтобы увидеть, что работает) одновременно?Это может уменьшить количество конфликтов на столе и заставить вещи работать быстрее.

1 голос
/ 21 декабря 2011

Если вы обновите много строк, индексы вам не помогут. Они только улучшают доступ к данным.

Что для вас медленно, так это само ОБНОВЛЕНИЕ.

A. Является ли эта таблица доступной для чтения / обновления пользователями?

Если нет, вы можете попытаться воссоздать таблицу с новыми данными.

create table copy_table as
select case 
       when s.archived = 0 and s.crea_date_time < '07/27/2011 13:53:36' and s.id = 0
       then 1 else s.archived as archived,
       when s.archived = 0 and s.crea_date_time < '07/27/2011 13:53:36' and s.id = 0
       then sysdate else s.last_update_date as last_update_date,
       id,
       other_columns
from mesg;

rename mesg to mesg_old;
rename copy_table to mesg;

B. Другой идеей / помощью является, если у вас есть лицензия, разделить вашу таблицу сообщений на crea_date_time (я предполагаю, что это date тип). В этом случае ваше обновление не будет сканировать всю таблицу, но, что более важно, вам, вероятно, никогда не понадобится помечать объекты архива. Старые разделы - старые данные.

C. Индекс CREA_DATE_TIME замедляет ваше обновление. Если это не обязательно, бросьте его.

0 голосов
/ 20 января 2014

Вы должны пойти на разделение таблиц и индексирование. Производительность увеличится

0 голосов
/ 21 декабря 2011

Три часа слишком много, даже для объема данных.

Вы можете попытаться изменить запрос, чтобы избежать приведения типов, примените функцию to_data к вашей строке даты (преобразуйте это '07 / 27/2011 13: 53: 36 до настоящего времени)

Но проблема должна быть в блокировках , вы можете проверить наличие блокировок с помощью Завершение сеанса оракула для удаления сценария блокировки .

Кроме того, вы можете разбить большой запрос на небольшие обновления, например:

for each year:
   begin transaction
   update statement where year(date) = @year and other conditions
   end transaction
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...