2017-03-05 54 views
1

我遇到了一个应用程序的问题,该应用程序正在引导我执行以下操作。在C#代码中优化SQL函数

protected override int GetCount(List<int> itemlist) 
{ 
    sql.Execute(@"TRUNCATE Table table0"); 
    int count = 0; 

    foreach (int itemgroup in itemlist) 
    { 
     count += sql.Execute(@" INSERT INTO table0 (ID, Guid) 
            SELECT table1.ID , table1.Guid 
            FROM dbo.tablefunction(@p0) table1 LEFT JOIN 
              dbo.table0 ON table1.ID = table0.ID 
            WHERE table0.ID IS NULL", itemgroup); 
    } 
    return count; 
} 

我是插入循环这是不完全出乎意料期间运行到一个关键的制约问题。

但我也注意到它可能会做多个不同大小的插入,所以我正在寻找动态组装联合查询的想法/建议,然后一次插入所有结果。例如,生成的查询可能是

WITH b AS 
(
    SELECT table1.ID , table1.Guid 
    FROM dbo.tablefunction(item0) table1 LEFT JOIN 
      dbo.table0 ON table1.ID = table0.ID 
    WHERE table0.ID IS NULL 

    UNION 

    SELECT table1.ID , table1.Guid 
    FROM dbo.tablefunction(item1) table1 LEFT JOIN 
      dbo.table0 ON table1.ID = table0.ID 
    WHERE table0.ID IS NULL 
) 
INSERT INTO table0 (ID, Guid) 
SELECT * FROM b 

我只是不确定如何最好地去做。

+0

它不是真的与您的动态大小的插入相关,但可以从多个位置同时调用此代码吗?如果是这样,如果在插入值之后表由另一个实例获取TRUNCATEd会发生什么情况,那么您不再拥有应该具有的值,而只需要一个空表而已? – seventyeightist

+0

有一个锁可以防止它同时运行。但是它所插入的表格也被序列中的下一组方法所使用,然后冲洗并重复,因此截断。有可能有更好的方法来完成整个事情,但我希望保持这种变化独立于这种方法,以避免更大的回归 –

+0

那么,编写union声明时会出现什么问题?看起来像一堆字符串连接。 – Evk

回答

0

使用的String.Format()方法:

protected override int GetCount(List<int> itemlist) 
     { 
      sql.Execute(@"TRUNCATE Table table0"); 
      int count = 0; 

      foreach (int itemgroup in itemlist) 
      { 
       string sql = string.Format(@" INSERT INTO table0 (ID, Guid) 
            SELECT table1.ID , table1.Guid 
            FROM dbo.tablefunction({0}) table1 LEFT JOIN 
              dbo.table0 ON table1.ID = table0.ID 
            WHERE table0.ID IS NULL", itemgroup); 

       count += sql.Execute(sql); 
      } 
      return count; 
     } 
+0

sql.Execute方法已经在代码中的其他地方执行了。我试图解决的问题是,这个foreach循环重新运行相同的小查询,并做大量不同的插入,我想合并成一个更高效的插入 –

+0

String sql =空字符串,然后连接到它在循环的每次迭代中(就像你基本上完成的那样)?但是sql.execute将不得不在循环之外,并且生成的字符串 - 一旦你连接了所有需要的语句 - 只执行一次,那么只有一次往返。 – seventyeightist

+0

你为什么不止一次这样做?在发布的代码和其他地方? – jdweng

0

你可以使用Table-Valued Parameters - msdn和存储过程来做到这一点。

首先,你需要创建一个程序使用一个表类型:

create type dbo.ItemGroups_udt as table (ItemGroup int not null); 
go 

然后,创建的过程:如果您在到约束violoations则不同

create procedure dbo.table0_truncate_and_insert (
    @ItemGroups as dbo.ItemGroups_udt readonly 
) as 
begin; 
    set nocount, xact_abort on; 

    truncate table table0; 

    insert into table0 (id, guid) 
    select tvf.id, tvf.guid 
    from @ItemGroups as i 
    cross apply dbo.tablefunction(i.ItemGroup) as tvf; 

end; 
go 

,可能需要分组或其他条件

然后,汇编并将项目组列表传递给存储过程,使用DataTable作为添加使用SqlDbType.Structured

表值参数参考:

0

这就是我最终想出来的。当我正在看这个时,我可能早就喝咖啡了。它可能仍然可以使用一些工作,但它应该工作。

protected override int GetCount(List<int> itemlist) 
{ 
    sql.Execute(@"TRUNCATE Table table0"); 
    int count = 0; 

    string sql = @"WITH b AS 
        (
         {0} 
        ) 
        INSERT INTO table0 (ID, Guid) 
        SELECT ID, Guid 
        FROM b"; 

    List<string> sqlsubs = new List<string>(); 

    foreach (int itemgroup in itemlist) 
    { 
     sqlsub.Add(string.Format(@"SELECT table1.ID , table1.Guid 
            FROM dbo.tablefunction({0}) table1 LEFT JOIN 
              dbo.table0 ON table1.ID = table0.ID 
            WHERE table0.ID IS NULL", itemgroup)); 
    } 

    string sqlunion = string.Join(" UNION ", sqlsub); 

    return context.Execute(string.Format(sql, sqlunion)); 
}