Массовая вставка SQL с отношениями родитель / потомок, порядок сохранен? - PullRequest
4 голосов
/ 22 июня 2011

По аналогии с этими другими вопросами, отмеченными ниже, у меня есть две таблицы со структурой:

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

Мне нужно быстро вставить несколько сотен тысяч записей в эти таблицы - и в таблицах содержатся миллионы других записей, не связанных с этой вставкой, и они никогда не будут тихими. Из-за характера родителя / ребенка, это не хороший кандидат (кажется) для SqlBulkCopy.

В C # с использованием SqlCommand с INSERT Я получаю около 400-500 записей в секунду, и это слишком медленно. Псевдокод:

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

После прочтения этих постов мне пришла в голову мысль. groupCode, прикрепленный к родительским записям, уникален для того набора родительских записей, которые я вставляю. Будет ли это работать для:

  1. Массовая вставка родительских записей с помощью SqlBulkCopy, позволяющая вставке автоматически генерировать поле идентификации recno как обычно.
  2. Выполните SELECT только для вставленных записей:

    select recno from parent where groupCode = @thisgroup order by recno;
    
  3. Используйте полученные значения для заполнения полей parentrecno для дочерних записей в памяти

  4. Массовая вставка дочерних записей с SqlBulkCopy

Это будет зависеть от того, будут ли родительские записи поступать в таблицу SQL в том же порядке, в котором они находятся в исходной таблице данных (и значения идентификаторов назначаются в том же порядке). Могу ли я на это положиться?

Похожие вопросы:

Как обновить родительские и дочерние таблицы набора данных с помощью автоматически сгенерированного идентификационного ключа?

SqlBulkCopy и DataTables с отношением родитель / потомок в столбце идентификаторов

Ответы [ 2 ]

6 голосов
/ 21 июля 2011

Создайте две промежуточные таблицы с той же структурой, что и ваши целевые таблицы, но не используйте идентификатор в столбце recno.

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

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

Массовая загрузка данных в промежуточные таблицы, сохраняя значения recno / parentrecno какis.

Затем вы можете использовать merge и output для перемещения данных из промежуточных таблиц.

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

Это будет работать только вSQL Server 2008 (и позже я предполагаю).

1 голос
/ 21 июля 2011

Это не абсолютная массовая вставка, но вместо этого она вставляет все дочерние данные одновременно с родительскими данными, совершая только одну обратную передачу в БД.

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;

Вы можете создавать подобные сценарии в своем коде C #, а затем выполнять один запрос для каждого родителя.

Помните, что это может быть не очень хорошим подходом, если известно, что объем дочерних данных велик. Не знаю деталей, но я уверен, что размер сценария sql не может расти бесконечно.

...