我有一个流程将40多个结构相同的数据库整合到一个统一数据库中,唯一的区别是统一数据库将project_id字段添加到每个表中。
为了尽可能高效,我尝试只将记录从源数据库复制/更新到统一数据库(如果已添加/更改)。我从统一数据库中删除过时的记录,然后复制到任何不存在的记录中。要删除过期/已更改的记录,我正在使用类似于此的查询:
DELETE FROM <table>
WHERE NOT EXISTS (SELECT <primary keys>
FROM <source> b
WHERE ((<b.fields = a.fields>) or
(b.fields is null and a.fields is null)))
AND PROJECT_ID = <project_id>
这大部分都有效,但源数据库中的一个表有超过700,000条记录,此查询需要一个多小时才能完成。
如何提高此查询效率?
答案 0 :(得分:2)
使用时间戳或更好的审计表来识别自“X”时间以来发生更改的记录,然后在上次同步开始时保存时间“X”。我们将它用于界面提要。
答案 1 :(得分:0)
您可能想尝试使用NULL过滤器进行LEFT JOIN:
DELETE <table>
FROM <table> t
LEFT JOIN <source> b
ON (t.Field1 = b.Field1 OR (t.Field1 IS NULL AND b.Field1 IS NULL))
AND(t.Field2 = b.Field2 OR (t.Field2 IS NULL AND b.Field2 IS NULL))
--//...
WHERE t.PROJECT_ID = <project_id>
AND b.PrimaryKey IS NULL --// any of the PK fields will do, but I really hope you do not use composite PKs
但如果您要比较所有非PK列,那么您的查询将受到影响。
在这种情况下,最好在两个数据库上添加UpdatedAt TIMESTAMP字段(如DVK建议的那样),您可以使用AFTER UPDATE触发器更新,然后您的同步过程会更快,因为您创建了包含PK的索引和UpdatedAt列。
答案 2 :(得分:0)
您可以重新排序WHERE语句;它有四个比较,最有可能首先失败。
如果您可以稍微更改数据库/应用程序,并且您需要再次执行此操作,则显示“已更新”的位字段可能不是一个糟糕的添加。
答案 3 :(得分:0)
我通常会重写这样的查询以避免不... Not In虽然表现糟糕,但Not Exists在此方面有所提升。
查看此文章http://www.sql-server-pro.com/sql-where-clause-optimization.html
我的建议......
将pkey列选择到工作/临时表中,添加一个列(标志)int default 0 not null,并索引pkey列。如果子查询中存在记录,则标记标记= 1(更快!)。 将主查询中的子选择替换为exists where(从temptable中选择pkey,其中flag = 0)
这样做可以创建一个“不存在”值列表,这些值可以包含在一个全包集合中。
这是我们的总集。 {1,2,3,4,5}
这是现有的一套 {1,3,4}
我们从这两组创建工作表(技术上是左外连接) (记录:存在)
{1:1,2:0,3:1,4:1,5:0}
我们的'不存在的记录'
{2,5}(选择* from flag = 0)
我们的产品......更快(索引!)
{2,5} = {2,5} 中的{p> {1,2,3,4,5}{1,2,3,4,5}不在{1,3,4} = {2,5}
这可以在没有工作台的情况下完成,但是它的使用使得可以更容易地看到发生的事情。
克里斯