You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用PowerShell高效将Mongo导出的JSON导入SQL Server表?

批量导入Mongo导出的JSON到SQL Server的性能优化问题

场景与问题背景

需要用PowerShell将Mongo的Export-MdbcData工具导出的JSON文件导入SQL Server表,示例JSON为每行一条独立对象(JSON Lines格式):

{ "code" : "0088", "name" : "BUTTON", "detail" : { "quantity" : 1 } }
{ "code" : "0081", "name" : "MATTERHORN", "detail" : { "quantity" : 2 } }
{ "code" : "0159", "name" : "BANKSTON", "detail" : { "quantity" : 1 } }

初始脚本采用读入数组转DataTable的方式,小文件导入仅需几秒,但处理400万+条记录时耗时数小时,急需更高效的JSON读取解析方案。

已做优化及现状

采纳建议修改脚本,移除内部foreach循环后,400万+条记录导入耗时降至约17分钟(批量大小设为80K,每次插入约14秒),但同规模CSV文件每次插入仅需3秒,推测JSON解析的开销远高于分隔符格式。修改后的脚本如下:

foreach ($line in [System.IO.File]::ReadLines($pathToJsonFile, $encoding)) 
{
    $json = $line | ConvertFrom-Json;
    [void]$dataTable.Rows.Add($json.code, $json.name, $json.detail.quantity);
    $i++; 
    if (($i % $batchsize) -eq 0) { 
        $bulkcopy.WriteToServer($dataTable) 
        Write-Host "$i rows have been inserted in $($elapsed.Elapsed.ToString())."
        $datatable.Clear() 
    }
}

进一步优化方案

针对JSON解析性能瓶颈,可从以下几个方向优化:

1. 替换内置ConvertFrom-Json为高效解析库

PowerShell内置的ConvertFrom-Json基于旧版.NET解析器,性能有限。推荐使用System.Text.Json(.NET Core/.NET 5+自带,Windows PowerShell需手动导入),其解析速度比内置命令提升数倍:

# 导入System.Text.Json程序集(Windows PowerShell需执行,PowerShell Core可省略)
Add-Type -AssemblyName System.Text.Json

# 预定义DataTable结构,避免动态类型开销
$dataTable = New-Object System.Data.DataTable
$dataTable.Columns.Add("code", [string]) | Out-Null
$dataTable.Columns.Add("name", [string]) | Out-Null
$dataTable.Columns.Add("quantity", [int]) | Out-Null

$i = 0
$batchsize = 80000
$elapsed = [System.Diagnostics.Stopwatch]::StartNew()

foreach ($line in [System.IO.File]::ReadLines($pathToJsonFile, $encoding)) {
    # 使用System.Text.Json解析单行JSON,直接取值避免动态对象开销
    $jsonDoc = [System.Text.Json.JsonDocument]::Parse($line)
    $code = $jsonDoc.RootElement.GetProperty("code").GetString()
    $name = $jsonDoc.RootElement.GetProperty("name").GetString()
    $quantity = $jsonDoc.RootElement.GetProperty("detail").GetProperty("quantity").GetInt32()
    
    [void]$dataTable.Rows.Add($code, $name, $quantity)
    $i++

    if (($i % $batchsize) -eq 0) {
        $bulkcopy.WriteToServer($dataTable)
        Write-Host "$i rows inserted in $($elapsed.Elapsed.ToString())"
        $dataTable.Clear()
        $jsonDoc.Dispose() # 手动释放资源,避免内存泄漏
    }
}

# 处理剩余未批量提交的记录
if ($dataTable.Rows.Count -gt 0) {
    $bulkcopy.WriteToServer($dataTable)
    Write-Host "Total $i rows inserted in $($elapsed.Elapsed.ToString())"
}
$elapsed.Stop()

2. 批量读取+批量解析

一次性读取多行JSON(比如一次读取10000行),减少IO操作的频次,进一步降低开销:

$reader = [System.IO.StreamReader]::new($pathToJsonFile, $encoding)
$parseBatchSize = 10000
$batchLines = @()

while (!$reader.EndOfStream) {
    $batchLines += $reader.ReadLine()
    if ($batchLines.Count -ge $parseBatchSize) {
        foreach ($line in $batchLines) {
            # 沿用上述System.Text.Json解析逻辑
            $jsonDoc = [System.Text.Json.JsonDocument]::Parse($line)
            # ... 取值并添加到DataTable
            $jsonDoc.Dispose()
        }
        $batchLines = @()
    }
}

# 处理剩余行
foreach ($line in $batchLines) {
    # 解析逻辑同上
}
$reader.Close()
$reader.Dispose()

3. 调整批量插入的最优大小

当前80K的批量大小可能并非最优值,可测试50K、100K等不同批量,找到SQL Server SqlBulkCopy的平衡点——过大的批量会占用过多内存,过小则会增加数据库交互次数。

4. 提前禁用DataTable的约束检查

在批量添加行之前,禁用DataTable的约束和索引检查,能减少插入时的验证开销:

$dataTable.EnforceConstraints = $false
# 批量添加行逻辑...
$dataTable.EnforceConstraints = $true

内容的提问来源于stack exchange,提问作者cenko

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 18:43:08