Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/269.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/angularjs/21.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# C/SQL Server 2016-使用哈希值更新约1亿条记录_C#_.net_Sql Server_Hash - Fatal编程技术网

C# C/SQL Server 2016-使用哈希值更新约1亿条记录

C# C/SQL Server 2016-使用哈希值更新约1亿条记录,c#,.net,sql-server,hash,C#,.net,Sql Server,Hash,我需要能够从SQL Server 2016数据库表中读取大约1亿条记录,然后为一个或多个列生成哈希,并将这些记录写回表中 到目前为止,我已经尝试了一些对我们的需求来说太慢的解决方案。我正在配备i7-7700HQ处理器和32GB RAM的Dell XPS 15上测试此功能。首先,我尝试将T-SQLHashBytes函数与SHA1哈希一起使用,但在1亿条记录的测试数据集上,这需要花费几个小时以上的时间 当然,使用OleDbReader进行更新更慢,但瓶颈似乎在于记录的编写。现在,我使用SqlBulk

我需要能够从SQL Server 2016数据库表中读取大约1亿条记录,然后为一个或多个列生成哈希,并将这些记录写回表中

到目前为止,我已经尝试了一些对我们的需求来说太慢的解决方案。我正在配备i7-7700HQ处理器和32GB RAM的Dell XPS 15上测试此功能。首先,我尝试将T-SQLHashBytes函数与SHA1哈希一起使用,但在1亿条记录的测试数据集上,这需要花费几个小时以上的时间

当然,使用OleDbReader进行更新更慢,但瓶颈似乎在于记录的编写。现在,我使用SqlBulkCopy将修改后的记录复制到一个新的临时表中,这比更新现有表快得多。但是,我仍然需要40分钟来生成所有哈希值,而写回记录需要这一时间的倍数。理想情况下,我们希望整个操作在一小时内完成。有人知道我可以在哪里进一步优化吗。代码如下:

using (SqlConnection sourceConnection = new SqlConnection(connectionString))
{
sourceConnection.Open();

SqlDataAdapter adapter = new SqlDataAdapter("SELECT *  FROM [ContosoRetailDW].[dbo].[FactInventory]", sourceConnection);

var dataTable = new System.Data.DataTable();

adapter.FillSchema(dataTable, System.Data.SchemaType.Source);              

dataTable.Columns[2].DataType = typeof(string);
dataTable.Columns[2].MaxLength = 20;

adapter.Fill(dataTable);

for (int i = 0; i < dataTable.Rows.Count; i++)
{
    byte[] toHash = Encoding.UTF8.GetBytes((string)dataTable.Rows[i][2]);
    dataTable.Rows[i][2] = xxHash.CalculateHash(toHash).ToString("X");
}

using (SqlConnection destinationConnection = new SqlConnection(connectionString))
{
    destinationConnection.Open();

    using (SqlBulkCopy bulkCopy = new SqlBulkCopy(destinationConnection.ConnectionString))
    {
        bulkCopy.BatchSize = 100000;
        bulkCopy.DestinationTableName = "FactInventory_Hashed";
        bulkCopy.WriteToServer(dataTable);
    }
}

我已经尝试过使用批量复制批量大小,我正在使用一种非常快速的哈希算法

这或多或少是一个扩展的评论

在我看来,这种方法有以下缺点:

[1] 它将大量数据移动到SQL Server SQL DB->C App->SQL DB之外,这会生成大量的网络I/O。这是网络I/O-没错-但仍然是大量的I/O

[2] 它将大量数据加载到内存中。如果此应用程序与SQL Server数据库引擎在同一台计算机上执行,则可能会对同一台计算机上运行的其他应用程序(包括此处的SQL Server)产生内存压力

[3] 它在可能较大的表上生成两次扫描。第一个是选择。。。从…起第二个是给。。。{…}语句

我会尝试什么

我将把xxHash.CalculateHash方法作为CLR标量函数导入,请参见

然后我将使用下面的T-SQL脚本

USE ContosoRetailDW
GO

INSERT dbo.FactInventory_Hashed (..., HashCol)
SELECT ..., dbo.xxHash(CONVERT(VARCHAR(8000), fi.Column2) AS HashCol
FROM dbo.FactInventory AS fi
警告:如果SQLServer使用并行性,则至少在大型表上应该可以很好地执行此操作。由于使用标量函数,SQL Server可能会生成串行计划

ii如果上述执行计划插入。。。SELECT语句是串行的,那么我将使用批处理:

一个连接将处理ID介于1和1.000.000之间的所有行

另一个连接将处理1.000.001和2.000.000之间的所有ID


等等

将所有这些数据批处理成n行并并行运行操作?您当前的方法是将整个源表加载到内存中吗?你怎么不忘记呢?您可以尝试像和SSIS数据流这样的流方法,并在脚本转换中完成哈希。如果瓶颈是DB/IO,这些都不会对您有所帮助。您可以实现自己的DataReader来动态散列值,并将其用作通过SqlBulkCopy传输数据的源。处理海量数据的关键点是必须避免“逐个”操作。我们知道bulkcopy只是一个快速的尝试,但使用for或foreach循环逐个插入数百万行需要很长的过程。这种SQL函数的性能最好,不同于您强制的逐个SQL函数。此外,似乎你的限速步骤是一个接一个的循环。只需将其更改为foreach循环。foreach是最快的一个..CLR标量函数示例:该方法看起来不错,但当我尝试使用它时,我的哈希函数上出现了一个NullReferenceException,因为我试图使用示例中select的值。当我计算散列时,该值似乎还不存在。@DavidH::因为我对这个问题没有任何线索,所以我假设在SQCLR/C方法中未正确处理null。在我的示例中,这意味着源列fi.Column2可能有空值,而dbo.xxHash函数不能正确处理这些空值->NullReferenceException。
USE ContosoRetailDW
GO

INSERT dbo.FactInventory_Hashed (..., HashCol)
SELECT ..., dbo.xxHash(CONVERT(VARCHAR(8000), fi.Column2) AS HashCol
FROM dbo.FactInventory AS fi
INSERT dbo.FactInventory_Hashed (..., HashCol)
SELECT ..., dbo.xxHash(CONVERT(VARCHAR(8000), fi.Column2) AS HashCol
FROM dbo.FactInventory AS fi
WHERE fi.ID BETWEEN 1 AND 1000000
INSERT dbo.FactInventory_Hashed (..., HashCol)
SELECT ..., dbo.xxHash(CONVERT(VARCHAR(8000), fi.Column2) AS HashCol
FROM dbo.FactInventory AS fi
WHERE fi.ID BETWEEN 1000001 AND 2000000