填充非常大的哈希表-如何最有效地做到这一点?

伊格拉姆

背景/背景:

为了识别“来自数据集A的项目X与来自数据集B的项目Y或Z匹配”,我必须交叉检查/比较多个数据集(这些数据集倾向于相互不一致)。

这些涉及的数据集有些大(10万条记录),并且涉及我戳SQL数据库。

经过一些初步的研究和性能测试,我已经从通过“大规模数组”解析到有效地使用“索引哈希表”作为关键属性点。

挑战:

一旦使用哈希表,使用哈希表的速度非常快……但是我的问题是有效地构建哈希表感觉就像我“快到了”,但是不得不诉诸(相对)缓慢的方法(50,000条记录大约需要300-400秒)。

这是我现在要编制索引的基本数据(我从SQL中获得了不同的设备名称列表,以及该设备具有多少记录的计数):

DEVICENAME      COUNTOF
==========      ========
DEVICE_1        1
DEVICE_2        1
DEVICE_3        2
....            ...
DEVICE_49999    3
DEVICE_50000    1

当前解决方案:

我目前正在通过遍历结果集(我从SQL中退出作为结果集的数组)并为每个订单项使用“ .add”来构造哈希表。

所以只是一个简单的...

for ($i=0; $i -lt @($SQL_Results).CountOf; $i++) {
    $MyIndexHash.Add( @($SQL_Results[$i]).DeviceName,  @($SQL_Results[$i]).CountOf)
}

相对而言,这有点“慢”(前面提到的300-400秒用于构建50,000个订单项)。CAN等待如果需要的话,但因为(在预感),我尝试这是“近即时”下面,逗它,有可能是一个更好的办法做到这一点(花了3秒左右)。

$MyIndexHash.Keys = $SQL_Results.DEVICENAME

但是,这填充哈希表的KEY,而不是相关值。而且我还没有找到一种有效实现以下目标的方法(将值从数组中直接分配给哈希表):

$MyIndexHash.Keys = ($SQL_Results.DEVICENAME, $SQL_Results.COUNTOF)

这是一个“纯粹的性能”问题-因为我需要做的其他一些比较将是80,000个和150,000个订单项。如果我必须“只是等待”通过遍历SQL结果数组的每一行来构造哈希表,就这样吧。

注意-我已经看过了-Powershell 2和.NET:针对超大哈希表进行优化吗?-但由于我有可变的数据集(很好-“未知但可能很大”)可以处理,所以我不确定是否可以/希望开始分解哈希表。

另外,哈希表中的LOOKUP(一旦填充)毕竟是超快的……只是希望以某种更有效的方式完成哈希表的构建?

任何有关如何改善如何更有效地构建哈希表的建议都将受到欢迎。

谢谢!

更新/调查

基于对@Pawel_Dyl应该多快进行哈希表分配的评论,我让我研究了我的代码的变体和更大的(200k行项目)数据值集。

这是测试结果以及持续时间:

#Create the Demo Data... 200k lines
$Src = 1..200000 | % { [pscustomobject]@{Name="Item_$_"; CountOf=$_} }

# Test # 1 - Checking (... -lt $Src.Count) option vs (... -lt @($Src)Count ) ...
# Test 1A - using $Src.CountOf
$timer = [System.Diagnostics.Stopwatch]::StartNew()
$hash1A = @{}
foreach ($i in $Src) { $hash1A[$i.Name] = $i.CountOf }
$Timer.Stop()
$Timer.ElapsedMilliseconds
# Duration = 736 ms

# Now with @()
$timer = [System.Diagnostics.Stopwatch]::StartNew()
$hash1B = @{}
foreach ($i in @($Src)) { $hash1B[$i.Name] = $i.CountOf }
$Timer.Stop()
$Timer.ElapsedMilliseconds
# Duration = 728 ms

##################

# Test # 2 - Checking (... -lt $Src.Count) option vs (... -lt @($Src).Count ) ...

$timer = [System.Diagnostics.Stopwatch]::StartNew()
$hash2A = @{}
for ($i=0; $i -lt @($Src).Count; $i++) {
    $hash2A.Add(@($Src[$i]).Name, @($Src[$i]).CountOf)
}
$Timer.Stop()
$Timer.ElapsedMilliseconds
# Duration == 4,625,755 (!) (commas added for easier readability!

$timer = [System.Diagnostics.Stopwatch]::StartNew()
$hash2B = @{}
for ($i=0; $i -lt $Src.Count; $i++) {
    $hash2B.Add( $Src[$i].Name, $Src[$i].CountOf )
}
$Timer.Stop()
$Timer.ElapsedMilliseconds
# Duration == 1788 ms

