2017-03-05 81 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)); 
}