1

我有一个这样设计的 SQL Server 数据库:

TableParameter
  Id    (int, PRIMARY KEY, IDENTITY)
  Name1 (string)
  Name2 (string, can be null)
  Name3 (string, can be null)
  Name4 (string, can be null)

TableValue
  Iteration         (int)
  IdTableParameter  (int, FOREIGN KEY)
  Type              (string)
  Value             (decimal)

因此,正如您刚刚了解的那样,TableValueTableParameter. TableParameter就像一个多维字典。

TableParameter应该有很多行(超过 300,000 行)

在我的 c# 客户端程序中,我必须在每个Compute()函数之后填充这个数据库:

for (int iteration = 0; iteration < 5000; iteration++)
{
    Compute();
    FillResultsInDatabase();
}

FillResultsInDatabase()方法上,我必须:

  1. 检查我的参数的标签是否已经存在于TableParameter. 如果它不存在,我必须插入一个新的。
  2. 我必须在TableValue

第1步需要很长时间!我将所有表加载到TableParameterIEnumerable 属性中,然后为每个参数创建一个

.FirstOfDefault( x => x.Name1 == item.Name1 &&
                      x.Name2 == item.Name2 &&
                      x.Name3 == item.Name3 &&
                      x.Name4 == item.Name4 );

为了检测它是否已经存在(以及之后获取id)。

这样的表现非常糟糕!

我试图用WHEREword 进行选择以避免加载每一行TableParameter但性能更差!

如何提高第 1 步的性能?

对于第 2 步,classic 的性能仍然很差INSERT。我要试试SqlBulkCopy

如何提高第 2 步的性能?

已编辑

我尝试过使用 Store Procedure :

CREATE PROCEDURE GetIdParameter
    @Id     int OUTPUT,
    @Name1  nvarchar(50) = null,
    @Name2  nvarchar(50) = null,
    @Name3  nvarchar(50) = null
AS
SELECT TOP 1 @Id = Id FROM TableParameter
WHERE
TableParameter.Name1 = @Name1   
AND
(@Name2 IS NULL OR TableParameter.Name2= @Name2)
AND
(@Name3 IS NULL OR TableParameter.Name3 = @Name3)
GO

CREATE PROCEDURE CreateValue
    @Iteration int,
    @Type   nvarchar(50),
    @Value  decimal(32, 18),
    @Name1  nvarchar(50) = null,
    @Name2  nvarchar(50) = null,
    @Name3  nvarchar(50) = null
AS
DECLARE @IdParameter int
EXEC GetIdParameter @IdParameter OUTPUT, 
                    @Name1, @Name2, @Name3
IF @IdParameter IS NULL
BEGIN
    INSERT TablePArameter (Name1, Name2, Name3) 
                               VALUES
                              (@Name1, @Name2, @Name3)

    SELECT @IdParameter= SCOPE_IDENTITY()
END
  INSERT TableValue (Iteration, IdParamter, Type, Value) 
                              VALUES
                              (@Iteration, @IdParameter, @Type, @Value)
GO

我仍然有相同的表现...... :-((不可接受)

4

4 回答 4

2

如果我了解发生了什么,您正在查询数据库以查看步骤 1 中是否存在数据。如果数据不存在,我将使用对存储过程的 db 调用来插入数据。所以只需计算结果并传递给 sp。

能不能先计算结果,再分批插入?

计算函数是否从数据库中获取数据?如果是这样,您可以将操作转换为基于集合的操作并在服务器本身上执行它吗?或者可能是其中的一部分?

请记住,sql server 是为大型数据集操作而设计的。

编辑:反映评论 由于数据插入的代码很慢,并且您怀疑这是因为插入必须在完成之前进行搜索,我建议您可能需要在您搜索的列上放置 SQL 索引以提高搜索速度。

不过我有另一个想法。

为什么不直接插入数据而不进行检查,然后在读取数据时删除该查询中的重复项?

于 2010-10-12T10:49:57.733 回答
0

鉴于 name2 - name3 可以为空,是否可以重构参数表:

TableParameter
  Id    (int, PRIMARY KEY, IDENTITY)
  Name  (string)
  Dimension int

现在您可以索引它并简化查询。(其中名称 = "TheNameIWant" AND Dimension="2")

(说到索引,您确实对参数表中的名称列进行了索引吗?)

你在哪里做插入的提交?如果您执行一个语句提交,请将多个插入分组为一个。

如果您是唯一一个插入值的人,如果速度真的很重要,请将数据库中的所有值加载到内存中并在那里检查。

只是一些想法

hth

马里奥

于 2010-10-12T11:12:19.330 回答
0

我必须承认,我正在努力掌握您在这里尝试实现的业务流程。

初步审查时,您似乎正在应用程序层内执行数据比较。我建议不要这样做,并建议您让数据库引擎完成它的设计目的,管理和实现您的数据访问。

正如另一位海报所提到的,我同意您应该创建一个存储过程来处理您的记录插入逻辑。该过程可以执行简单的检查以查看您的记录是否已经存在。

您还应该考虑:

  • 通过在四个名称列中创建唯一约束来强制执行插入逻辑/规则。
  • 创建包含四个名称列的覆盖非聚集索引。

关于插入的性能,也许您可​​以提供一些指标来限定您所看到的内容以及您如何衡量它?

为了给你一个标准,SQL Server 的当前 ETL 插入记录大约是每秒 1600 万行。您期待并希望看到什么样的数字?

于 2010-10-12T13:30:30.533 回答
0

最快的方法(到目前为止我知道)是批量插入。但不仅仅是 INSERT 行。尝试插入+选择+联合。它工作得非常快。

insert into myTable
select a1, b1, c1, ...
union select a2, b2, c2, ...
union select a3, b3, c3, ...
于 2010-10-12T13:44:12.527 回答