предисловие
Пожалуйста, используйте Вставить в выбор с осторожностью. В этот день xxx получил запрос на перенос данных из таблицы A в таблицу B для резервного копирования. Хотел сначала через программу проверить, а потом уже пачками вставлять. Но xxx посчитал, что это немного медленно и требует много сетевого ввода-вывода, и решил использовать другой метод для его реализации. Плавая в океанах Baidu, он обнаружил, что может использоватьinsert into selectРеализовано так, что вы можете избежать использования сетевого ввода-вывода и полагаться на ввод-вывод базы данных напрямую с помощью SQL, что просто не очень хорошо. Затем его уволили.
Произошла авария.
По данным в базеorder_todayОбъем данных слишком велик, кажется, что в то время он составлял 700 Вт, и он увеличивается со скоростью 30 Вт каждый день. Итак, босс приказал хххorder_todayЧасть данных при миграции наorder_record, и воляorder_todayУдаление данных в . это уменьшаетorder_todayКоличество данных в таблице.
Учитывая, что ввод-вывод БД будет занят, чтобы не влиять на бизнес, планирую начать миграцию после 9:00, но в 8:00 ххх попытался мигрировать небольшую часть данных (1000 записей ), и почувствовал, что проблемы нет, просто начните думать о массовых миграциях.
- В процессе миграции группа экстренной помощи сначала ответила, что небольшое количество пользователей не заплатили, а затем ответила большому количеству пользователей, которые не заплатили и не инициализировали заказы.В то же время Tencent также начала сообщать в полицию.
- Тогда ххх запаниковал и сразу остановил миграцию.
Я думал, что если остановлю миграцию, то смогу восстановиться, но не тут-то было. Вы можете составить свое мнение о том, что произошло дальше.
восстановление после аварии
Создайте компактную версию базы данных локально и сгенерируйте 100 Вт данных. Моделируйте то, что происходит в Интернете.
создать структуру таблицы
форма заказа
CREATE TABLE `order_today` (
`id` varchar(32) NOT NULL COMMENT '主键',
`merchant_id` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '商户编号',
`amount` decimal(15,2) NOT NULL COMMENT '订单金额',
`pay_success_time` datetime NOT NULL COMMENT '支付成功时间',
`order_status` varchar(10) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '支付状态 S:支付成功、F:订单支付失败',
`remark` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '备注',
`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间 -- 修改时自动更新',
PRIMARY KEY (`id`) USING BTREE,
KEY `idx_merchant_id` (`merchant_id`) USING BTREE COMMENT '商户编号'
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Бланк записи заказа
CREATE TABLE order_record like order_today;
Данные таблицы заказов на сегодня
Моделирование миграции
Перенести все данные до 8 числа вorder_recordиди к столу.
INSERT INTO order_record SELECT
*
FROM
order_today
WHERE
pay_success_time < '2020-03-08 00:00:00';
Запустите перенесенный sql в navicat, откройте другое окно для одновременной вставки данных и смоделируйте размещение заказа.
Из вышеизложенного видно, что в начале можно нормально вставлять, но вдруг застревает, и на успех уходит 23с, а потом можно продолжать вставлять. На данный момент миграция прошла успешно, поэтому ее можно нормально вставить.
Причина появления
При уровне изоляции транзакций по умолчанию:insert into order_record select * from order_todayПравила блокировки:order_recordзамок стола,order_todayПрогрессивные замки (сканирование замков один за другим).
Проанализируйте процесс исполнения.
Наблюдаяперенести sqlреализации вы найдетеorder_todayЭто полное сканирование таблицы, что означает, что выполняетсяinsert into select fromзаявление, mysql будет сканировать сверху внизorder_todayЗаписи в нем блокируются и блокируются, так что это не то же самое, что блокировать напрямую таблицу.
Это также может объяснить, почему только небольшое количество пользователей не смогло заплатить в начале, а затем большое количество пользователей не смогло заплатить, не смогло инициализировать заказы и т. д. Поскольку в начале была заблокирована лишь небольшая часть данных, данные, которые не были заблокированы, все еще могут быть изменены в обычном режиме. Поскольку блокируется все больше и больше данных, происходит большое количество сбоев при оплате. Наконец, все заблокировано, что приводит к невозможности вставить заказ и сбою его инициализации.
решение
Из-за условий запросаorder_todayПолное сканирование таблицы, что может избежать полного сканирования таблицы, очень просто, дайтеpay_success_timeдобавить полеidx_pay_suc_timeпоказательВот и все, поскольку используется индексный запрос, таблица не будет заблокирована из-за сканирования всей таблицы, а будут заблокированы только те записи, которые удовлетворяют условиям.
окончательный sql
INSERT INTO order_record SELECT
*
FROM
order_today FORCE INDEX (idx_pay_suc_time)
WHERE
pay_success_time <= '2020-03-08 00:00:00';
Процесс реализации
Суммировать
использоватьinsert into tablA select * from tableBзаявление, обязательноtableBНазадwhere,orderили другие условия, необходимо иметь соответствующиепоказатель, чтобы избежатьtableBВсе записи заблокированы.
Справочная статья
конец
Если вы думаете, что это полезно для вас, вы можете прокомментировать и понравиться больше, или вы можете пойти на свою домашнюю страницу, чтобы увидеть, может быть, есть статья, которую вам нравится, вы также можете просто следовать за ним, спасибо.