Запрос обновления Oracle SQL, цикл для ограничения строк, обновляемых одновременно

#sql #oracle #loops #limit #rows

#sql #Oracle #циклы #ограничение #строки

Вопрос:

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

 UPDATE table1
SET table1.comment = 
   (SELECT table2.comment
    FROM table2
    WHERE table1.ID = table2.ID)
WHERE(SELECT table2.updateTime
FROM table2
WHERE table1.ID = table2.ID) < sysdate
 

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

Комментарии:

1. Вы могли бы рассмотреть другие варианты, предложенные в этом потоке AskTom: asktom.oracle.com/pls/asktom /…

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

3. Многопользовательская среда также может помешать этому варианту.

Ответ №1:

Пара вещей… Во-первых, если ваши таблицы имеют первичные ключи, то это, вероятно, будет предпочтительной методологией обновления:

 update (
  select
    t1.comment c1, t2.comment c2
  from
    table1 t1,
    table2 t2
  where
    t1.id = t2.id and
    t2.updateTime < sysdate
)
set
  c1 = c2
 

Во-вторых, предполагая, что UpdateTime означает то, что я думаю, что это означает, разве оно не всегда будет меньше, чем sysdate? Есть ли причина для этого?

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

 update (
  select
    t1.comment c1, t2.comment c2
  from
    table1 t1,
    table2 t2
  where
    t1.id = t2.id and
    t2.updateTime < sysdate and
  ((t1.comment is null and t2.comment is not null) or
   (t1.comment is not null and t2.comment is null) or
    t1.comment != t2.comment)
)
set
  c1 = c2
 

Наконец, я не говорю, что цикл НИКОГДА не поможет, но я говорю, что это, как правило, неправильный подход. Oracle настроен на такие вещи. Если ваш запрос на обновление выполняется медленно, сомнительно, что его включение в процедурный цикл ускорит его выполнение. Обновление миллионов строк не должно быть проблемой для хорошо настроенной базы данных Oracle.

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

Комментарии:

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

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

3. Я понимаю, что вы говорите, и мне нужно будет посмотреть, что говорит мой наставник в понедельник. Вы заставляете меня задуматься, насколько разделение обновления более эффективно, если оно вообще есть.

4. С уважением, я думаю, что ограничение администратора базы данных немного жестковато. Тем не менее, вы также можете просто добавить ограничение во внутренний запрос, чтобы выполнять только 50 000 строк одновременно (число строк <= 50000) и запускать обновление, пока оно не вернет обновленные нулевые строки… Кроме того, теперь я понимаю, что такое sysdate. В вашем исходном сообщении говорилось, что его можно заменить; Я просто пропустил это.

5. как только я выясню, почему «t1.comment != t2.comment» выдает «несовместимые типы данных: ожидаемый сбой, несовместимые типы данных: ожидаемый% s получил%s», когда они оба, очевидно, являются clobs, и другие условия работают. Ваш запрос выполняется на 91 строке, а мой, выполняемый на всех 7000 в тестовой среде, может убедить всех, что цикл не нужен.