SQL Server вставляет производительность

У меня есть запрос на вставку, который сгенерирован как это

INSERT INTO InvoiceDetail (LegacyId,InvoiceId,DetailTypeId,Fee,FeeTax,Investigatorid,SalespersonId,CreateDate,CreatedById,IsChargeBack,Expense,RepoAgentId,PayeeName,ExpensePaymentId,AdjustDetailId) 
VALUES(1,1,2,1500.0000,0.0000,163,1002,'11/30/2001 12:00:00 AM',1116,0,550.0000,850,NULL,@ExpensePay1,NULL); 
DECLARE @InvDetail1 INT; SET @InvDetail1 = (SELECT @@IDENTITY);

Этот запрос сгенерирован для только 110K строки.

Требуется 30 минут для всех них запрос для выполнения

Я проверил план запросов, и самые большие узлы %

Кластерный индекс Вставляет по 57%-й стоимости запроса, которая имеет длинный xml, который я не хочу отправлять.

Шпулька Таблицы, которая является 38%-й стоимостью запроса

<RelOp AvgRowSize="35" EstimateCPU="5.01038E-05" EstimateIO="0" EstimateRebinds="0" EstimateRewinds="0" EstimateRows="1" LogicalOp="Eager Spool" NodeId="80" Parallel="false" PhysicalOp="Table Spool" EstimatedTotalSubtreeCost="0.0466109">
  <OutputList>
    <ColumnReference Database="[SkipPro]" Schema="[dbo]" Table="[InvoiceDetail]" Column="InvoiceId" />
    <ColumnReference Database="[SkipPro]" Schema="[dbo]" Table="[InvoiceDetail]" Column="InvestigatorId" />
    <ColumnReference Column="Expr1054" />
    <ColumnReference Column="Expr1055" />
  </OutputList>
  <Spool PrimaryNodeId="3" />
</RelOp>

Таким образом, мой вопрос - то, что там, что я могу сделать для улучшения скорости этой вещи? Я уже выполняю ИМЯ ТАБЛИЦЫ ALTER TABLE ОГРАНИЧЕНИЯ NOCHECK ВСЕ Перед запросами и затем ИМЕНЕМ ТАБЛИЦЫ ALTER TABLE ОГРАНИЧЕНИЯ NOCHECK ВСЕ после запросов.

И это едва ничего не сбрило прочь времени.

Знайте, что я выполняю эти запросы в приложении.NET, которое использует объект SqlCommand отправить запрос.

Я затем пытался произвести команды sql в файл и затем выполнить его с помощью sqlcmd, но я не надевал обновлений, как он делал, таким образом, я разочаровался в этом.

Какие-либо идеи или подсказки или справка?

ОБНОВЛЕНИЕ:

Хорошо, таким образом, все Вы были очень услужливы. В этой ситуации мне жаль, что я не мог дать кредит больше чем одному ответу.

Решение зафиксировать это было двукратным.

Первое:

1) Я отключил/повторно включил все внешние ключи (намного легче, чем отбрасывание их)

ALTER TABLE TableName NOCHECK CONSTRAINT ALL
ALTER TABLE TableName CHECK CONSTRAINT ALL

2) Я Отключил/Повторно включил индексы (снова намного легче, чем отбрасывание)

ALTER INDEX [IX_InvoiceDetail_1] ON [dbo].[InvoiceDetail] DISABLE
ALTER INDEX [IX_InvoiceDetail_1] ON [dbo].[InvoiceDetail] REBUILD PARTITION = ALL WITH ( PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON, ONLINE = OFF, SORT_IN_TEMPDB = OFF )

Второе:

Я перенес все операторы вставки в одну транзакцию. Я первоначально не знал, как сделать это в.NET.

Я действительно ценю весь вход, который я получил.

Если я когда-нибудь сделаю этот вид перевода от DB до DB, то я определенно запущу с BULK INSERT. Это кажется намного более гибким и быстрее.

19
задан Eric J. 27 April 2012 в 17:42
поделиться

7 ответов

Похоже, что вставки заставляют SQL Server пересчитывать индексы. Одним возможным решением было бы отбросить индекс, выполнить вставку и повторно добавить индекс. В случае попытки решения, даже если вы укажете ему игнорировать ограничения, ему все равно потребуется обновлять индекс.

14
ответ дан 30 November 2019 в 02:36
поделиться

Есть несколько вещей, которые вы можете сделать:

