C# 使用从并行线程运行的Create index、table和procedure的SQL查询
我对从并行线程执行的查询有问题。 关于索引|表类型|过程|表已经存在,我几乎总是会出错 我非常确定我的sql查询是针对该错误进行保护的,它永远不会出现 此查询应该能够从并发线程运行,不会出现任何错误 我在做什么:C# 使用从并行线程运行的Create index、table和procedure的SQL查询,c#,sql,entity-framework-6,sql-server-2016,C#,Sql,Entity Framework 6,Sql Server 2016,我对从并行线程执行的查询有问题。 关于索引|表类型|过程|表已经存在,我几乎总是会出错 我非常确定我的sql查询是针对该错误进行保护的,它永远不会出现 此查询应该能够从并发线程运行,不会出现任何错误 我在做什么: 我有数百个文件,每个文件包含数百万行 每行包含我需要插入到特定表中的对象 如果表/索引/过程不存在,我需要创建它 目前,这是相当好的工作,除了这个错误,不应该出现 我的查询代码(创建索引时): } 我已经标记了(…)代码,其中实际上没有什么重要的事情发生——只是一些数据处理 DB是实体
Parallel.ForEach(timeSeriesFiles, file =>
{
(...)
// FOREACH LINE
foreach (string line in File.ReadLines(file))
{
(...)
using (var db = Context.DB)
{
db.CreateIndex(tableName(line));
}
(...)
}
}
如果您能提供任何建议或线索,我将不胜感激。您收到此错误,因为至少有两个线程试图同时创建索引/存储过程/表。我在您的SQL中没有看到任何可以防止此错误的内容。我建议实现某种锁定机制来处理此错误。您可以在SQL或代码中执行此操作-无论哪种方式,逻辑基本相同:
使用(TABLOCKX)从tableName中选择1
您收到此错误是因为至少有两个线程试图同时创建索引/存储过程/表。我在您的SQL中没有看到任何可以防止此错误的内容。我建议实现某种锁定机制来处理此错误。您可以在SQL或代码中执行此操作-无论哪种方式,逻辑基本相同:
使用(TABLOCKX)从tableName中选择1
sb.AppendFormat(@"
begin tran
IF NOT EXISTS(SELECT * FROM sys.indexes
WHERE name='TimeSeries_DateStamp_{0}' AND object_id = OBJECT_ID('{0}'))
exec(' CREATE UNIQUE CLUSTERED INDEX TimeSeries_DateStamp_{0} ON [dbo].[{0}]
(
[TimeSeriesID] ASC,
[DateStamp] ASC
) WITH (
PAD_INDEX = OFF,
STATISTICS_NORECOMPUTE = OFF,
SORT_IN_TEMPDB = OFF,
IGNORE_DUP_KEY = OFF,
DROP_EXISTING = OFF,
ONLINE = OFF,
ALLOW_ROW_LOCKS = ON,
ALLOW_PAGE_LOCKS = ON)
ON [PRIMARY] ');
commit", tableName);
或者您可以使用使用事务。
对于exlamle,请修改脚本:
sb.AppendFormat(@"
begin tran
IF NOT EXISTS(SELECT * FROM sys.indexes
WHERE name='TimeSeries_DateStamp_{0}' AND object_id = OBJECT_ID('{0}'))
exec(' CREATE UNIQUE CLUSTERED INDEX TimeSeries_DateStamp_{0} ON [dbo].[{0}]
(
[TimeSeriesID] ASC,
[DateStamp] ASC
) WITH (
PAD_INDEX = OFF,
STATISTICS_NORECOMPUTE = OFF,
SORT_IN_TEMPDB = OFF,
IGNORE_DUP_KEY = OFF,
DROP_EXISTING = OFF,
ONLINE = OFF,
ALLOW_ROW_LOCKS = ON,
ALLOW_PAGE_LOCKS = ON)
ON [PRIMARY] ');
commit", tableName);
或者你也可以用我在史蒂佛和马克西姆·埃罗什金的帮助下最终取得的成就 是: 创建新存储过程的代码(我遇到了最大的问题) 重要的是要添加锁,对于存储过程BEGIN TRY和BEGIN CATCH也是如此。
这是我找到的最好的方法。多亏了史蒂佛和马克西姆·埃罗什金,我终于实现了目标 是: 创建新存储过程的代码(我遇到了最大的问题) 重要的是要添加锁,对于存储过程BEGIN TRY和BEGIN CATCH也是如此。 这是我找到的最好的方法
sb.AppendFormat(@"BEGIN TRAN
IF NOT EXISTS ( SELECT *
FROM sys.procedures AS T
WITH (TABLOCKX)
INNER JOIN sys.schemas AS S ON T.schema_id = S.schema_id
WHERE S.Name = 'dbo' AND T.Name = 'BulkMerge{0}' )
BEGIN
SELECT 1 FROM sys.procedures WITH (TABLOCKX)
IF NOT EXISTS ( SELECT *
FROM sys.procedures AS T
WITH (TABLOCKX)
INNER JOIN sys.schemas AS S ON T.schema_id = S.schema_id
WHERE S.Name = 'dbo' AND T.Name = 'BulkMerge{0}' )
BEGIN TRY
EXEC('
CREATE PROCEDURE [dbo].[BulkMerge{0}]
@table [Bulk{0}] READONLY
AS
BEGIN
SET NOCOUNT ON;
MERGE INTO {0} t1
USING @table t2
ON t1.[TimeSeriesID] = t2.[TimeSeriesID] AND t1.[DateStamp] = t2.[DateStamp]
WHEN MATCHED
THEN UPDATE SET {1}
WHEN NOT MATCHED
THEN INSERT VALUES (t2.TimeSeriesID, t2.DateStamp {2} );
END
')
END TRY BEGIN CATCH END CATCH
END
COMMIT ", tableName, fieldsSB, insertSB);