2017-03-05 1 views
1

Ich bin auf ein Problem mit einer Anwendung, die mich zu einer Methode führt das folgende führt.Optimieren Sie die SQL-Funktion in C# -Code

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; 
} 

Ich renne in eine Schlüsseleinschränkung Problem während der Einfügeschleife, die nicht völlig unerwartet ist.

Aber ich merke auch, dass es mehrere Inserts unterschiedlicher Größe potenziell tun, so dass ich nach Ideen/Vorschläge für die dynamische Assembly eine Union-Abfrage und dann alle Ergebnisse auf einmal einfügen. Zum Beispiel könnte die resultierende Abfrage

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 

Ich bin nur nicht sicher, wie es am besten geht.

+0

Es hängt nicht wirklich mit Ihrer dynamisch großen Einfügung zusammen, aber kann dieser Code von mehr als einem Ort gleichzeitig aufgerufen werden? Wenn ja, was passiert, wenn die Tabelle nach dem Einfügen der Werte TRUNCATEd von einer anderen Instanz erhält, so dass Sie nicht mehr die Werte haben, die Sie haben sollten, sondern stattdessen eine leere Tabelle? – seventyeightist

+0

Es gibt eine Sperre, die verhindert, dass dies gleichzeitig ausgeführt wird. aber die Tabelle, die es einfügt, wird von der nächsten Reihe von Methoden in der Sequenz verwendet und dann abgespült und wiederholt, daher die Kürzung. Es gibt wahrscheinlich bessere Möglichkeiten, um das Ganze zu machen, aber ich hoffe, diese Änderung isoliert auf diese Methode zu halten, um größere Regressionen zu vermeiden. –

+0

Also, was ist das Problem genau beim Komponieren dieser Gewerkschaftserklärung? Scheint wie eine Reihe von String-Verkettungen. – Evk

Antwort

0

Verwendung string.format() -Methode:

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

Die sql.Execute-Methode macht das bereits an anderer Stelle im Code. Das Problem, das ich angehen möchte, ist, dass diese Foreach-Schleife die gleiche kleine Abfrage wiederholt und eine größere Anzahl von verschiedenen Einfügungen ausführt, die ich zu einem effizienteren Insert kombinieren möchte. –

+0

String sql = leere Zeichenfolge und dann verketten es in jeder Iteration der Schleife (wie Sie im Grunde getan haben?) Aber die sql.execute müsste außerhalb der Schleife sein, mit der generierten Zeichenfolge - sobald Sie alle erforderlichen Anweisungen verkettet haben - nur einmal ausgeführt, so nur eine Hin- und Rückfahrt. – seventyeightist

+0

Warum machst du es mehr als einmal? Im Code geschrieben und woanders? – jdweng

0

Sie könnten Table-Valued Parameters - msdn und eine gespeicherte Prozedur verwenden, um dies zu tun.

Zunächst müssten Sie einen Tabellentyp zu schaffen, mit dem Verfahren zu verwenden:

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

Erstellen Sie dann das Verfahren:

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 

Wenn Sie laufen violoations dann deutlich, auf Zwang Gruppieren nach, oder andere Bedingungen können erforderlich sein

Dann assemblieren und übergeben Sie die Liste der Artikelgruppen an die gespeicherte Prozedur mit einer DataTable alshinzugefügtmit SqlDbType.Structured.

Tabellenwert Parameter Referenz:

0

Dies ist, was ich am Ende kam. Ich war vielleicht schon früher Kaffee, als ich mir das anschaute. Es könnte wahrscheinlich noch ein wenig Arbeit gebrauchen, aber es sollte funktionieren.

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)); 
}