BaseX - XQuery - 将结果写入 CSV 文件时内存不足
BaseX - XQuery - Out of memory when writing results to CSV file
我正在尝试将 XQuery 结果写入 CSV 文件,请参阅附加代码(产生至少 160 万行,可能会变得更多......)。
然而,在执行几分钟后,程序失败并出现 'out of main memory' 错误。我使用的是 4GB 内存的笔记本电脑。我原以为写入文件可以防止内存瓶颈。另外,我已经在使用 copynode-false pragma。
我可能以错误的方式处理代码,因为这是我的第一个 XQuery/BaseX-program。或者,如果没有额外的硬件,这可能无法解决。(当前数据库大小:3092 MB;节点:142477344)任何帮助将不胜感激!
let $params :=
<output:serialization-parameters xmlns:output="http://www.w3.org/2010/xslt-xquery-serialization">
<output:method value="csv"/>
<output:csv value="header=yes, separator=semicolon"/>
</output:serialization-parameters>
return file:write(
'/tmp/output.csv',
(# db:copynode false #){<csv>{
for $stand in //*:stand
return <record>{$stand//*:kenmerk}</record>
(: {$stand//*:identificatieVanVerblijfsobject}
{$stand//*:inOnderzoek}
{$stand//*:documentdatum}
{$stand//*:documentnummer} :)
}</csv>},
$params
)
使用 copynode
pragma 来节省内存是个好主意。在给定的情况下,可能是新创建的元素节点的总数会在数据写入磁盘之前简单地消耗太多内存。
如果您有大型数据集,xquery
序列化格式可能是更好的选择。映射和数组消耗的内存少于 XML 个节点:
let $params := map {
'format': 'xquery',
'header': true(),
'separator': 'semicolon'
}
let $data := map {
'names': [
'kenmerk', 'inOnderzoek'
],
'records': (
for $stand in //*:stand
return [
string($stand//*:kenmerk),
string($stand//*:inOnderzoek)
]
)
}
return file:write-text(
'/tmp/output.csv',
csv:serialize($data, $params)
)
另一种方法是使用 window
子句并将结果写入块中:
for tumbling window $stands in //*:stand
start at $s when true()
end at $e when $e - $s eq 100000
let $first := $s = 1
let $path := '/tmp/output.csv'
let $csv := <csv>{
for $stand in $stands
return <record>{
$stand//*:kenmerk,
$stand//*:inOnderzoek
}</record>
}</csv>
let $params := map {
'method': 'csv',
'csv': map {
'separator': 'semicolon',
'header': $first
}
}
return if ($first) then (
file:write($path, $csv, $params)
) else (
file:append($path, $csv, $params)
)
第一次写入操作后,后续 table 行将附加到原始文件。块大小(此处:每个循环 100000 行)可以自由调整。与您的原始代码类似,序列化参数也可以指定为 XML;当然也可以在第二个例子中使用 xquery
序列化格式。
我正在尝试将 XQuery 结果写入 CSV 文件,请参阅附加代码(产生至少 160 万行,可能会变得更多......)。 然而,在执行几分钟后,程序失败并出现 'out of main memory' 错误。我使用的是 4GB 内存的笔记本电脑。我原以为写入文件可以防止内存瓶颈。另外,我已经在使用 copynode-false pragma。
我可能以错误的方式处理代码,因为这是我的第一个 XQuery/BaseX-program。或者,如果没有额外的硬件,这可能无法解决。(当前数据库大小:3092 MB;节点:142477344)任何帮助将不胜感激!
let $params :=
<output:serialization-parameters xmlns:output="http://www.w3.org/2010/xslt-xquery-serialization">
<output:method value="csv"/>
<output:csv value="header=yes, separator=semicolon"/>
</output:serialization-parameters>
return file:write(
'/tmp/output.csv',
(# db:copynode false #){<csv>{
for $stand in //*:stand
return <record>{$stand//*:kenmerk}</record>
(: {$stand//*:identificatieVanVerblijfsobject}
{$stand//*:inOnderzoek}
{$stand//*:documentdatum}
{$stand//*:documentnummer} :)
}</csv>},
$params
)
使用 copynode
pragma 来节省内存是个好主意。在给定的情况下,可能是新创建的元素节点的总数会在数据写入磁盘之前简单地消耗太多内存。
如果您有大型数据集,xquery
序列化格式可能是更好的选择。映射和数组消耗的内存少于 XML 个节点:
let $params := map {
'format': 'xquery',
'header': true(),
'separator': 'semicolon'
}
let $data := map {
'names': [
'kenmerk', 'inOnderzoek'
],
'records': (
for $stand in //*:stand
return [
string($stand//*:kenmerk),
string($stand//*:inOnderzoek)
]
)
}
return file:write-text(
'/tmp/output.csv',
csv:serialize($data, $params)
)
另一种方法是使用 window
子句并将结果写入块中:
for tumbling window $stands in //*:stand
start at $s when true()
end at $e when $e - $s eq 100000
let $first := $s = 1
let $path := '/tmp/output.csv'
let $csv := <csv>{
for $stand in $stands
return <record>{
$stand//*:kenmerk,
$stand//*:inOnderzoek
}</record>
}</csv>
let $params := map {
'method': 'csv',
'csv': map {
'separator': 'semicolon',
'header': $first
}
}
return if ($first) then (
file:write($path, $csv, $params)
) else (
file:append($path, $csv, $params)
)
第一次写入操作后,后续 table 行将附加到原始文件。块大小(此处:每个循环 100000 行)可以自由调整。与您的原始代码类似,序列化参数也可以指定为 XML;当然也可以在第二个例子中使用 xquery
序列化格式。