Непонятно, что вам нужно сделать.
- Заменить всю таблицу - заполнить новую таблицу, а затем поменять местами
- Изменить один столбец для всех строк - Звучит как неряшливо дизайн. Пожалуйста, поясните, что вы делаете.
- Измените один столбец для некоторых строк - то же самое.
- Добавление нового столбца и его инициализация - Рассмотрите возможность создания параллельной таблицы и т.д. c. Это будет иметь нулевую блокировку, но усложнит ваш код.
- Значения вычисляются из других столбцов - рассмотрим «сгенерированный» столбец. (Какую версию MySQL вы используете?)
Вот обсуждение того, как пройти по таблице с помощью PRIMARY KEY
и минимизировать влияние на другие запросы: http://mysql.rjweb.org/doc.php/deletebig#deleting_in_chunks (Он написан с учетом DELETE
, но принцип применим и к UPDATE
)
Доступность таблицы
При любой операции При этом соответствующие строки «блокируются», чтобы другие запросы не могли изменять их одновременно. («Блокировка включает в себя управление несколькими версиями, et c, et c.) Они должны оставаться заблокированными до тех пор, пока не будет завершена вся« транзакция ». Между тем, любые изменения должны быть записаны на случай сбоя сервера или пользователя решает «откатить» изменения.
Итак, если изменяются миллионы строк, то удерживаются миллионы блокировок. Это требует времени.
Мой блог рекомендует делать только 1000 строк за раз; это обычно достаточно небольшое количество, чтобы иметь очень небольшое влияние на другие задачи, но достаточно большое, чтобы завершить задачу за разумный промежуток времени.
Stock Split
Предполагая, что желаемый запрос (к огромной таблице) имеет вид
UPDATE t
SET price = 2 * price
WHERE date < '...'
AND ticker = '...'
Вам нужен индекс (или, возможно, PRIMARY KEY
), равный (ticker, date)
. Большинство записи ориентированы на дату, но большинство операций чтения ориентировано на тикер? Учитывая это, следующее может быть оптимальным:
PRIMARY KEY(ticker, date),
INDEX(date, ticker)
При этом строки, которые необходимо изменить с помощью UPDATE
, - это ' кластеризованный '( последовательный) в BTree данных. Следовательно, есть некоторая степень эффективности. Если, однако, этого недостаточно, тогда будет довольно легко написать код вроде:
date_a = SELECT MIN(date) FROM t WHERE ticker = ?
SET AUTOCOMMIT=ON
Loop
date_z = date_a + 1 month
UPDATE t
SET price = 2 * price
WHERE date >= ? -- put date_a here
AND date < ? -- put date_z here
AND ticker = '...'
check for deadlock; if found, re-run the UPDATE
set date_a = date_z
exit loop when finished
End Loop
Это будет достаточно быстро и мало повлияет на другие запросы. Однако, если кто-то смотрит на этот тикер в течение ряда дней, цены могут не обновляться постоянно. (Если это вас беспокоит, мы можем обсудить дальше.)