#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 в тестовой среде, может убедить всех, что цикл не нужен.