我们如何才能更快地比较两个不同表之间的数据
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
这样的数据结构,甚至可能只是基本的迭代
我有两个来自两个不同数据库的不同 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
这样的数据结构,甚至可能只是基本的迭代