Java 将一个表中的数百万行与另一个表中的数百万行进行比较的最快方法
我想比较两个表,每个表中有数百万条记录,并从比较中获得匹配数据 为了从两个表中获得匹配数据,我们首先比较Java 将一个表中的数百万行与另一个表中的数百万行进行比较的最快方法,java,database,oracle,performance,optimization,Java,Database,Oracle,Performance,Optimization,我想比较两个表,每个表中有数百万条记录,并从比较中获得匹配数据 为了从两个表中获得匹配数据,我们首先比较表1中的名称不应等于表2中的名称。然后我们比较表1中的城市应等于表2中的城市,最后我们比较表1中的出生日期应与表2中的出生日期在+-1年范围内 表1中的一行可以与表2中的数据有多个匹配项。 此外,对于每个匹配,我需要一个唯一的记录ID,单个表1行的多个匹配数据必须具有相同的唯一记录ID 我尝试使用Java代码和PL/SQL过程,但这两个过程都需要几个小时,因为这涉及到数百万数据与数百万数据的比
表1
中的名称不应等于表2
中的名称。然后我们比较表1中的城市
应等于表2中的城市
,最后我们比较表1中的出生日期
应与表2中的出生日期
在+-1年范围内
表1
中的一行可以与表2中的数据有多个匹配项。
此外,对于每个匹配,我需要一个唯一的记录ID,单个表1行的多个匹配数据必须具有相同的唯一记录ID
我尝试使用Java代码和PL/SQL过程,但这两个过程都需要几个小时,因为这涉及到数百万数据与数百万数据的比较。有没有更快的方法进行匹配?从两个表中选择数据,按关键字段排序,然后并行迭代并比较。比较时间应该很快,所以总运行时间应该只比每个有序查询的运行时间之和略多
更新
显示需要数据的部分交叉联接:
left.name <> right.name
left.city = right.city
abs(left.birthDate - right.birthDate) <= 1 year
迭代记录并跳过具有相同名称的记录。这些是与给定记录“匹配”的left
记录
- 如果需要,可以将其展平,并使用流过滤名称:
List<Person> matches = coll.stream()
.flatMap(List::stream)
.filter(p -> ! p.name.equals(right.name))
.collect(Collectors.toList());
List matches=coll.stream()
.flatMap(列表::流)
.filter(p->!p.name.equals(right.name))
.collect(Collectors.toList());
可选地用实际处理逻辑替换collect()
如步骤4所述处理完区块后,即当您看到下一个城市
时,清除树状图
,并从步骤3开始重复下一个区块,即城市
这种逻辑的优点:
- 数据只从数据库服务器发送一次,即从相对较慢的数据链路中消除了部分交叉连接导致的数据重复
- 如果需要,这两个查询可以来自两个不同的数据库
- 通过一次只保留一个查询的
城市
(左侧的块
)的数据,可以减少内存占用
- 如果需要,匹配逻辑可以是多线程的,以获得额外的性能,例如
- 线程1将
left
区块加载到TreeMap
,并将其交给线程2进行处理,而线程1开始加载下一个区块
- 线程2通过调用
subMap()
,迭代subMap,将匹配的左
和右
记录交给线程3处理,从而迭代右
并查找匹配的记录
- 线程3处理匹配对
从两个表中选择数据,按关键字段排序,然后并行迭代并比较。比较时间应该很快,所以总运行时间应该只比每个有序查询的运行时间之和略多
更新
显示需要数据的部分交叉联接:
left.name <> right.name
left.city = right.city
abs(left.birthDate - right.birthDate) <= 1 year
迭代记录并跳过具有相同名称的记录。这些是与给定记录“匹配”的left
记录
- 如果需要,可以将其展平,并使用流过滤名称:
List<Person> matches = coll.stream()
.flatMap(List::stream)
.filter(p -> ! p.name.equals(right.name))
.collect(Collectors.toList());
List matches=coll.stream()
.flatMap(列表::流)
.filter(p->!p.name.equals(right.name))
.collect(Collectors.toList());
可选地用实际处理逻辑替换collect()
如步骤4所述处理完区块后,即当您看到下一个城市
时,清除树状图
,并从步骤3开始重复下一个区块,即城市
这种逻辑的优点:
- 数据只从数据库服务器发送一次,即从相对较慢的数据链路中消除了部分交叉连接导致的数据重复
- 如果需要,这两个查询可以来自两个不同的数据库
- 通过一次只保留一个查询的
城市
(左侧的块
)的数据,可以减少内存占用
- 如果需要,匹配逻辑可以是多线程的,以获得额外的性能,例如
- 线程1将
left
区块加载到TreeMap
,并将其交给线程2进行处理,而线程1开始加载下一个区块
- 线程2通过调用
subMap()
,迭代subMap,将匹配的左
和右
记录交给线程3处理,从而迭代右
并查找匹配的记录
- 线程3处理匹配对
“我尝试使用java,通过jdbc连接将两个表中的数据存储在列表中,然后用一个列表迭代另一个列表。但这非常缓慢,需要花费许多小时才能完成,甚至多次出现超时异常。”
祝贺你。这是启蒙道路上的第一步。数据库在处理数据方面比Java好得多。Java是一种优秀的通用编程语言,但数据库针对关系数据处理进行了优化:它们只需更快地完成,CPU更少,内存更少,网络流量更少
“我还为同样的问题创建了一个sql过程,这是一个更快的过程
比java程序还慢,但仍然需要很多时间(几个小时)才能完成
完成。”
您即将进入启蒙的第二步:逐行处理(即程序迭代)很慢。SQL是
select col1, col2, col3
from huge_table_1
MINUS
select col1, col2, col3
from huge_table_2
select * from huge_table_1 ht1
where exists
( select null from huge_table_2 ht2
where ht2.city = ht1.city
and ht1.date_of birth between add_months(ht2.date_of birth, -12)
and add_months(ht2.date_of birth, 12)
and ht2.name != ht1.name)
/