我有2个文件。第一个文件包含数据库中表的元组的行ID列表。 第二个文件包含查询的“where”子句中包含这些行ID的SQL查询。
例如:
档案1
1610657303
1610658464
1610659169
1610668135
1610668350
1610670407
1610671066
文件2
update TABLE_X set ATTRIBUTE_A=87 where ri=1610668350;
update TABLE_X set ATTRIBUTE_A=87 where ri=1610672154;
update TABLE_X set ATTRIBUTE_A=87 where ri=1610668135;
update TABLE_X set ATTRIBUTE_A=87 where ri=1610672153;
我必须阅读文件1并在文件2中搜索与文件1中的行ID匹配的所有SQL命令,并将这些SQL查询转储到第三个文件中。
文件1有1,00,000个条目,文件2包含10倍于文件1的条目,即1,00,0000。
我使用了grep -f File_1 File_2 > File_3
。但这非常缓慢,每小时1000个条目。
有没有更快的方法呢?
答案 0 :(得分:30)
您不需要regexp,因此grep -F -f file1 file2
答案 1 :(得分:17)
awk
的一种方式:
awk -v FS="[ =]" 'NR==FNR{rows[$1]++;next}(substr($NF,1,length($NF)-1) in rows)' File1 File2
这应该很快。在我的机器上,花了不到2秒的时间创建了100万个条目的查找,并将其与300万行进行比较。
机器规格:
Intel(R) Xeon(R) CPU E5-2670 0 @ 2.60GHz (8 cores)
98 GB RAM
答案 2 :(得分:1)
我建议使用Perl,Ruby或Python等编程语言。
在Ruby中,只读一次文件(f1
和f2
)的解决方案可能是:
idxes = File.readlines('f1').map(&:chomp)
File.foreach('f2') do | line |
next unless line =~ /where ri=(\d+);$/
puts line if idxes.include? $1
end
或使用Perl
open $file, '<', 'f1';
while (<$file>) { chomp; $idxs{$_} = 1; }
close($file);
open $file, '<', 'f2';
while (<$file>) {
next unless $_ =~ /where ri=(\d+);$/;
print $_ if $idxs{$1};
}
close $file;
答案 3 :(得分:1)
上面提到的awk / grep解决方案在我的机器上很慢或内存耗尽(file1 10 ^ 6行,file2 10 ^ 7行)。所以我想出了一个使用sqlite3的SQL解决方案。
将file2转换为CSV格式的文件,其中第一个字段是ri=
cat file2.txt | gawk -F= '{ print $3","$0 }' | sed 's/;,/,/' > file2_with_ids.txt
创建两个表:
sqlite> CREATE TABLE file1(rowId char(10));
sqlite> CREATE TABLE file2(rowId char(10), statement varchar(200));
从file1导入行ID:
sqlite> .import file1.txt file1
使用“准备好的”版本从文件2导入语句:
sqlite> .separator ,
sqlite> .import file2_with_ids.txt file2
使用表file2
中匹配的rowId选择表file1
中的所有语句并使其显示:
sqlite> SELECT statement FROM file2 WHERE file2.rowId IN (SELECT file1.rowId FROM file1);
通过在发出select语句之前将输出重定向到文件,可以轻松创建文件3:
sqlite> .output file3.txt
测试数据:
sqlite> select count(*) from file1;
1000000
sqlite> select count(*) from file2;
10000000
sqlite> select * from file1 limit 4;
1610666927
1610661782
1610659837
1610664855
sqlite> select * from file2 limit 4;
1610665680|update TABLE_X set ATTRIBUTE_A=87 where ri=1610665680;
1610661907|update TABLE_X set ATTRIBUTE_A=87 where ri=1610661907;
1610659801|update TABLE_X set ATTRIBUTE_A=87 where ri=1610659801;
1610670610|update TABLE_X set ATTRIBUTE_A=87 where ri=1610670610;
在没有创建任何索引的情况下,在AMD A8 1.8HGz 64位Ubuntu 12.04计算机上,select语句大约需要15秒。
答案 4 :(得分:0)
也许尝试AWK并使用文件1中的数字作为关键字,例如简单的脚本
第一个脚本将生成awk脚本:
awk -f script1.awk
{ print "\$0 ~ ",$0,"{ print \$0 }" > script2.awk; }
然后使用文件
调用script2.awk答案 5 :(得分:0)
我可能遗漏了一些东西,但仅仅迭代file1
中的ID和每个ID grep file2
并将匹配存储在第三个文件中是不够的?即。
for ID in `cat file1`; do grep $ID file2; done > file3
这不是非常有效(因为file2将被反复阅读),但它可能对你来说已经足够了。如果你想要更快的速度,我建议使用更强大的脚本语言,让你将file2
读入地图,快速识别给定ID的行。
这是这个想法的Python版本:
queryByID = {}
for line in file('file2'):
lastEquals = line.rfind('=')
semicolon = line.find(';', lastEquals)
id = line[lastEquals + 1:semicolon]
queryByID[id] = line.rstrip()
for line in file('file1'):
id = line.rstrip()
if id in queryByID:
print queryByID[id]
答案 6 :(得分:0)
答案 7 :(得分:-1)
##报告&lt;中包含的所有行。文件1&gt;缺少&lt;文件2&gt;
IFS=$(echo -en "\n\b") && for a in $(cat < file 1>);
do ((\!$(grep -F -c -- "$a" < file 2>))) && echo $a;
done && unset IFS
或做要求者想要的,取消否定并重定向
(IFS=$(echo -en "\n\b") && for a in $(cat < file 1>);
do (($(grep -F -c -- "$a" < file 2>))) && echo $a;
done && unset IFS) >> < file 3>