加快将XML文件插入SQL Server表的速度

时间:2019-03-02 02:58:05

标签: sql sql-server xml powershell

我正在使用以下脚本使用powershell将大型XML文件(3.5Gb)插入本地SQL Server表'files_index,因为该文件超过了SQL的2 GB限制。

表结构如下,然后是PowerShell脚本。该文件包含约500万行,但要花很长时间插入,而此方法行之有效,并且确实正在寻找任何方法来加速它(目前大约需要15分钟)。

任何加快处理速度的建议,我都尝试过用批处理大小进行填充,但似乎并没有太大的区别,我不久前在stackoverflow上获得了此powershell脚本,但我只是想简化流程。感谢您的帮助或建议。

CREATE TABLE [dbo].[files_index]
(
    [Product_ID] [int] NOT NULL,
    [path] [varchar](100) NULL,
    [Updated] [varchar](50) NULL,
    [Quality] [varchar](50) NULL,
    [Supplier_id] [int] NULL,
    [Prod_ID] [varchar](100) NULL,
    [Catid] [int] NULL,
    [On_Market] [int] NULL,
    [Model_Name] [varchar](250) NULL,
    [Product_View] [varchar](250) NULL,
    [HighPic] [varchar](250) NULL,
    [HighPicSize] [int] NULL,
    [HighPicWidth] [int] NULL,
    [HighPicHeight] [int] NULL,
    [Date_Added] [varchar](150) NULL,

    CONSTRAINT [PK_files_index] 
        PRIMARY KEY CLUSTERED ([Product_ID] ASC)
                WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, 
                      IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, 
                      ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

PowerShell脚本:

Set-ExecutionPolicy Unrestricted -scope LocalMachine

[String]$global:connectionString = "Data Source=Apps2\Apps2;Initial 
Catalog=DTEDATA;Integrated Security=SSPI";
[System.Data.DataTable]$global:dt = New-Object System.Data.DataTable;
[System.Xml.XmlTextReader]$global:xmlReader = New-Object 
System.Xml.XmlTextReader("C:\Scripts\icecat\files.index.xml");
[Int32]$global:batchSize = 100000;

Function Add-FileRow() {
    $newRow = $dt.NewRow();
    $null = $dt.Rows.Add($newRow);

    $newRow["Product_ID"] = $global:xmlReader.GetAttribute("Product_ID");
    $newRow["path"] = $global:xmlReader.GetAttribute("path");
    $newRow["Updated"] = $global:xmlReader.GetAttribute("Updated");
    $newRow["Quality"] = $global:xmlReader.GetAttribute("Quality");
    $newRow["Supplier_id"] = $global:xmlReader.GetAttribute("Supplier_id");
    $newRow["Prod_ID"] = $global:xmlReader.GetAttribute("Prod_ID");
    $newRow["Catid"] = $global:xmlReader.GetAttribute("Catid");
    $newRow["On_Market"] = $global:xmlReader.GetAttribute("On_Market");
    $newRow["Model_Name"] = $global:xmlReader.GetAttribute("Model_Name");
    $newRow["Product_View"] = $global:xmlReader.GetAttribute("Product_View");
    $newRow["HighPic"] = $global:xmlReader.GetAttribute("HighPic");
    $newRow["HighPicSize"] = $global:xmlReader.GetAttribute("HighPicSize");
    $newRow["HighPicWidth"] = $global:xmlReader.GetAttribute("HighPicWidth");
    $newRow["HighPicHeight"] = $global:xmlReader.GetAttribute("HighPicHeight");
    $newRow["Date_Added"] = $global:xmlReader.GetAttribute("Date_Added");
}

# init data table schema
$da = New-Object System.Data.SqlClient.SqlDataAdapter("SELECT * FROM 
files_index WHERE 0 = 1", $global:connectionString);
$null = $da.Fill($global:dt);

$bcp = New-Object System.Data.SqlClient.SqlBulkCopy($global:connectionString);
$bcp.DestinationTableName = "dbo.files_index";

$recordCount = 0;

while($xmlReader.Read() -eq $true)
{

    if(($xmlReader.NodeType -eq [System.Xml.XmlNodeType]::Element) -and 
($xmlReader.Name -eq "file"))
    {
        Add-FileRow -xmlReader $xmlReader;
        $recordCount += 1;
        if(($recordCount % $global:batchSize) -eq 0) 
        {
            $bcp.WriteToServer($dt);
            $dt.Rows.Clear();
            Write-Host "$recordCount file elements processed so far";
        }
    }

}

if($dt.Rows.Count -gt 0)
{
    $bcp.WriteToServer($dt);
}

$bcp.Close();
$xmlReader.Close();

Write-Host "$recordCount file elements imported ";

catch
{
    throw;
}

1 个答案:

答案 0 :(得分:0)

距离足够近,可以标记为以下内容的重复...

Importing and parsing a large XML file in SQL Server (when “normal” methods are rather slow)

可接受的答案:

  

好。我在XML数据列上创建了XML索引。 (只是一个主要的   目前)。现在,花费约4:30分钟的查询现在花费约9秒!   似乎该表存储具有正确XML索引的XML和   用xml.nodes()函数解析数据是可行的   解决方案。

Improve performance of converting a large xml file (~300 MB) to relational table in SQL Server

可接受的答案:

  

我对此有另一种看法,可以重现您的问题。尝试添加   选项(MAXDOP 1)进行查询。在我的测试装备中,有300MB的文件   这花了1分钟42秒。未提示的版本运行了30分钟   在我杀死它之前以100%的CPU运行。您也可以看看OPENXML。   人们经常说使用大型XML文件更快,而且看起来   在这种情况下。但是,您应该了解与   OPENXML(例如可以占用1/8的缓冲池,是一种老式的COM   .dll,则必须调用sp_xml_removedocument等)。一旦你   研究了OPENXML的优缺点,您可以尝试类似   这个:

DECLARE @FileData XML

SELECT @FileData = BulkColumn
FROM OPENROWSET(BULK 'd:\temp\temp.xml', SINGLE_BLOB) AS x

DECLARE @hDoc int

EXEC sp_xml_preparedocument @hDoc OUTPUT, @FileData 

SELECT *
INTO #tmp
FROM OPENXML( @hDoc, '/Data/Entities/Entity/Attributes/Attribute/Values/Value', 1 ) 
WITH
    (
    Id VARCHAR(50) '../../../../@Id',
    Name VARCHAR(100) '../../../../@Name',
    AttributeName VARCHAR(100)  '../../@AttributeName',
    AttributeValue VARCHAR(MAX) '.'
    )

EXEC sp_xml_removedocument @hDoc
  

老实说,由于这些问题,我最近尽量避免使用它。是什么   当您仅将1/8的数据包进去时,查询的速度会更快   缓冲池?最后,最快,最可扩展的方法(IMHO)是   SSIS。该版本与   以上方法在我的钻机上。 SSIS XML导入方法创建一个包,添加   一个数据流任务,添加一个XML Source,然后添加每个表。我创建了一个   300MB档案,与您的档案结构相同,大约10颗档案   秒,例如