Поиск по NULL при обновлении таблицы
От: Буравчик Россия  
Дата: 13.02.21 13:40
Оценка:
В таблице много записей. Добавлена новая колонка со значением NULL.

Нужно присвоить новое значение этой колонке в каждой строке. Для этого много раз выполняется следующий код:
UPDATE TOP(100000) table
SET col = value
WHERE col IS NULL


Как это ускорить?

Правильно ли я понимаю, что при каждом выполнении такого кода будет выполнять скан по всей таблице, пока не найдутся NOT NULL значения. Т.е. по мере обновления таблицы скорость поиска NULL будет замедляться. Грубо говоря сложность обновления всех записей таблицы O(N^2)

Что произойдет, если добавить индекс по колонке col — индекс для поиска NULL? Ускорится выполнение обновления за счет быстрого поиска NULL, или замедлится за счет постоянного обновления индекса при обновлении таблицы?
Best regards, Буравчик
Отредактировано 13.02.2021 13:45 Буравчик . Предыдущая версия . Еще …
Отредактировано 13.02.2021 13:44 Буравчик . Предыдущая версия .
Re: Поиск по NULL при обновлении таблицы
От: B7_Ruslan  
Дата: 13.02.21 13:47
Оценка: 7 (1)
Напишите миграцию на c#/java. В таблице наверняка есть PK.
Выберите все PK в одной транзакции.
Потом в цикле делайте транзакцию для пакета и обновляйте колонку по PK.
Обработанные PK убираете из очереди.
Re[2]: Поиск по NULL при обновлении таблицы
От: Буравчик Россия  
Дата: 13.02.21 14:04
Оценка:
Здравствуйте, B7_Ruslan, Вы писали:

B_R>Напишите миграцию на c#/java. В таблице наверняка есть PK.

B_R>Выберите все PK в одной транзакции.
B_R>Потом в цикле делайте транзакцию для пакета и обновляйте колонку по PK.
B_R>Обработанные PK убираете из очереди.

Почему не на SQL? Если правильно понял:

Создаем новую временную таблицу для хранения обновляемых значений:
— id (PK) — автоинкремент
— updating_table_pk — первичный ключ обновляемой таблицы

-- непонятно как на лету создать autoincrement-поле, это возможно?
CREATE TABLE temp
AS 
  SELECT id (AS AUTOINCREMENT), table.pk AS updating_table_pk 
  FROM table
  WHERE col IS NULL

-- далее
UPDATE table
SET col = value
WHERE table.pk IN (
  SELECT updating_table_pk
  FROM temp
  WHERE id BETWEEN start AND start+batch_size
)
-- следующий батч
start := start + batch_size
Best regards, Буравчик
Re: Поиск по NULL при обновлении таблицы
От: bnk СССР http://unmanagedvisio.com/
Дата: 13.02.21 14:15
Оценка:
Здравствуйте, Буравчик, Вы писали:

Б>Правильно ли я понимаю, что при каждом выполнении такого кода будет выполнять скан по всей таблице, пока не найдутся NOT NULL значения. Т.е. по мере обновления таблицы скорость поиска NULL будет замедляться. Грубо говоря сложность обновления всех записей таблицы O(N^2)


Не понятно откуда тут N^2, тут же вроде просто один раз пройти всю таблицу, это вроде N

Не проще сделать значение по умолчанию (default) на это поле?
Кстати это можно было сделать прямо при добавлении колонки, тогда даже 1 раз не надо было бы вызвать.
Отредактировано 13.02.2021 14:16 bnk . Предыдущая версия .
Re: Поиск по NULL при обновлении таблицы
От: wildwind Россия  
Дата: 13.02.21 14:17
Оценка: 14 (1)
Здравствуйте, Буравчик, Вы писали:

Б>Как это ускорить?


1. Обновить все сразу, если возможно.

2. Использовать подходящий индекс, например по PK, если есть. Разбить множество значений ключа на диапазоны, и обновлять их в цикле.

Б>Правильно ли я понимаю, что при каждом выполнении такого кода будет выполнять скан по всей таблице, пока не найдутся NOT NULL значения. Т.е. по мере обновления таблицы скорость поиска NULL будет замедляться. Грубо говоря сложность обновления всех записей таблицы O(N^2)


Могут быть нюансы, но в общем да.

Б>Что произойдет, если добавить индекс по колонке col — индекс для поиска NULL? Ускорится выполнение обновления за счет быстрого поиска NULL, или замедлится за счет постоянного обновления индекса при обновлении таблицы?


