我们如何才能更快地比较两个不同表之间的数据

how can we compare data between two different tables much faster

我有两个来自两个不同数据库的不同 table。我在两个 table 中都有大量数据,但我在两个 table 中都有相同的列。

当我尝试使用下面的代码时,我遇到了一些性能问题(虽然它在员工 table 中只有 2 条记录,但在部门 table 我有 100 000 条记录)比较正在进行超过10分钟。

有什么办法可以降低性能并使其更快。

EmplTbl = cur.execute("select A , B , C from EmployeeTable where EmplName in ('A','B')") 
for line in EmplTbl:
    EmplData.append(line)

DeptTbl = cur.execute("select A , B , C from DeptTable") 

for line in DeptTbl:
    DeptData.append(line)

for Empl in EmplData:
    DeptResult = all(Empl in DeptData for elm in DeptData)
    if DeptResult:
        print("Yes")
    else:
        print("No")

考虑一个纯粹的 SQL 解决方案来避免多个 Python 循环。具体来说,运行 aLEFT JOIN 和 test NULL 匹配所有三列:

select e.A as emp_A, e.B as emp_B, e.C as emp_C, 
       d.A as dept_A, d.B as dept_B, d.C as dept_C,
       case
           when not (d.A is null or d.B is null or d.C is null) then 'Yes'
           else 'No'
       end as DeptResult
from EmployeeTable e
left join DeptTable d 
    on e.A = d.A and e.B = d.B and e.C = d.C
where e.EmplName in ('A', 'B')

纯sql。

select * from DeptResult
minus 
select * from EmployeeTable

union 

select * from EmployeeTable
minus 
select * from DeptResult

如果table几乎相同,比较数据块的散列会更快,然后只比较块的所有数据差异。

我敢打赌 运行 大部分时间都花在了传输和转换数据上。从 Employee table 读取 100,000 行在数据库中可能只需要几秒钟。使用函数 DBMS_SQLHASH.GETHASH,Oracle 可以快速生成大量数据的哈希值。 (您可能需要有 DBA 运行 grant execute on sys.dbms_sqlhash to your_user;

例如,想象一下这两个 table(实际上它们要大得多,并且在不同的数据库上):

create table EmployeeTable1 as
select 1 a, 2 b, 3 c, 'abcdefg' EmplName from dual union all
select 1 a, 2 b, 3 c, 'bcdefg'  EmplName from dual union all
select 1 a, 2 b, 3 c, 'cdefg'   EmplName from dual;

create table EmployeeTable2 as
select 1 a, 2 b, 3 c, 'abcdefg' EmplName from dual union all
select 1 a, 2 b, 3 c, 'bcdefg'  EmplName from dual union all
select 9 a, 9 b, 9 c, 'cdefg'   EmplName from dual;

为员工姓名的每个首字母生成哈希。

--Table 1 hashes:
select 'a', dbms_sqlhash.gethash('select a,b,c,EmplName from EmployeeTable1 where EmplName like ''a%'' order by 1,2,3', 3) from dual union all
select 'b', dbms_sqlhash.gethash('select a,b,c,EmplName from EmployeeTable1 where EmplName like ''b%'' order by 1,2,3', 3) from dual union all
select 'c', dbms_sqlhash.gethash('select a,b,c,EmplName from EmployeeTable1 where EmplName like ''c%'' order by 1,2,3', 3) from dual;

a   923920839BFE25A44303718523CBFE1CEBB11053
b   355CB0FFAEBB60ECE2E81F3C9502F2F58A23F8BC
c   F2D94D7CC0C82329E576CD867CDC52D933C37C2C <-- DIFFERENT


--Table 2 hashes:
select 'a', dbms_sqlhash.gethash('select a,b,c,EmplName from EmployeeTable2 where EmplName like ''a%'' order by 1,2,3', 3) from dual union all
select 'b', dbms_sqlhash.gethash('select a,b,c,EmplName from EmployeeTable2 where EmplName like ''b%'' order by 1,2,3', 3) from dual union all
select 'c', dbms_sqlhash.gethash('select a,b,c,EmplName from EmployeeTable2 where EmplName like ''c%'' order by 1,2,3', 3) from dual;

a   923920839BFE25A44303718523CBFE1CEBB11053
b   355CB0FFAEBB60ECE2E81F3C9502F2F58A23F8BC
c   6B7B1D374568B353E9A37EB35B4508B6AE665F8A <-- DIFFERENT

Python程序只需要比较hash,很快就能发现"a"和"b"是一样的,不同的是[=32=开头的员工=].然后程序只需比较较小结果集的所有细节。

不幸的是,此解决方案需要更多编码,因为您必须在 Python 中构建循环并构建多个 SQL 语句。如果您的 table 非常不同,解决方案将是 较慢 ,并且您需要研究数据以找到正确的块大小。

您的代码所做的工作似乎比您预期的要多得多。你的线路:

DeptResult = all(Empl in DeptData for elm in DeptData)

正在隐式地做:

DeptResult = True
for elem in DeptData:
  for tmp in DeptData:
     DeptResult = DeptResult and Empl == tmp

即当您只需要一次时,您在 DeptData 上进行了两次嵌套传递,因此需要 len(DeptData) ** 2 次操作。这意味着您正在尝试进行 1e10 比较,并且确实需要很长时间才能完成

我将其重写为:

cur.execute("select A , B , C from DeptTable")
dept_entries = set(cur)

cur.execute("select A , B , C from EmployeeTable where EmplName in ('A','B')") 
for empl in cur:
  if empl in dept_entries:
    print(empl, 'Yes')
  else:
    print(empl, 'No')

请注意,Python 数据库连接器通常 return 不是由它们的 execute 方法产生的,您应该调用它们的一种 fetch* 方法或迭代光标。我不使用 Oracle,但 other posts 建议他们应该遵循标准并且您的代码已损坏

DeptTable 放入 set 意味着查找现在是 O(1),因此 empl in dept_entries 非常便宜

注意:可能值得阅读一些关于 tuple 等式如何在 Python 中工作的教程,以及像 set 这样的数据结构,甚至可能只是基本的迭代