1) Disable any triggers on this table
2) Drop all indexes
3) Drop all foreign keys
4) Disable any check constraints
4
ответ дан 30 November 2019 в 02:36
поделиться

Выполнение отдельных операций INSERT всегда будет самым медленным вариантом. Кроме того, в чем дело с @@ IDENTITY - не похоже, что вам нужно отслеживать тех, кто находится между ними.

Если вы не хотите использовать BULK INSERT из файла или SSIS, в ADO.NET есть функция SqlBulkCopy, которая, вероятно, будет вашим лучшим выбором, если вам абсолютно необходимо сделать это изнутри Программа .NET.

Для импорта 110 тыс. Строк должно потребоваться меньше времени, чем при повторном чтении и написании этого ответа.

4
ответ дан 30 November 2019 в 02:36
поделиться

Хм, дайте поработать, проверьте счетчики производительности. что ты видишь? Какая у вас раскладка диска? Я могу вставить несколько миллионов строк за 30 минут - точнее, почти сто миллионов строк (финансовая информация в реальном времени, ссылки на 3 другие таблицы). Я уверен, что у вас плохая схема ввода-вывода (т.е. плохая структура диска, плохое распределение файлов)

1
ответ дан 30 November 2019 в 02:36
поделиться

Выполняете ли вы эти запросы по одному от клиента .Net (т. Е. Отправляете 110000 отдельных запросов на SQL Server)?

В этом случае, вероятно, это задержка в сети и другие накладные расходы на отправку этих INSERT к SQL Server без их пакетной обработки, а не к самому SQL Server.

Обратите внимание на BULK INSERT.

10
ответ дан 30 November 2019 в 02:36
поделиться

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

Например, попытка вставить 100 тыс. Строк, подобных вашей, в стиле фиксации одной строки:

set nocount on; 
declare @start datetime = getutcdate();  

declare @i int = 0;
while @i < 100000
begin
INSERT INTO InvoiceDetail (
  LegacyId,InvoiceId,DetailTypeId,Fee,
  FeeTax,Investigatorid,SalespersonId,
  CreateDate,CreatedById,IsChargeBack,
  Expense,RepoAgentId,PayeeName,ExpensePaymentId,
  AdjustDetailId) 
  VALUES(1,1,2,1500.0000,0.0000,163,1002,
    '11/30/2001 12:00:00 AM',
    1116,0,550.0000,850,NULL,1,NULL); 
  set @i = @i+1;
end

select datediff(ms, @start, getutcdate());

На моем сервере это выполняется примерно за 12 секунд. Но при добавлении управления транзакциями и фиксации каждых 1000 строк вставка 100 тыс. Строк длится всего около 4 с:

set nocount on;  
declare @start datetime = getutcdate();  

declare @i int = 0;
begin transaction
while @i < 100000
begin
INSERT INTO InvoiceDetail (
  LegacyId,InvoiceId,DetailTypeId,
  Fee,FeeTax,Investigatorid,
  SalespersonId,CreateDate,CreatedById,
  IsChargeBack,Expense,RepoAgentId,
  PayeeName,ExpensePaymentId,AdjustDetailId) 
  VALUES(1,1,2,1500.0000,0.0000,163,1002,
    '11/30/2001 12:00:00 AM',
    1116,0,550.0000,850,NULL,1,NULL); 
  set @i = @i+1;
  if (@i%1000 = 0)
  begin
    commit
    begin transaction
  end  
end
commit;
select datediff(ms, @start, getutcdate());

Также с учетом того, что я могу вставить 100 тыс. Строк за 12 секунд даже без пакетной фиксации, в то время как вам нужно 30 минут, это стоит изучить 1) скорость вашей подсистемы ввода-вывода (например, сколько Avg. Sec per Transaction вы видите на дисках) и 2) что еще делает код клиента между получением идентификатора @@ из одного вызова и вызовом следующая вставка. Возможно, большая часть времени находится на стороне клиента стека. Одним из простых решений может быть параллельный запуск нескольких вставок (BeginExecuteNonQuery), чтобы вы постоянно подавали вставки SQL Server.

9
ответ дан 30 November 2019 в 02:36
поделиться

Вы отметили этот вопрос как «bulkinsert». Так почему бы не использовать команду BULK INSERT ?

Если вам нужны обновления прогресса, вы можете разделить массовую вставку на более мелкие части и обновлять прогресс после завершения каждой части.

6
ответ дан 30 November 2019 в 02:36
поделиться
Другие вопросы по тегам:

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