Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/kotlin/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 获取两个几乎相同的表之间的记录差异_Sql_Performance_Not Exists - Fatal编程技术网

Sql 获取两个几乎相同的表之间的记录差异

Sql 获取两个几乎相同的表之间的记录差异,sql,performance,not-exists,Sql,Performance,Not Exists,我有一个将40多个相同结构的数据库合并为一个合并数据库的过程,唯一的区别是合并数据库向每个表添加一个project_id字段 为了尽可能地提高效率,我尝试只将已添加/更改的记录从源数据库复制/更新到合并数据库。我从合并数据库中删除过时的记录,然后复制任何不存在的记录。要删除过期/更改的记录,我将使用类似于以下内容的查询: DELETE FROM <table> WHERE NOT EXISTS (SELECT <primary keys>

我有一个将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>
这在很大程度上是可行的,但是源数据库中的一个表有超过700000条记录,并且这个查询需要一个多小时才能完成


如何使此查询更高效?

使用时间戳或更好的审计表来识别自时间X以来更改的记录,然后在上次同步启动时保存时间X。我们将其用于接口提要。

您可能希望尝试使用空筛选器进行左连接:

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列,那么您的查询将受到影响


在这种情况下,最好按照DVK的建议在两个数据库上都添加UpdatedAt TIMESTAMP字段,您可以使用AFTER update触发器进行更新,这样您的同步过程会快得多,因为您创建了一个包含PKs和UpdatedAt列的索引。

您可以对WHERE语句重新排序;它有四个比较,把最有可能失败的一个放在第一位


如果您可以稍微更改数据库/应用程序,并且需要再次更改,那么添加一个表示已更新的位字段可能不是一个好的选择。

我通常会重写这样的查询,以避免。。。 不存在对性能来说是可怕的,尽管不存在对这方面的改进

看看这篇文章

我的建议

在工作/临时表中选择pkey列,添加列标志int default 0 not null,并为pkey列编制索引。如果子查询中存在记录,则标记标志=1!快得多!。 将主查询中的子选择替换为exists where select pkey from TENTABLE where flag=0

这样做的结果是能够创建一个“不存在”值列表,这些值可以从一个全包集合中包含使用

这是我们的全套。 {1,2,3,4,5}

这是现有的一套 {1,3,4}

我们从这两个集合中创建工作表,从技术上讲是一个左外连接 记录:存在

{1:1,2:0,3:1,4:1,5:0}

我们的一组“不存在的记录”

{2,5}从其中选择*标志=0

我们的产品。。。还有更快的索引

{1,2,3,4,5}在{2,5}={2,5}

{1,2,3,4,5}不在{1,3,4}={2,5}

这可以在没有工作台的情况下完成,但它的使用使得可视化正在发生的事情变得更容易


Kris

您有字段索引吗?这些是您添加到数据库/表中的内容吗?IE:在每个表中添加一个last_updated字段,在每个数据库中添加一个audit_表?不幸的是,我无法修改源数据库的架构,因为它们来自供应商产品。从技术上讲,我可以向每个表添加一个审核表,甚至一个字段作为时间戳,但供应商流程永远不会向审核表添加任何内容,也不会在更改时填充时间戳字段。该表是否具有非递减字段?DB生成的或自然发生的ID?如果没有,可以通过定期运行的SP来填充审计表,但是非常讨厌。此外,请查看是否可以以某种方式非正式地插入供应商流程。例如,可能在某个文件系统或数据库中有一些剩余的淤泥,这些文件系统或数据库列出了5分钟前刚刚或自5分钟前开始执行的行。