Такой индекс при апдейте выше использоваться не будет. В обычном индексе по одной колонке null значения не сохраняются. Такая особенность реализации в Oracle.
Re[2]: Поиск по NULL при обновлении таблицы
От: Буравчик Россия  
Дата: 13.02.21 14:18
Оценка: :)
Здравствуйте, bnk, Вы писали:

bnk>Не понятно откуда тут N^2, тут же вроде просто один раз пройти всю таблицу, это вроде N


Этот update повторяется сотни/тысячи раз

bnk>Не проще сделать значение по умолчанию (default) на это поле?

bnk>Кстати это можно было сделать прямо при добавлении колонки, тогда даже 1 раз не надо было бы вызвать.

Так проще, но это надолго блокирует всю таблицу
Best regards, Буравчик
Re[3]: Поиск по NULL при обновлении таблицы
От: bnk СССР http://unmanagedvisio.com/
Дата: 13.02.21 14:27
Оценка:
Здравствуйте, Буравчик, Вы писали:

Б>Этот update повторяется сотни/тысячи раз


Понятно

bnk>>Кстати это можно было сделать прямо при добавлении колонки, тогда даже 1 раз не надо было бы вызвать.


Б>Так проще, но это надолго блокирует всю таблицу


Но добавление колонки, даже без дефолта, ее же все равно блокирует, или?
Re[4]: Поиск по NULL при обновлении таблицы
От: Буравчик Россия  
Дата: 13.02.21 14:31
Оценка: 6 (1)
Здравствуйте, bnk, Вы писали:

bnk>Но добавление колонки, даже без дефолта, ее же все равно блокирует, или?


NULL колонка не блокирует
Best regards, Буравчик
Re[2]: Поиск по NULL при обновлении таблицы
От: Буравчик Россия  
Дата: 13.02.21 14:38
Оценка:
Здравствуйте, wildwind, Вы писали:

W>Такой индекс при апдейте выше использоваться не будет. В обычном индексе по одной колонке null значения не сохраняются. Такая особенность реализации в Oracle.


Спасибо. Этот вопрос больше все интересовал.

А если обхитрить, сделать индекс из несколькиз колонок, например, (NULLABLE + PK)?
Best regards, Буравчик
Re: Поиск по NULL при обновлении таблицы
От: Ромашка Украина  
Дата: 13.02.21 14:53
Оценка:
Здравствуйте, Буравчик, Вы писали:
Б>Как это ускорить?

Это не ускорить.

Б>Правильно ли я понимаю, что при каждом выполнении такого кода будет выполнять скан по всей таблице, пока не найдутся NOT NULL значения. Т.е. по мере обновления таблицы скорость поиска NULL будет замедляться. Грубо говоря сложность обновления всех записей таблицы O(N^2)


Неа. Там время поиска будет слишком малым по сравнению со временем записи новых данных.

Б>Что произойдет, если добавить индекс по колонке col — индекс для поиска NULL? Ускорится выполнение обновления за счет быстрого поиска NULL, или замедлится за счет постоянного обновления индекса при обновлении таблицы?


Ускорится, за счет ускорения чтения блоков. Индекс компактнее таблицы, поэтому контроллер его тупо быстрее почитает в память.

Но самое главное — блокировка будет накладываться на индекс, а не на таблицу. Я подозреваю, что проблема как раз в блокировке, а не во времени обновления. Поэтому:

1. Добавляем новый столбец.
2. Создаем на него индекс.
3. Делаем update table set newcol = value без where или top N.

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


Всё, что нас не убивает, ещё горько об этом пожалеет.
Re[2]: Поиск по NULL при обновлении таблицы
От: Буравчик Россия  
Дата: 13.02.21 15:06
Оценка:
Здравствуйте, Ромашка, Вы писали:

Р>1. Добавляем новый столбец.

Р>2. Создаем на него индекс.
Р>3. Делаем update table set newcol = value без where или top N.

Разве в этом случае не будет заблокирована каждая строка таблицы до завершения обновления? Что-то слабо верится.

И индекс на это не влияет, вроде
Best regards, Буравчик
Re[3]: Поиск по NULL при обновлении таблицы
От: wildwind Россия  
Дата: 13.02.21 15:11
Оценка:
Здравствуйте, Буравчик, Вы писали:

Б>А если обхитрить, сделать индекс из несколькиз колонок, например, (NULLABLE + PK)?


Заставить Oracle использовать индекс можно, но выигрыша, скорее всего не будет. Вероятно будет проигрыш.