因此,问题出在使用@()-s在循环中引用数组。旨在防止SQL中的1行数组/结果(出于某种奇怪的原因,Powershell并没有将其作为一个概念,而是将其完全视为DATAOBJECT而不是数组(因此,.Count之类的东西不可用)而不强制POSH通过@()将其作为数组处理。

因此,“暂时”的解决方案是添加一个简单的... If(@($ MyArray).Count -eq 1){用@()来做}} ElseIf(@($ MyArray).Count -gt 1){不使用@()-s来做事情

罪魁祸首-在循环中使用@()-s花费了将近1.25个小时,而同一操作则花费了约1秒钟。

进行更改会极大地加速工作(即使只用0.1秒就可以构造每个哈希表,即使90,000个以上的对象在“愤怒中”也是如此。代码使用起来不太方便,但是,哦,我仍然不明白为什么) Powershell在“ 1行数组”的概念上存在问题,因此决定将它们作为单独的数据类型以不同的方式进行处理,但是您就可以了。

我仍将查看DataReader的建议,以了解在哪里/如何在代码中最好地利用它们,以作为将来的改进。非常感谢您的所有建议和能使一切变得有意义的出色解释!

PawełDyl

我希望性能瓶颈在哈希表之外。我测量了我见过的最常用的方法,结果如下:

#demo data
#$src = 1..200000 | % { [pscustomobject]@{Name="Item_$_";Count=$_} }

#1
$timer = [System.Diagnostics.Stopwatch]::StartNew()
$hash1 = @{}
$src | % {$hash1[$_.Name]=$_.Count}
$timer.Stop()
$timer.ElapsedMilliseconds

#2
$timer = [System.Diagnostics.Stopwatch]::StartNew()
$hash2 = @{}
for ($i=0; $i -lt $src.Count; $i++) {
    $hash2.Add($src[$i].Name,$src[$i].Count)
}
$timer.Stop()
$timer.ElapsedMilliseconds

#3
$timer = [System.Diagnostics.Stopwatch]::StartNew()
$hash3 = @{}
foreach ($i in $src.GetEnumerator()) { $hash3[$i.Name] = $i.Count }
$timer.Stop()
$timer.ElapsedMilliseconds

#4
$timer = [System.Diagnostics.Stopwatch]::StartNew()
$hash3 = @{}
foreach ($i in $src) { $hash3[$i.Name] = $i.Count }
$timer.Stop()
$timer.ElapsedMilliseconds

在我的计算机上分别花费了大约5s,〜1.7s,〜0.7s,〜0.7s来完成第1-4节(200000条记录)。如果必须进一步优化,我将评估一些用于构建字典的本机.NET方法。

尝试优化其余代码。提示:

  • 您确定所有记录都在hastable循环开始之前已在内存中吗?
  • 您确定属性是简单类型(整数,字符串-小心代理,带有“隐藏”代码的属性)吗?

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

MySQL查询,3个表,t1-t2然后更新t3。我怎样才能最有效地做到这一点?

有什么办法可以在PHP中更有效地做到这一点?

在一个非常大的表中为每个组有效地选择最新行?

使用相同的sql Server表执行不同的更新,有没有办法做到这一点?

脚本:以非常特殊的方式替换文件中的行。如何使用Powershell做到这一点?

我们如何在Google工作表中做到这一点?根据条件相乘

客观化关系:一对多,我可以有效地做到这一点吗?

我可以获得代码审查吗?如果我可以更有效地做到这一点,需要帮助

将编辑差异拼合到主记录上-我可以更简单或更有效地做到这一点吗?

CakePHP做到这一点的正确方法(从设置的表中获取值)

如何有效地将大型rdd加入非常大的rdd中?

如何有效地读取非常大的 gzipped 日志文件的最后一行?

如何有效地更改非常大的QPixmap的很小一部分?

遍历非常大的表并更新行的最有效方法是什么?

目前使用 Word 表作为数据库——有没有更好的方法来做到这一点?

性能计数器的读取访问速度非常慢-任务管理器如何做到这一点?

如何做到这一点,因此只能为石头剪刀剪选择有效的选项

我想使用查询获取表的单行列中可用的多个数据如何做到这一点?

将非常大的一维数组写入工作表

有两个非常大的列表/集合 - 如何有效地检测和/或删除重复项

有效地删除一个非常大的文本文件的最后两行

我需要实现一个数组哈希表,该哈希表无需在开始时将数组初始化为null即可工作。任何线索如何做到这一点?

问:[Pandas]如何根据非常大的df中的姓名有效地向具有多个条目的个人分配唯一ID

有没有一种有效的算法可以做到这一点?

有没有更简单,有效或更短的方法来做到这一点?

如何在并行R中填充一个非常大的数组

有没有办法有效地计算Cassandra中一个非常大的分区的行?

我想创建一个 Excel 电子表格,其中每个工作表都是一个列表。关于我如何做到这一点的任何建议。我需要列出清单吗?

我有一个数据表。我想在毛伊岛打印它。我怎样才能做到这一点?或者类似于 wpf 的 DataGrid