SQL-Bulk-Einfügung mit Eltern / Kind-Beziehungen, wird die Reihenfolge beibehalten?

c# sqlbulkcopy sql-server-2008

Frage

Ähnlich wie diese anderen Fragen, die unten aufgeführt sind, habe ich zwei Tabellen mit der Struktur:

create table parent (
   recno int identity(1,1) primary key not null,
   groupCode int,
   parentdata varchar(80)
);

create table child (
   parentrecno int not null,
   childdata varchar(80)
)

Ich muss einige hunderttausend Datensätze schnell in diese Tabellen einfügen - und die Tabellen enthalten Millionen von anderen Datensätzen, die nichts mit dieser Einfügung zu tun haben und sind nie still. Wegen der Eltern / Kind-Natur ist es kein guter Kandidat (scheint es) für SqlBulkCopy .

In C # mit SqlCommand mit INSERT bekomme ich etwa 400-500 Datensätze / Sekunde eingefügt, und das ist ein bisschen zu langsam. Pseudocode:

 foreach(Record r in parentRecords)
 {
      Insert Fields from r into SqlCommand Parameters but not "recno"
      Call ExecuteScalar to insert and fetch the inserted identity value (recno)
      foreach(ChildRecord cr in parentRecords.Children)
      {
          Insert Fields from cr into SqlCommand Parameters
          Insert the identity value (recno) from above into Parameters 
                                                       (as parentrecno)
          Call ExecuteNonQuery to insert the record
      }   
 }

Nachdem ich diese anderen Beiträge gelesen hatte, fiel mir ein. Der groupCode , der an die übergeordneten Datensätze angehängt ist, ist einzigartig für die Menge der übergeordneten Datensätze, die ich einfüge. Würde es funktionieren:

  1. Bulk fügt die übergeordneten Datensätze mit SqlBulkCopy und lässt die Einfügung das recno Identitätsfeld wie üblich automatisch generieren.
  2. Führen Sie SELECT nur für die eingefügten Datensätze aus:

    select recno from parent where groupCode = @thisgroup order by recno;
    
  3. Verwenden Sie die abgerufenen Werte, um die parentrecno Felder für die parentrecno Datensätze im Speicher auszufüllen

  4. Bulk fügt die SqlBulkCopy Datensätze mit SqlBulkCopy

Dies würde darauf beruhen, dass die übergeordneten Datensätze in der gleichen Reihenfolge in die SQL-Tabelle gelangen wie in der ursprünglichen DataTable (und die Identitätswerte in derselben Reihenfolge zugewiesen werden). Ist das etwas, auf das ich mich verlassen kann?

Verwandte Fragen:

Wie aktualisiert man Eltern- und Kindtabellen von Datasets mit automatisch generiertem Identitätsschlüssel?

SqlBulkCopy und DataTables mit Parent / Child-Beziehung für Identitätsspalte

Akzeptierte Antwort

Erstellen Sie zwei Zwischenspeichertabellen mit derselben Struktur wie Ihre Zieltabellen, verwenden Sie jedoch keine Identität in der Spalte 'recno'.

create table parentTmp (
   recno int,
   groupCode int,
   parentdata varchar(80)
);

create table childTmp (
   parentrecno int not null,
   childdata varchar(80)
)

Bulk Laden Sie Ihre Daten in die Staging-Tabellen, wobei Sie die Werte für recno / parentrecno unverändert lassen.

Anschließend können Sie die Daten aus den Staging-Tabellen mithilfe von Zusammenführung und Ausgabe verschieben.

-- Table variable to hold mapping between 
-- SourceRecno and TargetRecno
declare @recno table(SourceRecno int, TargetRecno int);

-- Merge data from parentTmp to parent
-- Output old and new recno to @recno
merge parent T
using parentTmp S
on 0=1
when not matched then
  insert (groupCode, parentdata)
    values (S.groupCode, S.parentData)
output S.recno, inserted.recno into @recno;

-- Copy data from childTmp to child
-- Use @recno to get the new recno
insert into child(parentrecno, childdata)
select R.TargetRecno, C.childdata
from childTmp as C
  inner join @recno as R
    on C.parentrecno = R.SourceRecno;

Dies funktioniert nur in SQL Server 2008 (und später nehme ich an).


Beliebte Antwort

Dies ist keine absolute Masseneinfügung, sondern stattdessen werden alle untergeordneten Daten gleichzeitig mit den übergeordneten Daten eingefügt, wodurch nur ein Umlauf in die DB erfolgt.

insert into parent(groupcode, parentdata) values(1, 'parent data');
insert into child(parentrecno, childdata) select parentrecno, childdata from (
    select SCOPE_IDENTITY() as parentrecno, 'child data 1' as childdata
    union
    select SCOPE_IDENTITY() as parentrecno, 'child data 2' as childdata
    union
    select SCOPE_IDENTITY() as parentrecno, 'child data 3' as childdata
) childrendata;

Sie können Skripte wie diese in Ihrem C # -Code erstellen und dann eine Anfrage pro Elternteil ausführen.

Beachten Sie, dass dies möglicherweise kein guter Ansatz ist, wenn bekannt ist, dass die Anzahl der Kinddaten groß ist. Ich kenne die Details nicht, aber ich bin mir sicher, dass die Größe des SQL-Skripts nicht unbegrenzt wachsen kann.



Lizenziert unter: CC-BY-SA with attribution
Nicht verbunden mit Stack Overflow
Ist diese KB legal? Ja, lerne warum
Lizenziert unter: CC-BY-SA with attribution
Nicht verbunden mit Stack Overflow
Ist diese KB legal? Ja, lerne warum