Гость
Map
Форумы / Oracle [игнор отключен] [закрыт для гостей] / аск фор кодривью :) / 25 сообщений из 71, страница 1 из 3
24.11.2021, 11:48
    #40114471
legg
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
аск фор кодривью :)
Научите уму-разуму, как надо было делать и что плохого в моей реализации.

Постановка задачи:
есть табл tablitchka с количеством записей 1 000 000 000. В таблице нет индексов кроме первичного ключа
Требуется проапдейтить таблицу по условию COND (условие на неиндексированные поля) установив поле kolonka в 1, прогнозируемое количество попадающих под апдейт - 10 000 000.

Мое решение:
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
declare
 
   type tp is record (rid rowid, id number);
   type tAr is table of tp;
   ar tar;
   cursor c is
   select t.rowid, t.id from
   tablitchka t
   where /*условие COND*/
    .. and kolonka = 0;               
begin
  open c;
  loop
     fetch c bulk collect  into ar limit 10000; 
     forall i in 1..ar.count save exceptions
     
     update
     tablitchka  --
     SET kolonka = 1 where rowid = ar(i).rid and id = ar(i).id;
     cnt := cnt + sql%rowcount;
     commit;
     exit when c%notfound;
  end loop;
 
  close c; 
 
exception when others then
   null;    
end;



не очень мне нравится, но это единственный вариант который смог извергнуть. Прошу критики и рассказа о правильном подходе
...
Рейтинг: 0 / 0
24.11.2021, 11:54
    #40114472
AmKad
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
аск фор кодривью :)
ctas [+partitioning] + rename + grants.
...
Рейтинг: 0 / 0
24.11.2021, 12:02
    #40114474
Stax
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
аск фор кодривью :)
legg,

если
напр kolonka = 2 проапдейтить надо?


ps
имхо
если есть условие по ровид, то по ид лишнее

.....
stax
...
Рейтинг: 0 / 0
24.11.2021, 12:05
    #40114475
legg
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
аск фор кодривью :)
AmKad
ctas
- отказался от такого варианта, тк решил что на работающей базе (таблица активно используется другими сессиями) так не прокатит. важное уточнение - забыл сразу дописать
...
Рейтинг: 0 / 0
24.11.2021, 12:16
    #40114479
legg
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
аск фор кодривью :)
Stax
legg,

если
напр kolonka = 2 проапдейтить надо?
stax

нет
Stax

ps
имхо
если есть условие по ровид, то по ид лишнее

.....
stax

имхо тоже, коллега вцепился зубами в ногу, боится что у записи rowid поменяется в одном случае из стотыщмиллионов. Надеюсь это успокоит
...
Рейтинг: 0 / 0
24.11.2021, 12:52
    #40114489
Stax
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
аск фор кодривью :)
legg

имхо тоже, коллега вцепился зубами в ногу, боится что у записи rowid поменяется в одном случае из стотыщмиллионов. Надеюсь это успокоит

допустим поменяется ровид и ....

тогда условие rowid = ar(i).rid and id = ar(i).id; не отработает (0 на 1 не поменяется)

ps
есть save exceptions, а обработка за циклом

....
stax
...
Рейтинг: 0 / 0
24.11.2021, 13:16
    #40114498
AmKad
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
аск фор кодривью :)
legg
отказался от такого варианта, тк решил что на работающей базе (таблица активно используется другими сессиями) так не прокатит. важное уточнение - забыл сразу дописать
Есть вариант похардовее.

1) С учетом того, таблица, как и любой сегмент, состоит из экстентов, в цикле с помощью dbms_rowid получаешь первый и последний rowid для каждого экстента и делаешь update по условию
Код: plsql
1.
where your_fucking_condition and rowid between r_begin and r_end

например, с фиксацией транзакции после каждого или N-го экстента.
2) Делаешь финальный update-скан по всей таблице только для тех записей, что были добавлены или мигрированы с момента старта этапа 1 и для которых выполняется условие
Код: plsql
1.
where your_fucking_condition and lnnvl(kolonka = 1)


Какой в этом профит в сравнении с твоим вариантом - не нужно вычитывать таблицу перед обновлением.
...
Рейтинг: 0 / 0
24.11.2021, 13:30
    #40114502
legg
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
аск фор кодривью :)
Stax
legg

имхо тоже, коллега вцепился зубами в ногу, боится что у записи rowid поменяется в одном случае из стотыщмиллионов. Надеюсь это успокоит

допустим поменяется ровид и ....

тогда условие rowid = ar(i).rid and id = ar(i).id; не отработает (0 на 1 не поменяется)

ps
есть save exceptions, а обработка за циклом

....
stax