Если регламент позволяет даунтайм и нет прочих ограничений (типа FK, которые нельзя трогать по другим причинам), наиболее быстрый способ все провернуть это CTAS, create table as select в новую таблицу, с нумерацией из сиквенса, с order by в нужном порядке.
Re[2]: Поиск по NULL при обновлении таблицы
От: wildwind Россия  
Дата: 13.02.21 15:14
Оценка: +1
Здравствуйте, Ромашка, Вы писали:

Р>Но самое главное — блокировка будет накладываться на индекс, а не на таблицу.


С чего это? И на таблицу, и на индекс.

Р>3. Делаем update table set newcol = value без where или top N.


Если бы value было константой, и update не нужен был бы. Ему же нужно пронумеровать строки.
Re[3]: Поиск по NULL при обновлении таблицы
От: Буравчик Россия  
Дата: 13.02.21 15:22
Оценка:
Здравствуйте, wildwind, Вы писали:

W>Если бы value было константой, и update не нужен был бы. Ему же нужно пронумеровать строки.


Не совсем пронумеровать, но близко. К таблице добавляется альтернативный ключ.
Best regards, Буравчик
Re[3]: Поиск по NULL при обновлении таблицы
От: Ромашка Украина  
Дата: 13.02.21 17:29
Оценка:
Здравствуйте, wildwind, Вы писали:
Р>>Но самое главное — блокировка будет накладываться на индекс, а не на таблицу.
W>С чего это? И на таблицу, и на индекс.

А на таблицу-то зачем? Я не большой специалист по блокировкам в оракле, но чет мне быстрый гуглинг подсказывает, что блокировки на таблицу не будет. Не вижу причин для нее.

Р>>3. Делаем update table set newcol = value без where или top N.

W>Если бы value было константой, и update не нужен был бы. Ему же нужно пронумеровать строки.

Да пофиг. Если может с топ, значит сможет и без топ.


Всё, что нас не убивает, ещё горько об этом пожалеет.
Re[3]: Поиск по NULL при обновлении таблицы
От: Dym On Россия  
Дата: 13.02.21 18:44
Оценка: 7 (1)
Здравствуйте, Буравчик, Вы писали:

-- непонятно как на лету создать autoincrement-поле, это возможно?
CREATE TABLE temp
AS 
  SELECT rownum  as id , table.pk AS updating_table_pk 
..
Счастье — это Glück!
Re[4]: Поиск по NULL при обновлении таблицы
От: Буравчик Россия  
Дата: 14.02.21 10:10
Оценка:
Здравствуйте, Ромашка, Вы писали:

Р>А на таблицу-то зачем? Я не большой специалист по блокировкам в оракле, но чет мне быстрый гуглинг подсказывает, что блокировки на таблицу не будет. Не вижу причин для нее.


Можно ссылку из гугла?

Я думаю, что перед обновлением таблицы СУБД наложит эксклюзивную блокировку на каждую запись таблицы.
И скорее всего, СУБД, видя, что заблокированы все записи, наложит блокировку на всю таблицу целиком, т.е. таблица будет полностью заблокирована и на чтение тоже.

Вроде, по-умолчанию так и в Oracle, и в MSSQL (инфа из интернета). Интересно, а как в Postgres будет?
Best regards, Буравчик
Re[2]: Поиск по NULL при обновлении таблицы
От: Буравчик Россия  
Дата: 14.02.21 10:17
Оценка:
Здравствуйте, wildwind, Вы писали:

W>Могут быть нюансы, но в общем да.


Сделал замеры, "квадратичность" проявляется. И уже после 20 млн записей выгоднее создать индекс (см. ниже).

W>Такой индекс при апдейте выше использоваться не будет. В обычном индексе по одной колонке null значения не сохраняются. Такая особенность реализации в Oracle.


Помог BITMAP индекс по NULL колонке, квадратичность ушла.

Вернее, почти ушла, чуток осталось (судя по замерам). Если правильно понял, то из-за того, что BITMAP можно создать только локальным, то при работе с таким индексом просматриваются повторно индекс в уже обработанных партициях.
Best regards, Буравчик
Re[5]: Поиск по NULL при обновлении таблицы
От: wildwind Россия  
Дата: 14.02.21 13:14
Оценка:
Здравствуйте, Буравчик, Вы писали:

Б>Я думаю, что перед обновлением таблицы СУБД наложит эксклюзивную блокировку на каждую запись таблицы.


Не на каждую, а на каждую изменяемую. И не всегда "перед", иногда "в процессе".

Б>И скорее всего, СУБД, видя, что заблокированы все записи, наложит блокировку на всю таблицу целиком, т.е. таблица будет полностью заблокирована и на чтение тоже.


