2010-10-12 82 views
1

我设计了这样一个SQL Server数据库:C#代码和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) 

因此,当你刚刚明白,TableValue链接到TableParameterTableParameter就像一个多维词典。

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

从我的C#的客户端程序,我有每个Compute()功能后,填补了这一数据库:

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

FillResultsInDatabase()方法,我必须:

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

第1步插入值,需要很长的时间!我加载所有的表TableParameter在IEnumerable的属性,然后,每个参数我为了做一个

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

来检测,如果它已经存在(后得到的ID)。

性能非常糟糕!

我试着用WHERE这个词做选择,以避免加载TableParameter的每一行,但性能更差!

如何提高步骤1的性能?

对于第2步,经典INSERT的性能依然不佳。我要去尝试SqlBulkCopy

如何提高步骤2的性能?

EDITED

我试着存储过程:

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 

我仍然有同样的性能... :-((不能接受)

回答

2

如果我没有理解发生了什么事情你正在查询数据库以查看数据是否存在于步骤1中。我会使用db调用存储过程来插入数据(如果它不存在),那么只需计算结果并传递给sp 。

您可以先计算结果,然后分批插入吗?

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

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

编辑:反映意见 由于代码是在数据插入慢,并且怀疑这是因为,刀片具有找回来可以做之前,我建议您可能需要将SQL为了提高搜索速度,您搜索的列上的索引。

但是我有另外一个想法。

你为什么不只是插入数据,而无需检查,再后来,当你读取数据删除重复在该查询?

+0

好的。我要去测试它。但在这种情况下,我无法做一个SqlBulkCopy来提高插入的性能(步骤2)? – 2010-10-12 10:54:43

+0

我需要在批量插入之前在数据库中获取我的参数的ID。 Compute()函数不会从数据库中获取任何数据。我无法在Compute()期间执行插入操作,因为我只在Compute()函数的结尾有结果。 – 2010-10-12 10:58:32

+0

否我的意思是将数据传递给SP,如果数据存在,让我们解决。 – 2010-10-12 11:50:51

0

鉴于名2 - NAME3可以为空,将有可能重组的参数表:

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

现在你可以索引,并简化查询。 (其中name =“TheNameIWant”和尺寸=“2”)

(和指数的讲,你有指数在参数表中的名称列?)

你在哪里做插入您的提交?如果你做一个语句提交,将多个插入组合成一个。

如果你是唯一一个插入值,如果速度是真正本质,从数据库中加载的所有值到内存中,并检查那里。

只是一些想法

心连心

马里奥

0

我必须承认,我挣扎把握,你正试图在这里实现了业务流程。

初次审查时,看起来好像您正在应用程序层内执行数据比较。我建议不要这样做,并建议让数据库引擎完成它旨在执行的任务,以管理和实施您的数据访问。

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

你还应该考虑:

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

关于插入的性能,也许你可以提供一些指标来限定你看到的是什么以及你如何测量它?

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

+0

感谢您的建议。你能看看我的SP(编辑后)吗? 我将在四个名称列和索引中添加唯一约束。 10 000行需要60秒以上:166行/秒...我想在不到1分钟的时间内添加10万行:1666行/秒将是很好的:-) – 2010-10-12 14:19:16

+1

看看你的程序看起来似乎您正在按记录级别处理记录。如另一张海报中所提到的,如果您设计一套基于解决方案的解决方案,您将看到显着提升的性能例如,创建一个临时表,其中包含要处理的所有记录并为连接谓词上的表建立索引,然后将LEFT OUTER与此表连接到TableParameter表中,然后插入不返回现有ID的记录。 – 2010-10-12 16:46:58

+0

谢谢!我已经用临时表编写了一些程序,并按照您的建议使用了LEFT OUTER join:从SQL Server中,性能非常好! 现在,我将尝试从我的c#程序调用这些过程。我讨厌看到我无法传递商店过程中的对象列表... – 2010-10-27 13:40:59

0

最快的方式(我知道迄今为止)是批量插入。但不仅仅是INSERT行。尝试插入+选择+联合。它工作得很快。

insert into myTable 
select a1, b1, c1, ... 
union select a2, b2, c2, ... 
union select a3, b3, c3, ...