да, верное замечание. просто долго описывать все нюансы. логика - 'если случилась неведомая фигня - лучше ничего трогать не буду, надо ручками разбирать что там.' - в данном случае так можно. и вместо null в обработчике логирование варнинга идет
...
Рейтинг: 0 / 0
24.11.2021, 13:32
    #40114503
legg
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
аск фор кодривью :)
AmKad
legg
отказался от такого варианта, тк решил что на работающей базе (таблица активно используется другими сессиями) так не прокатит. важное уточнение - забыл сразу дописать
Есть вариант похардовее.

1) С учетом того, таблица, как и любой сегмент, состоит из экстентов, в цикле с помощью dbms_rowid получаешь первый и последний rowid для каждого экстента и делаешь update по условию
Код: plsql
1.
where your_fucking_condition and rowid between r_begin and r_end


например, с фиксацией транзакции после каждого или N-го экстента.
2) Делаешь финальный update-скан по всей таблице только для тех записей, что были добавлены или мигрированы с момента старта этапа 1 и для которых выполняется условие
Код: plsql
1.
where your_fucking_condition and lnnvl(kolonka = 1)



Какой в этом профит в сравнении с твоим вариантом - не нужно вычитывать таблицу перед обновлением.


крутокрутокруто! попробую. сейчас оставлю так, а в след релизе глядишь и эту версию выпущу. на сам деле я чего то подобного и хотел, не знал как реализовать.
...
Рейтинг: 0 / 0
24.11.2021, 14:06
    #40114518
Stax
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
аск фор кодривью :)
legg

вместо null в обработчике логирование варнинга идет


я не про null

я про место обработки, следующие 10000 не обработаются если была "ошибка"


зы
я так понимаю ето разовая операция,
"оптимизация" займет больше времени чем проапдейтить 10млн
stax
...
Рейтинг: 0 / 0
24.11.2021, 14:19
    #40114520
legg
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
аск фор кодривью :)
[quot Stax#22400192]
legg

вместо null в обработчике логирование варнинга идет


я не про null

я про место обработки, следующие 10000 не обработаются если была "ошибка"


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

попытался связанно объяснить, но не уверен что вышло).

Stax

"зы
я так понимаю ето разовая операция,
"оптимизация" займет больше времени чем проапдейтить 10млн
stax " stax
- нет. ежедневно по паре десятков таблиц. с перспективой увеличения количества как таблиц так и их объемов.
...
Рейтинг: 0 / 0
24.11.2021, 14:34
    #40114528
andrey_anonymous
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
аск фор кодривью :)
legg
по полю kolonka идет партиционирование. конечная цель - перенос из исходной таблицы в целевую неактуальных данных (архивировать то есть) на лету, без техперерывов всяких.

Через row movement?
Мсье знает толк в извращениях.

https://docs.oracle.com/en/database/oracle/oracle-database/19/vldbg/manage-data-db-ilm.html#GUID-C53B27F1-7E71-4683-A2A0-3DE194A59C2E
...
Рейтинг: 0 / 0
24.11.2021, 14:40
    #40114530
legg
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
аск фор кодривью :)
andrey_anonymous
legg
по полю kolonka идет партиционирование. конечная цель - перенос из исходной таблицы в целевую неактуальных данных (архивировать то есть) на лету, без техперерывов всяких.

Через row movement?
Мсье знает толк в извращениях.

согласен. через row movement естественно. не я это придумал. но реализовываю -я). а тут грабля на грабле.
...
Рейтинг: 0 / 0
24.11.2021, 14:46
    #40114533
legg
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
аск фор кодривью :)


первый раз вижу о такой возможности. вечером почитаю. спасибо огромное!
...
Рейтинг: 0 / 0
24.11.2021, 14:52
    #40114537
legg
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
аск фор кодривью :)
legg


первый раз вижу о такой возможности. вечером почитаю. спасибо огромное!

толи я не туда смотрю, но только я че та не уверен что тут есть то что надо. архивировать можно записи по довольно сложным условиям. к примеру документы могут архивироваться только после того как закрыт соответствующий счет (и еще ряд условий). такие условия разве можно политиками описать? или я не туда поперся?
кажется то что надо. буду вкуривать.
...
Рейтинг: 0 / 0
24.11.2021, 14:57
    #40114538
Stax
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
аск фор кодривью :)
legg

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


имхо
тогда и мало смысла в save exceptions

.....
stax
...
Рейтинг: 0 / 0
24.11.2021, 14:58
    #40114539
legg
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
аск фор кодривью :)
Stax
legg

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


имхо
тогда и мало смысла в save exceptions

.....
stax

я там ругаюсь)
...
Рейтинг: 0 / 0
24.11.2021, 16:14
    #40114571