Нет. Заблокировать таблицу на чтение в Oracle практически невозможно.
Re[3]: Поиск по NULL при обновлении таблицы
От: wildwind Россия  
Дата: 14.02.21 13:16
Оценка:
Здравствуйте, Буравчик, Вы писали:

Б>Помог BITMAP индекс по NULL колонке, квадратичность ушла.


Ну OK. После обновления можно его удалить, т.к. в других ситуациях он вряд ли будет полезен.
Re[4]: Поиск по NULL при обновлении таблицы
От: wildwind Россия  
Дата: 14.02.21 13:21
Оценка:
Здравствуйте, Ромашка, Вы писали:

Р>А на таблицу-то зачем? Я не большой специалист по блокировкам в оракле, но чет мне быстрый гуглинг подсказывает, что блокировки на таблицу не будет. Не вижу причин для нее.


Я, разумеется, имел в виду блокировку строк таблицы (и индекса). На всю таблицу блокировки тоже накладываются, но разделяемые.
Re[6]: Поиск по NULL при обновлении таблицы
От: Буравчик Россия  
Дата: 14.02.21 15:21
Оценка:
Здравствуйте, wildwind, Вы писали:

W>Не на каждую, а на каждую изменяемую. И не всегда "перед", иногда "в процессе".


У меня отрывистые знания про блокировки.

Не понял, если мы делаем update table set col = seq.nextval для всех строк одновременно, то какие строки будут заблокированы и когда?

Будет ли доступно в других транзакция чтение строк, изменение, удаление и добавление?
Как из из этих операций будут доступны? Желательно про oracle, но можно и в общем

P.S. Посоветуйте литературу про блокировки и лучшие практики
Best regards, Буравчик
Отредактировано 14.02.2021 20:14 Буравчик . Предыдущая версия .
Re[7]: Поиск по NULL при обновлении таблицы
От: vladislav_somov Россия  
Дата: 15.02.21 14:20
Оценка: 14 (1)
Здравствуйте, Буравчик, Вы писали:

Слишком общие вопросы, чтобы на них ответить однозначно.

Б>Не понял, если мы делаем update table set col = seq.nextval для всех строк одновременно, то какие строки будут заблокированы и когда?


Сначала будут блокироваться строки по мере доступа к ним, а потом будет выполнена эскалация блокировки на всю таблицу, когда количество заблокированных строк превысит некую величину.
(В перечеркнутом ошибка вышла, это не про oracle, а про sql server).

Б>Будет ли доступно в других транзакция чтение строк, изменение, удаление и добавление?

Б>Как из из этих операций будут доступны? Желательно про oracle, но можно и в общем

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

Б>P.S. Посоветуйте литературу про блокировки и лучшие практики


Опять же, если для oracle, то вот:
https://www.ozon.ru/context/detail/id/6311145/
следующее издание:
https://www.ozon.ru/context/detail/id/149325770/?stat=YW5fMQ%3D%3D

По SQL Server я на амазон брал.
Для oracle там тоже есть:
https://www.amazon.com/Oracle-Database-Transactions-Locking-Revealed/dp/148426424X/ref=sr_1_11?dchild=1&keywords=oracle&qid=1613398599&s=books&sr=1-11
Отредактировано 15.02.2021 18:10 vladislav_somov . Предыдущая версия . Еще …
Отредактировано 15.02.2021 18:07 vladislav_somov . Предыдущая версия .
Re[8]: Поиск по NULL при обновлении таблицы
От: wildwind Россия  
Дата: 15.02.21 17:21
Оценка: 7 (2)
Здравствуйте, vladislav_somov, Вы писали:

_>а потом будет выполнена эскалация блокировки на всю таблицу, когда количество заблокированных строк превысит некую величину.


В Oracle такого не будет.
Re[7]: Поиск по NULL при обновлении таблицы
От: wildwind Россия  
Дата: 15.02.21 17:39
Оценка:
Здравствуйте, Буравчик, Вы писали:

Б>Не понял, если мы делаем update table set col = seq.nextval для всех строк одновременно, то какие строки будут заблокированы и когда?


Если меняются все строки, значит все и будут заблокированы. Насчет "когда именно" могут быть нюансы реализации, но обычно они блокируются по мере выборки и изменения.

Б>Будет ли доступно в других транзакция чтение строк, изменение, удаление и добавление?

Б>Как из из этих операций будут доступны? Желательно про oracle, но можно и в общем

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

Б>P.S. Посоветуйте литературу про блокировки и лучшие практики


Буду банален и посоветую начать с документации.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.