Parallel.ForEach 到 运行 项目列表上的函数
Parallel.ForEach to run function on list of items
我有一长串 ID 填充的员工列表。我想将它们并行添加到数据库中以加快处理速度。 vb.net 中使用 parallel.foreach 对列表中的每个项目调用函数的正确语法是什么。以下是执行此操作的串行方式。
Dim employees As New List(Of Employee)()
For Each element As String In ids
Dim emp As New Employee(element)
employees.Add(emp)
Next
For Each emp In employees
emp.AddToDatabase()
Next
语法为:
Parallel.ForEach(employees, Sub(emp) emp.AddToDatabase())
但是,并行执行数据库插入实际上会更快是值得怀疑的。唯一可能的加速是在实际插入之前的开销,最后数据库一次只能对 table.
执行一个插入
您可以尝试加快插入速度的一件事是在一个查询中放置多个插入,即将员工分成小批。
这看起来像是 XY problem 您已经决定了解决方案。
我建议您最好退后一步,找出如何在一个查询中添加所有数据,而不是尽可能快地触发大量查询。通常,一个查询会比多个查询快。
您在评论中声明 "This is a simple example for a future more complicated problem," 所以我将举一个向 table 添加数据的示例,该 table 的列仅包含文件名和关键字,希望您可以将其扩展到你未来的用途。
一、table的定义:
CREATE TABLE [dbo].[Keywords](
[Filename] [nvarchar](256) NOT NULL,
[Keyword] [nvarchar](64) NOT NULL
) ON [PRIMARY]
然后数据库中用户定义的table类型:
CREATE TYPE [dbo].[filename_keyword_tbltype] AS TABLE(
[Filename] [nvarchar](256) NOT NULL,
[Keyword] [nvarchar](64) NOT NULL,
PRIMARY KEY CLUSTERED -- may not apply to you
(
[Keyword] ASC -- may not apply to you
)WITH (IGNORE_DUP_KEY = OFF) -- may not apply to you
)
需要对用户定义的table类型设置权限:
GRANT EXECUTE ON TYPE::[filename_tbltype] TO [APPROPRIATE\USER_GOES_HERE]
现在数据库已设置为创建一个存储过程来处理将要发送给它的数据:
CREATE PROCEDURE [dbo].[AddKeywords]
@Data [dbo].[filename_keyword_tbltype] ReadOnly
AS
BEGIN
SET NOCOUNT ON;
INSERT INTO Keywords
SELECT [Filename],[Keyword]
FROM @Data;
END
终于可以写代码一次性发送所有数据了:
Imports System.Data.SqlClient
Imports System.Data.SqlTypes
' ...
sqlcmd = New SqlCommand("AddKeywords", sqlConn)
sqlcmd.CommandType = CommandType.StoredProcedure
Dim tvpData As New List(Of SqlDataRecord)
Dim tvpDataType(1) As SqlMetaData
tvpDataType(0) = New SqlMetaData("Filename", SqlDbType.NVarChar, 256)
tvpDataType(1) = New SqlMetaData("Keyword", SqlDbType.NVarChar, 64)
' metadata.Keywords is a List(Of String) with the keywords for a file
For Each kwd In metadata.Keywords
Dim rec = New SqlDataRecord(tvpDataType)
' smallName is simply the filename
rec.SetSqlString(0, smallName)
rec.SetSqlString(1, kwd.ToLower(CultureInfo.InvariantCulture))
tvpData.Add(rec)
Next
sqlParam = New SqlParameter("@Data", SqlDbType.Structured)
sqlParam.TypeName = "filename_keyword_tbltype"
sqlParam.Value = tvpData
sqlcmd.Parameters.Add(sqlParam)
sqlConn.Open()
sqlcmd.ExecuteNonQuery()
sqlConn.Close()
请注意,所有数据都是一次性发送的,无论是一条记录还是一千条记录。
参考:Arrays and Lists in SQL Server 2008 - Using Table-Valued Parameters
我有一长串 ID 填充的员工列表。我想将它们并行添加到数据库中以加快处理速度。 vb.net 中使用 parallel.foreach 对列表中的每个项目调用函数的正确语法是什么。以下是执行此操作的串行方式。
Dim employees As New List(Of Employee)()
For Each element As String In ids
Dim emp As New Employee(element)
employees.Add(emp)
Next
For Each emp In employees
emp.AddToDatabase()
Next
语法为:
Parallel.ForEach(employees, Sub(emp) emp.AddToDatabase())
但是,并行执行数据库插入实际上会更快是值得怀疑的。唯一可能的加速是在实际插入之前的开销,最后数据库一次只能对 table.
执行一个插入您可以尝试加快插入速度的一件事是在一个查询中放置多个插入,即将员工分成小批。
这看起来像是 XY problem 您已经决定了解决方案。
我建议您最好退后一步,找出如何在一个查询中添加所有数据,而不是尽可能快地触发大量查询。通常,一个查询会比多个查询快。
您在评论中声明 "This is a simple example for a future more complicated problem," 所以我将举一个向 table 添加数据的示例,该 table 的列仅包含文件名和关键字,希望您可以将其扩展到你未来的用途。
一、table的定义:
CREATE TABLE [dbo].[Keywords](
[Filename] [nvarchar](256) NOT NULL,
[Keyword] [nvarchar](64) NOT NULL
) ON [PRIMARY]
然后数据库中用户定义的table类型:
CREATE TYPE [dbo].[filename_keyword_tbltype] AS TABLE(
[Filename] [nvarchar](256) NOT NULL,
[Keyword] [nvarchar](64) NOT NULL,
PRIMARY KEY CLUSTERED -- may not apply to you
(
[Keyword] ASC -- may not apply to you
)WITH (IGNORE_DUP_KEY = OFF) -- may not apply to you
)
需要对用户定义的table类型设置权限:
GRANT EXECUTE ON TYPE::[filename_tbltype] TO [APPROPRIATE\USER_GOES_HERE]
现在数据库已设置为创建一个存储过程来处理将要发送给它的数据:
CREATE PROCEDURE [dbo].[AddKeywords]
@Data [dbo].[filename_keyword_tbltype] ReadOnly
AS
BEGIN
SET NOCOUNT ON;
INSERT INTO Keywords
SELECT [Filename],[Keyword]
FROM @Data;
END
终于可以写代码一次性发送所有数据了:
Imports System.Data.SqlClient
Imports System.Data.SqlTypes
' ...
sqlcmd = New SqlCommand("AddKeywords", sqlConn)
sqlcmd.CommandType = CommandType.StoredProcedure
Dim tvpData As New List(Of SqlDataRecord)
Dim tvpDataType(1) As SqlMetaData
tvpDataType(0) = New SqlMetaData("Filename", SqlDbType.NVarChar, 256)
tvpDataType(1) = New SqlMetaData("Keyword", SqlDbType.NVarChar, 64)
' metadata.Keywords is a List(Of String) with the keywords for a file
For Each kwd In metadata.Keywords
Dim rec = New SqlDataRecord(tvpDataType)
' smallName is simply the filename
rec.SetSqlString(0, smallName)
rec.SetSqlString(1, kwd.ToLower(CultureInfo.InvariantCulture))
tvpData.Add(rec)
Next
sqlParam = New SqlParameter("@Data", SqlDbType.Structured)
sqlParam.TypeName = "filename_keyword_tbltype"
sqlParam.Value = tvpData
sqlcmd.Parameters.Add(sqlParam)
sqlConn.Open()
sqlcmd.ExecuteNonQuery()
sqlConn.Close()
请注意,所有数据都是一次性发送的,无论是一条记录还是一千条记录。
参考:Arrays and Lists in SQL Server 2008 - Using Table-Valued Parameters