在 1000 万行中查找记录

Posted

技术标签:

【中文标题】在 1000 万行中查找记录【英文标题】:find record in 10 million rows 【发布时间】:2013-01-25 20:22:36 【问题描述】:

我有一个逗号分隔格式的文本文件。每行有两列,每列都有整数值。喜欢

12334,23433
23234,45663
234422,324545
324543,23433
143233,23433
.....

重复第二列中的值。我需要完成的是找到第一列中第二列具有相同值的所有值并将它们表示为一行。就像上面的数据:

23433 12334,324543,143233
45663 23234
324545 234422

我所做的如下:

    使用逗号 (,) 将文本文件导入 SQL Server 表 分隔符。 从每行代码中读取文本文件。 以逗号 (,) 为基础分割行并使用第二列值发送 查询 SQL 表。 将结果存储在字典数据结构中,其中键是第二列 并将所有结果连接到第一列值。 处理完毕,遍历字典,写入文件。

这肯定花费了太多时间。我已经用 C# 编写了代码。 T-SQL 中的任何解决方案都可以正常工作。

任何优化它的帮助。

【问题讨论】:

向我们展示您正在使用的查询怎么样? 我对此一无所知,但我认为如果您只检查每个数字中的第一个字节并照亮其他所有内容并将其放入新表中,您将能够大大缩短检查时间,然后释放原始表(空闲内存),然后用第二个字节重复该过程,依此类推,直到您完成了最大数字大小的字节数? @leppie - 索引第一列感谢您的回复 一千万行?那不是大数据:P - “小数据是适合 RAM 的时候。大数据是因为不适合 RAM 而崩溃的时候。” @DEVOPS_BORAT @Malik 为什么要为第一列创建索引?您正在按第二列分组/排序,因此第二列需要索引。 【参考方案1】:

只要数据很小,在纯 C# 中执行此操作应该既快速又简单。无需将 CSV 文件拉入 SQL 数据库。

只要文件适合您的 RAM,最大的成本应该是 IO,而不是处理。如果有 1000 万行,该文件应该有大约 100 MB,并且可能需要一秒钟的时间来处理。

var lines = File.ReadLines(inputFilename);

var table = lines.Select(line => line.Split(','));
var groups = table.GroupBy(columns => columns[1]);
var output = groups.Select(g => g.Key + " " + string.Join(",", g.Select(columns=>columns[0])));

File.WriteAllLines(outputFilename, output);

【讨论】:

非常感谢您的回复。我有超过 1000 万行。上面的代码会花费更少的时间吗? @Malik 只要它适合您的 RAM,此代码应该很快。如果它不适合 RAM,您将获得异常或您的计算机将开始交换。如果遇到异常,请切换到 64 位。 GroupBy 步骤之前将字符串转换为 int 可能会稍微减少所需的内存。 我实际上可能会将 .ToList() 添加到第 2 行的末尾。这可能会减少 String.Split 运行的次数... @Aron 为什么?它使用当前代码每行拆分一次。与所有 LINQ 函数一样,GroupBy 仅在输入序列上迭代一次。添加ToList() 将增加内存使用量而不会改善任何内容。【参考方案2】:

只需使用 order by 一次处理一个 col2

select col1, col2 
from table  
order by col2, col1

然后当你得到 col2 的新值时写出该行

Int col2Last = 0;  // assume 0 is not a valid value
StringBuilder sb = new string builder();

    while (rdr.read());
    
        col1 = rdr.GetInt(0);
        col2 = rdr.GetInt(1);
        if(col2 != col2Last and col2Last !=0)
        
             Console.WriteLine(col2Last.ToString() + " " + sb.ToString());
             sb.clear();
        
        if (sb.Lenght > 0) sb.Append(",");
        sb.Append(col1.ToString());
        col2Last = col2;
    
    Console.WriteLine(col2Last.ToString() + " " + sb.ToString());

【讨论】:

非常感谢您的回复,但我不确定“写出”部分。请提供任何详细信息。 但我会尝试 CodesInChaos 的答案并消除 SQL。 1000 万应该仍然可以存储在内存中。对象大小有 1 GB 的限制。 不要忘记在 col2 上创建索引,这样排序很快。 @CodesInChaos 我不同意。创建索引将比单次扫描花费更长的时间。【参考方案3】:

如果您已经将数据导入表格,为什么不尝试这种方式:

declare @t table(c1 int, c2 int)
insert into @t values
(12334,23433),
(23234,45663),
(234422,324545),
(324543,23433),
(143233,23433)

select c2, replace((select cast(c1 as varchar) as 'data()' from @t where c2=t.c2 for xml path('')),' ',', ')
from 
@t t
group by c2 

【讨论】:

非常感谢您的回复,但我有一个包含 16522439 行的文本文件。我无法运行插入。我使用 SQL 导入/导出向导创建了表。任何 SQL 查询? 这只是一个例子。在我的选择语句中使用您创建的表而不是 @t。

以上是关于在 1000 万行中查找记录的主要内容,如果未能解决你的问题,请参考以下文章

查找多个刷入/刷出时间戳之间的总分钟数 - 从垂直行中选择多个记录并转换水平行

假设一个表中有多个列有 1000 条记录,如何在整个表中查找重复记录? [复制]

是否可以遍历我的 SQL 数据库中的每个表并查找其他行中未使用的记录? (PK/FK检查)

SQL Server 索引问题 - 地址查找

SQL:如何从重复行中选择第一条记录?

查看聚集索引查找超过 50 万行需要 7 分钟