多线程PowerShell脚本可更快地从大型XML文件中提取数据
下面的脚本按预期工作以获得所需的输出,但处理大型XML文件(2GB及以上)需要很长时间。请专家就如何通过多线程或在powershell脚本中使用其他技术来提高速度提出建议 参考文章-了解以下脚本的逻辑: 输出:多线程PowerShell脚本可更快地从大型XML文件中提取数据,powershell,Powershell,下面的脚本按预期工作以获得所需的输出,但处理大型XML文件(2GB及以上)需要很长时间。请专家就如何通过多线程或在powershell脚本中使用其他技术来提高速度提出建议 参考文章-了解以下脚本的逻辑: 输出: PRIORITY KEY HITS -------- --- ---- 1 1 1 -3 2 2 -14 2 3 <ABC-FOF-PROCESS> <H> <PRIORITY>-
PRIORITY KEY HITS
-------- --- ----
1 1 1
-3 2 2
-14 2 3
<ABC-FOF-PROCESS>
<H>
<PRIORITY>-14</PRIORITY>
<KEY>F637A146-3437AB82-BA659D4A-17AC7FBF</KEY>
</H>
<H>
<PRIORITY>-14</PRIORITY>
<KEY>F637A146-3437AB82-BA659D4A-17AC7FBF</KEY>
</H>
<H>
<PRIORITY>-3</PRIORITY>
<KEY>D6306210-CF424F11-8E2D3496-E6CE1CA7</KEY>
</H>
<H>
<PRIORITY>1</PRIORITY>
<KEY>D6306210-CF424F11-8E2D3496-E6CE1CA7</KEY>
</H>
<H>
<PRIORITY>-3</PRIORITY>
<KEY>4EFR02B4-ADFDAF12-3C123II2-ADAFADFD</KEY>
</H>
<H>
<PRIORITY>-14</PRIORITY>
<KEY>5D2702B2-ECE8F1FB-3CEC3229-5FE4C4BC</KEY>
</H>
</ABC-FOF-PROCESS>
xml:
PRIORITY KEY HITS
-------- --- ----
1 1 1
-3 2 2
-14 2 3
<ABC-FOF-PROCESS>
<H>
<PRIORITY>-14</PRIORITY>
<KEY>F637A146-3437AB82-BA659D4A-17AC7FBF</KEY>
</H>
<H>
<PRIORITY>-14</PRIORITY>
<KEY>F637A146-3437AB82-BA659D4A-17AC7FBF</KEY>
</H>
<H>
<PRIORITY>-3</PRIORITY>
<KEY>D6306210-CF424F11-8E2D3496-E6CE1CA7</KEY>
</H>
<H>
<PRIORITY>1</PRIORITY>
<KEY>D6306210-CF424F11-8E2D3496-E6CE1CA7</KEY>
</H>
<H>
<PRIORITY>-3</PRIORITY>
<KEY>4EFR02B4-ADFDAF12-3C123II2-ADAFADFD</KEY>
</H>
<H>
<PRIORITY>-14</PRIORITY>
<KEY>5D2702B2-ECE8F1FB-3CEC3229-5FE4C4BC</KEY>
</H>
</ABC-FOF-PROCESS>
-14
F637A146-3437AB82-BA659D4A-17AC7FBF
-14
F637A146-3437AB82-BA659D4A-17AC7FBF
-3
D6306210-CF424F11-8E2D3496-E6CE1CA7
1.
D6306210-CF424F11-8E2D3496-E6CE1CA7
-3
4EFR02B4-ADFDAF12-3C123II2-ADAFADFD
-14
5D2702B2-ECE8F1FB-3CEC3229-5FE4C4BC
我想这是一个例子,重点放在单个命令()上,而不是完成解决方案
总的来说,我建议您查看整个解决方案,而不仅仅是单个语句
在您的例子中,如果仅仅因为要使用Foreach
语句而需要实例化一个脚本并使用调用该脚本,您可能会超出目标:
对于您提供的小文件,这(将管道与
ForEach对象一起使用)
:
显示速度通常快于此(使用ForEach
语句和Call操作符):
由于
Sort Object
cmdlet的性质(所有对象都必须能够对其进行排序),它需要暂停管道以对其进行重新排序,出于同样的原因,多线程方法可能没有多大意义。如果xml是固定格式,您可以逐行读取文件,并在运行时调整结果
它不是并行的,它不如使用xml解析功能那么健壮,它不会赢得任何美貌奖,但它应该非常快
$hits = @{} # Hashtable containing number of hits per priority
$keys = @{} # Hashtable containing unique keys per priority
switch -Regex -File $env:temp\test.xml
{
'^\s+<PRIORITY>(?<priority>[-]?\d+)'
{
$currentPriority = $matches.Priority
$hits[$currentPriority] = $hits[$currentPriority]+1
continue
}
'^\s+<KEY>(?<key>[\w-]+)'
{
$currentKey = $matches.Key
if ($keys[$currentPriority] -eq $null) {$keys[$currentPriority] = @{}}
$keys[$currentPriority][$currentKey] = $null
}
}
$hits.GetEnumerator() | % {
[PSCustomObject]@{
PRIORITY = [int]$_.Key
KEY = $keys[$_.Key].Count
HITS = [int]$_.Value
}
} | Sort PRIORITY -Descending
现在需要多长时间?什么样的时间是可以接受的?使用此脚本处理3 GB文件大约需要9个小时,解决此问题的主要目标是使用此脚本在很短的时间内找到统计信息,最有可能在15分钟内找到,而不是将XML加载到数据库中,然后使用sql查找统计信息(将文件加载到数据库大约需要12小时)。将整个XML转换为CSV格式,并带有列作为优先级和键。加载到数据库中并在SQL中进行求和。不要在数据库中使用XML数据类型,这样效率很低。@vonPryz我不想将数百万条记录加载到数据库中以获取此统计数据,相反,我需要动态获取统计数据,因此数据库管理将减少。因为此脚本t尚未最终确定,目前我们正在将XML加载到DB,但不幸的是,由于我们为该解决方案设置的软件限制,我们无法将XML转换为CSV,正如您所说,这将更加有效。感谢您的回答,我将很快对此进行测试,并将分享我的反馈。我能够启动脚本并使用它运行代码中有一点小小的调整。您共享的脚本有助于解决前所未有的问题,因为输入XML具有STX.etc等控制字符,因为解决方案基于regex,这是有益的。而且脚本在完成任务方面非常快。早些时候,我不得不坚持备份计划,以完全依赖python脚本传统上被认为是高效的,但在我的例子中,你的脚本为我工作。谢谢!用一个大的XML文件(2.4GB)测试它在16分钟内完成,这是令人惊讶的。我的一个关键测试用例,重点是脚本的逻辑,失败了-测试用例的详细信息在我的另一篇文章中更新。为了解决这个问题,我将键和优先级推到一个哈希表,然后再次键和点击到另一个哈希表,我让循环通过两个表来分组并获得最大值嗯,优先级和点击总数。谢谢你们的回答,我会很快测试,我会分享我的反馈。
$hits = @{} # Hashtable containing number of hits per priority
$keys = @{} # Hashtable containing unique keys per priority
switch -Regex -File $env:temp\test.xml
{
'^\s+<PRIORITY>(?<priority>[-]?\d+)'
{
$currentPriority = $matches.Priority
$hits[$currentPriority] = $hits[$currentPriority]+1
continue
}
'^\s+<KEY>(?<key>[\w-]+)'
{
$currentKey = $matches.Key
if ($keys[$currentPriority] -eq $null) {$keys[$currentPriority] = @{}}
$keys[$currentPriority][$currentKey] = $null
}
}
$hits.GetEnumerator() | % {
[PSCustomObject]@{
PRIORITY = [int]$_.Key
KEY = $keys[$_.Key].Count
HITS = [int]$_.Value
}
} | Sort PRIORITY -Descending
PRIORITY KEY HITS
-------- --- ----
1 1 1000000
-3 2 2000000
-14 2 3000000
$timer
IsRunning Elapsed ElapsedMilliseconds ElapsedTicks
--------- ------- ------------------- ------------
False 00:02:25.7186698 145718 413249113