问题描述
|
模式
我有一个带有一个大表的MysqL数据库(说500万行)。该表具有几个用于实际数据的字段,一个可选的注释字段以及用于记录何时首次添加该行以及何时删除该数据的字段。为了简化为一个“数据”列,它看起来像这样:
+----+------+---------+---------+----------+
| id | data | comment | created | deleted |
+----+------+---------+---------+----------+
| 1 | val1 | NULL | 1 | 2 |
| 2 | val2 | nice | 1 | NULL |
| 3 | val3 | NULL | 2 | NULL |
| 4 | val4 | NULL | 2 | 3 |
| 5 | val5 | NULL | 3 | NULL |
由于有了created
和deleted
字段,这种模式使我们能够查看数据的任何过去版本。
SET @version=1;
SELECT data,comment FROM MyTable
WHERE created <= @version AND
(deleted IS NULL OR deleted > @version);
+------+---------+
| data | comment |
+------+---------+
| val1 | NULL |
| val2 | nice |
可以更简单地获取当前版本的数据:
SELECT data,comment FROM MyTable WHERE deleted IS NULL;
+------+---------+
| data | comment |
+------+---------+
| val2 | nice |
| val3 | NULL |
| val5 | NULL |
DDL:
CREATE TABLE `MyTable` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,`data` varchar(32) NOT NULL,`comment` varchar(32) DEFAULT NULL,`created` int(11) NOT NULL,`deleted` int(11) DEFAULT NULL,PRIMARY KEY (`id`),KEY `data` (`data`,`comment`)
) ENGINE=InnoDB;
更新中
一组新的数据和注释会定期到达。五百万行表示,这可能会很大。我需要更新ѭ6,以便将新数据集存储在其中。这表示:
\“删除\”旧行。注意\“吓人的报价\”-我们实际上并未从MyTable
中删除行。我们必须将deleted
字段设置为新版本N
。必须对MyTable
中所有在先前版本N-1
中但不在新集合中的行进行此操作。
插入新行。必须将ѭ6set中新版本中ѭ11not版本以外的所有行添加为新行,其中created
字段设置为新版本N
,deleted
设置为NULL。
新集中的某些行可能与版本11的版本6中的行匹配,在这种情况下,无需执行任何操作。
我目前的解决方案
鉴于我们必须“区分”两组数据来计算出删除,我们不能只读取新数据并进行适当的插入。我想不出一种方法,不用先将所有新数据转储到临时表中就可以执行差异操作。所以我的策略是这样的:
-- temp table uses MyISAM for speed.
CREATE TEMPORARY TABLE tempupdate (
`data` char(32) NOT NULL,`comment` char(32) DEFAULT NULL,PRIMARY KEY (`data`),KEY (`data`,`comment`)
) ENGINE=MyISAM;
-- Bulk insert thousands of rows
INSERT INTO tempupdate VALUES
(\'some new\',NULL),(\'other\',\'comment\'),...
-- Start transaction for the update
BEGIN;
SET @newVersion = 5; -- Worked out out-of-band
-- Do the \"deletions\". The join selects all non-deleted rows in MyTable for
-- which the matching row in tempupdate does not exist (tempupdate.data is NULL)
UPDATE MyTable
LEFT JOIN tempupdate
ON MyTable.data = tempupdate.data AND
MyTable.comment <=> tempupdate.comment
SET MyTable.deleted = @newVersion
WHERE tempupdate.data IS NULL AND
MyTable.deleted IS NULL;
-- Delete all rows from the tempupdate table that match rows in the current
-- version (deleted is null) to leave just new rows.
DELETE tempupdate.*
FROM MyTable RIGHT JOIN tempupdate
ON MyTable.data = tempupdate.data AND
MyTable.comment <=> tempupdate.comment
WHERE MyTable.id IS NOT NULL AND
MyTable.deleted IS NULL;
-- All rows left in tempupdate are new so add them.
INSERT INTO MyTable (data,comment,created)
SELECT disTINCT tempupdate.data,tempupdate.comment,@newVersion
FROM tempupdate;
COMMIT;
DROP TEMPORARY TABLE IF EXISTS tempupdate;
问题(最后)
我需要找到最快的方法来执行此更新操作。我无法更改ѭ6的架构,因此任何解决方案都必须使用该约束。您能想到一种执行更新操作的更快方法,还是建议加快现有方法的速度?
我有一个Python脚本,用于测试不同更新策略的时间并检查其在多个版本中的正确性。它相当长,但是我可以编辑一下这个问题,如果人们认为它会有用。
解决方法
加快速度之一是用于装载-LOAD DATA INFILE。
, 就我所经历的审计日志而言,使用两个表会更好,例如:
yourtable (id,col1,col2,version) -- pkey on id
yourtable_logs (id,version) -- pkey on (id,version)
然后在yourtable上添加一个更新触发器,该触发器将先前版本插入yourtable_logs中。