我每周都要获得一个数据源,我将要解析并放入数据库。数据每周都不会有太大变化,但我应该定期更新数据库。除了每周更新外,数据都是静态的。
现在重建整个数据库不是问题,但最终这个数据库将是实时的,人们可能在重建数据库时查询数据库。数据量不小(几百兆字节),因此它不会立即加载,而且我个人想要一个比“我希望没有人在数据库处于混乱状态时查询。”的简单系统。 / p>
我想到了解决这个问题的几种不同方法,并想知道最好的方法是什么。到目前为止,这是我的想法:
不是替换整个表,而是查询当前数据库与我想要放在数据库中的区别。但这似乎可能是一项不必要的工作量。
创建虚拟数据表,然后执行表重命名(或将服务器代码指向新数据表)。
告诉用户该网站正在进行维护并将系统脱机几分钟。 (由于显而易见的原因,这不是优选的,但如果它是最好的答案,我愿意接受它。)
思想?
答案 0 :(得分:5)
我不能代表MySQL,但PostgreSQL有事务性DDL。这是一个很棒的功能,这意味着您的第二个选项,即将新数据加载到虚拟表中,然后执行表重命名,应该很有效。如果要将表foo
替换为foo_new
,则只需将新数据加载到foo_new
并运行脚本即可进行重命名。此脚本应在其自己的事务中执行,因此如果重命名的内容变坏,foo
和foo_new
在回滚时将保持不变。
这种方法的主要问题是,处理来自foo
的其他表的外键可能会有点麻烦。但至少可以保证您的数据保持一致。
我认为,从长远来看,更好的方法就是直接对数据进行更新(您的第一个选择)。再次,您可以将所有更新保留在单个事务中,因此您可以保证全有或全无语义。更好的是在线更新,只是在新信息可用时直接更新数据。如果您需要其他人的批处理作业的结果,这可能不是您的选择,但如果您可以这样做,那么这是最佳选择。
答案 1 :(得分:3)
BEGIN;
DELETE FROM TABLE;
INSERT INTO TABLE;
COMMIT;
当您点击提交时,用户将立即看到转换。在提交之前启动的任何查询将在旧数据上运行,之后的任何内容都将在新数据上运行。一旦最后一个用户完成它,数据库实际上将清除旧表。因为一切都是“静态的”(你是唯一一个改变它的人,每周只有一次),你不必担心任何锁定问题或超时。对于MySQL,这取决于InnoDB。 PostgreSQL做到了,SQL Server将其称为“快照”,由于我很少使用它,我不记得我头脑中的细节。
如果您使用谷歌“交易隔离”+您正在使用的任何数据库的名称,您将找到适当的信息。
答案 2 :(得分:2)
我们通过使用PostgreSQL的表继承/约束机制解决了这个问题。 您可以创建一个触发器,根据日期字段自动创建分区的子表。
This文章是我使用的来源。
答案 3 :(得分:1)
您使用的是哪个数据库服务器? SQL 2005及更高版本提供了一种名为“Snapshot”的锁定方法。它允许您打开事务,执行所有更新,然后提交,同时数据库的用户继续查看事务前数据。通常,您的事务会锁定您的表并阻止他们的查询,但快照锁定在您的情况下将是完美的。
此处有更多信息:http://blogs.msdn.com/craigfr/archive/2007/05/16/serializable-vs-snapshot-isolation-level.aspx
但它需要SQL Server,所以如果你正在使用别的东西......
答案 4 :(得分:1)
几个数据库系统(因为你没有指定你的,我会保持这个一般)确实提供了名为MERGE
的SQL:2003标准语句,它基本上允许你
SQL Server 2008是第一个提供此声明的Microsoft产品 - 请查看更多here,here或here。
其他数据库系统可能会有类似的实现 - 毕竟它是SQL:2003标准语句。
马克
答案 5 :(得分:1)
使用不同的表名(mytable_ [yyyy] _ [wk])和视图为您提供常量名称(mytable)。完全导入新表后,请更新您的视图,以便它使用该表。