在Oracle中有限地加入了一个巨大的表

时间:2013-06-06 20:04:35

标签: sql plsql bigdata

问题:我们想要从数据库中删除拼写错误的地址。但我们手头有很多东西要做。所以相反,我有一个函数FN,如果两个地址看起来非常相似(表示可能的拼写错误),则返回true。一个简单的检查是做一些像......

select *
from
    address adr1
    join address adr2
    on FN(adr1, adr2)

但是,这基本上是交叉连接并比较行。由于我们的桌子有多大(> 100万行),这是不可能做到的。但是,我可以限制它只查看彼此附近的地址。例如,同一城市内的地址。所以,我尝试通过这样做来计算这样的地址......

select count(1)
from
    address adr1
    join address adr2
    on adr1.zip = adr2.zip
    and adr1.city = adr2.city
    --Don't want to compare to self
    and adr1.ID <> adr2.ID

问题是这需要太长时间才能运行(我已经等了,但仍然没有完成)。我怀疑oracle有更好的方法来处理大量行的这类事情,但我只是不知道。

那么,如果有办法限制加入的内容(例如只查看相同的邮政编码),那么一个人如何加入一个极大的表呢?

P.S。数万亿条记录是大数据还是应该删除标记?

Edit1:Zip和City已经编入索引。

Edit2:Zip和City都有大量的空值200,000+。这可能会影响索引在连接中的使用方式。

解释计划:

SELECT STATEMENT  ALL_ROWSCost: 35,301  Bytes: 42  Cardinality: 1           
    4 SORT AGGREGATE  Bytes: 42  Cardinality: 1         
        3 HASH JOIN  Cost: 35,301  Bytes: 2,195,769,492  Cardinality: 52,280,226    
            1 TABLE ACCESS FULL TABLE SCHEMA.ADDRESS Cost: 15,677  Bytes: 21,388,962  Cardinality: 1,018,522  
            2 TABLE ACCESS FULL TABLE SCHEMA.ADDRESS Cost: 15,677  Bytes: 21,388,962  Cardinality: 1,018,522  

Edit3:我已经尝试过以不同的方式计算行数。

select
    sum(cnt * (cnt - 1))
from
(
select
    count(1) as CNT
from schema.address adr1
group by adr1.zip, adr1.city
)

这在不到10秒的时间内返回了大约450亿个不同的配对。我不确定我的函数每秒可处理超过10万行,这是在12小时内运行所需的行。

3 个答案:

答案 0 :(得分:1)

1)在字段ZIPCITY

上构建索引

2)要获得重复项(这是您在第二种情况下的操作),请使用GROUP BY

SELECT ZIP,CITY, count(*) FROM ADDRESS HAVING COUNT(*)>1 GROUP BY ZIP,CITY

答案 1 :(得分:1)

我有一些好消息,还有一些坏消息。

好消息是,您现有的查询可能接近50亿行,而不是450亿行。

坏消息是,这是因为它不会尝试匹配具有null zip或null city值的200,000条记录中的任何一条 - Oracle(以及我知道的所有其他RDBMS)都不会将NULL值连接到其他NULL值;有关示例,请参阅here。您可以使用coalesce作为加入条件的一部分来解决此问题,但我建议您分别处理空城/邮编记录。

假设您的函数对称地处理地址(以便FN(addr1,addr2)返回与FN(addr2,addr1)相同的结果),您可以通过将adr1.ID <> adr2.ID更改为{{1}来进一步减少组合数量的一半在您现有的查询中。如果您还没有合适的索引,我建议在zip,city和id上添加一个(按此顺序)。

答案 2 :(得分:0)

另一种方法是使用邮政编码idcode编码每个地址,如果存在相关地址/国家/地区。这意味着,不是将每个地址与自身进行比较,而是首先将所有精力放在解析和解码地址上。我们使用这种方法,并将id存储在每一行中,这意味着我们可以在以后非常精确和快速地加入。

如果您不能使用邮政ID(并且我的意思是邮局指定的每个送货地址的唯一身份证),则考虑对每个地址进行地理编码,然后通过地址附近的地址加入。如果地址不是纯粹的邮政地址,地理编码也可能适用。

我对FN()对地址的作用非常感兴趣,您是否看到http://www.mjt.me.uk/posts/falsehoods-programmers-believe-about-addresses/与您的问题无关,但如果您不熟悉地址处理,请阅读良好。