我有一个带有表 (
A
) 的 MySql 数据库(数据库 data
),我想将所有这些数据移动到另一个 MySql 数据库(数据库 reading
)中的新表 (B
) 中。
data
和 reading
具有不同的结构,因此我不能仅将表 mysqldump 到新数据库中。我当前的方法(有效)需要超过一天的时间。这是查询:
CREATE `uspInsertIgnoreDataInBatches`()
BEGIN
DECLARE start_index INT DEFAULT 0;
DECLARE batch_size INT DEFAULT 100000;
DECLARE total_rows INT;
-- Get the total count of rows
SELECT COUNT(*) INTO total_rows
FROM A.data
LEFT JOIN A.device_sensor ON data.device_sensor_id = device_sensor.id
LEFT JOIN A.sensors ON sensors.id = device_sensor.sensor_id;
-- Loop until all rows are processed
WHILE start_index < total_rows DO
BEGIN
-- Insert data in batches
INSERT IGNORE INTO B.reading (Id, RecordedAtMT, SensorId, LocationId, SensorValue)
SELECT data.id, data.datetime, sensors.id as sensor_id, data.location_id, data.value
FROM A.data
LEFT JOIN A.device_sensor ON data.device_sensor_id = device_sensor.id
LEFT JOIN A.sensors ON sensors.id = device_sensor.sensor_id
ORDER BY A.data.datetime DESC
LIMIT batch_size OFFSET start_index;
END;
-- Move to the next batch
SET start_index = start_index + batch_size;
END WHILE;
END
注意:使用
INSERT IGNORE
是因为前一个表中的行将违反新表的唯一约束。
我正在寻找任何能够使此操作尽可能快速高效的解决方案,谢谢。
SELECT INTO OUTFILE
然后使用LOAD DATA LOCAL INFILE
,你当然可以让你的SP更有效率。
我们没有有关表的数据量或 DDL 的信息,但时间尺度表明数据集“非常大”。大偏移量的分页可能会非常慢,因此使用 id(假设它是 INT PK)会产生显着的差异。 这是 SP 的修改(且未经测试)版本:
DELIMITER $$
CREATE PROCEDURE `uspInsertIgnoreDataInBatches`()
BEGIN
DECLARE max_id INT DEFAULT 0;
DECLARE batch_size INT DEFAULT 10000;
DECLARE max_src_id INT;
-- Get the total count of rows
SELECT MAX(id) INTO max_src_id
FROM A.data;
-- Loop until all rows are processed
WHILE max_id < max_src_id DO
-- Insert data in batches
INSERT IGNORE INTO B.reading (Id, RecordedAtMT, SensorId, LocationId, SensorValue)
SELECT data.id, data.datetime, device_sensor.sensor_id as sensor_id, data.location_id, data.value
FROM A.data
LEFT JOIN A.device_sensor ON data.device_sensor_id = device_sensor.id
WHERE A.data.id > max_id
ORDER BY A.data.id ASC
LIMIT batch_size;
-- Move to the next batch
SELECT MAX(Id) INTO max_id FROM B.reading;
END WHILE;
END$$
如果您不需要将其写入二进制日志,您也可以使用
set sql_log_bin = 0;
禁用它,假设定义者具有超级权限。