场景:将数据库表的记录按规则存放在数据文件(文本文件)中,每个记录一行,一条记录的字段之间用“|”分隔,现知道第二个字段是主键字段,现在需要校验此数据文件中有没有主键重复的记录。目前我想到的方案是:使用UNIX的awk将主键字段写到单独文件中(称为主键文件),从数据文件中读一条记录,拆分出主键字符串,使用UNIX grep -c 命令在主键文件中统计此主键字符串出现的次数,如果大于等于2次,说明主键有重复,如果等于1次说明没有主键重复记录;如此循环检查数据文件所有记录。这种方案的弊端:数据文件记录数不多时,效率还行,当记录数很大时,性能难已接受,比如有5000万记录,grep -c遍历一次文件需要将近2分钟,那对做完整个数据文件主键校验需要时间 5000万*2分钟,这是很可怕的。原因分析:grep是从第一行到最后一行顺序遍历一遍文件,所有效率不高。我想到的替代方案:使用类似数据库的索引技术,利用B TREE在主键字段上建立“索引”,这样时间复杂度可以从grep命令的n下降到log(n)。
“索引”实现遇到的困难:
1.不能一次将索引列所有值都加载到内存中(数据量可能很大);
2. 记录存储在硬盘中,如何定位某条记录在硬盘中的位置并访问(记录首地址存放在B TREE结点中,便于找到结点后直接定位到磁盘记录并读取)。如果您有更好的方案,也欢迎提出来。
不考虑具体代码实现C,Java都行。
不甚感激!

解决方案 »

  1.   

    不要逐条比较,用awk取出主键字段后做一个hash,然后用hash去比较
      

  2.   

    主键是不是个数字,那么你可以考虑用数组5000万个int,也就大约需要
    50×4=200M内存默认数组每个数都是0。
    扫描一行,检查将主键对应的数组,如果为0,则设置为1,如果为1,则设置为2,总之增加1
    扫描完毕后,再次查看数组哪些大于1,就知道哪些重复了。当然,第二步你发现重复了,可以输出一些日志信息,方便查找。
      

  3.   

    拆分成小文件再Hash比较,可以考虑,其它的直接读主键到内存的方法都不合适,因为5000W其实也是个不算是大数据,有的甚至都上亿(中国人口基数大啊)。公司内部有个保底方案是用oracle SQLLOADER入库,然后解析错误文件,这方案数据库压力大,目前没去执行。
      

  4.   

    bitmap或类似思想
    5000万数量级绝对能支持
    主要是看主键的范围了,
    符合的话,就能行,
    不符合的话
    用树
    分层的思想,
    每个父结点10个结点,
    从0到9
    没有估算,不清楚这些结点内存放的下不