kapelan
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
аск фор кодривью :)
А зачем вообше такая странная логика:
1. Скопировать втаблицу в память
2. Сканировать таблицу в памяти
3. Апдейтить оригинальную таблицу
Вроде-как по всем книжкам гораздо быстрее работать напрямую
...
Рейтинг: 0 / 0
24.11.2021, 16:30
    #40114587
andrey_anonymous
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
аск фор кодривью :)
kapelan
Вроде-как по всем книжкам гораздо быстрее работать напрямую

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

Если натравить update на большую меняющуюся таблицу с ограничителем по числу строк (...and rownum < :BatchSize), то FTS будет бегать каждый запуск. При этом конкуренция и statement restart тоже никуда не денутся.

Примечение: В случае ТС если "самопалить", то надо гонять не update, а delete...returning с последующим выходом на forall insert, это будет дешевле update+row_movement.
Впрочем, означенные выше проблемы delete-у тоже свойственны.


Есть вариант распараллелить dml несколько снижая проблемы с конкуренцией, но не уверен что ТС это надо.

На круг предложенный вариант с разбиением работы на части посредством предварительного анализа таблицы экстентов вполне себе неплох.
...
Рейтинг: 0 / 0
24.11.2021, 16:40
    #40114593
kapelan
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
аск фор кодривью :)
andrey_anonymous
kapelan
Вроде-как по всем книжкам гораздо быстрее работать напрямую

Прямая прямой рознь....

это все понятно, тока переложить большую таблицу в другое место тоже не быстрая операция ... потом сканировать ее в памяти ...
Грубо говоря получаем двойной фулл скан большой таблицы.
Я бы посмотрел в в сторону мат. вью: навесить на него нужные индексы и делать поиск по индексам.
Таким образом получаем поиск по индексу в мат. вью и UPDATE таблицы по PRIMARY KEY
...
Рейтинг: 0 / 0
24.11.2021, 16:47
    #40114598
andrey_anonymous
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
аск фор кодривью :)
kapelan
переложить большую таблицу в другое место тоже не быстрая операция ... потом сканировать ее в памяти ...

Это о чем?
...
Рейтинг: 0 / 0
24.11.2021, 17:05
    #40114607
kapelan
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
аск фор кодривью :)
andrey_anonymous
kapelan
переложить большую таблицу в другое место тоже не быстрая операция ... потом сканировать ее в памяти ...

Это о чем?


Код: plsql
1.
2.
     fetch c bulk collect  into ar limit 10000; 
     forall i in 1..ar.count save exceptions
...
Рейтинг: 0 / 0
24.11.2021, 17:15
    #40114611
legg
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
аск фор кодривью :)
kapelan
andrey_anonymous
пропущено...

Это о чем?


Код: plsql
1.
2.
     fetch c bulk collect  into ar limit 10000; 
     forall i in 1..ar.count save exceptions


или я чего то не понимаю или выглядит так, что вы сравниваете скорость чтения с диска данных таблицы и скорость перебора массива в оперативной памяти.
...
Рейтинг: 0 / 0
24.11.2021, 17:21
    #40114615
legg
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
аск фор кодривью :)
kapelan
andrey_anonymous
пропущено...

Прямая прямой рознь....

это все понятно, тока переложить большую таблицу в другое место тоже не быстрая операция ... потом сканировать ее в памяти ...
Грубо говоря получаем двойной фулл скан большой таблицы.
Я бы посмотрел в в сторону мат. вью: навесить на него нужные индексы и делать поиск по индексам.
Таким образом получаем поиск по индексу в мат. вью и UPDATE таблицы по PRIMARY KEY

вопрос в том как одним махом проапдейтить 10 000 000 строк. база не в монопольном доступе, очередные 10000000 записей как раз в таблицу инсертятся в это время. а чуть позже - апдейтятся. даже если конкуренций не случится -снапшот ту олд практически гарантирован ведь при прямом апдейте всего сразу?
...
Рейтинг: 0 / 0
24.11.2021, 17:30
    #40114620
booby
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
аск фор кодривью :)
legg
...
или я чего то не понимаю или выглядит так, что вы сравниваете скорость чтения с диска данных таблицы и скорость перебора массива в оперативной памяти.

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

Кроме того, с транзакционной точки зрения, вы совершаете логическую ошибку,
не блокируя прочитанные вашим первым чтением данные.
После исключения логических ошибок ваш код, может быть, просто поставит базу колом на какое-то количество часов.
...
Рейтинг: 0 / 0
Форумы / Oracle [игнор отключен] [закрыт для гостей] / аск фор кодривью :) / 25 сообщений из 71, страница 1 из 3
Целевая тема:
Создать новую тему:
Автор:
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]