SqlBulkCopy работает медленно, не использует полную скорость сети - PullRequest
1 голос
/ 16 декабря 2010

за последние пару недель я создавал общий сценарий, который может копировать базы данных.Цель состоит в том, чтобы иметь возможность указать любую базу данных на каком-либо сервере и скопировать ее в другое место, и она должна копировать только указанное содержимое.Точное содержимое для копирования указывается в файле конфигурации.Этот скрипт будет использоваться в 10 различных базах данных и запускаться еженедельно.И, наконец, мы копируем только около 3% -20% баз данных размером до 500 ГБ.Я использовал сборки SMO ​​для достижения этой цели.Я впервые работаю с SMO, и потребовалось время, чтобы создать общий способ копирования объектов схемы, файловых групп ... и т. Д.(На самом деле помог найти некоторые плохо хранимые проки).

В целом у меня есть рабочий скрипт, которому не хватает производительности (и время от времени), и я надеялся, что вы, ребята, сможете помочь.При выполнении команды WriteToServer для копирования большого объема данных (> 6 ГБ) мой тайм-аут достигает 1 часа.Вот основной код для копирования данных таблицы.Сценарий написан на PowerShell.

$query = ("SELECT * FROM $selectedTable " + $global:selectiveTables.Get_Item($selectedTable)).Trim()
Write-LogOutput "Copying $selectedTable : '$query'"            
$cmd = New-Object Data.SqlClient.SqlCommand -argumentList $query, $source
$cmd.CommandTimeout = 120;
$bulkData = ([Data.SqlClient.SqlBulkCopy]$destination)
$bulkData.DestinationTableName = $selectedTable;
$bulkData.BulkCopyTimeout = $global:tableCopyDataTimeout # = 3600
$reader = $cmd.ExecuteReader();
$bulkData.WriteToServer($reader); # Takes forever here on large tables

Исходная и целевая базы данных расположены на разных серверах, поэтому я также отслеживал скорость сети.Использование сети никогда не превышало 1%, что меня удивило.Но когда я просто передаю большие файлы между серверами, загрузка сети возрастает до 10%.Я попытался установить для параметра $ bulkData.BatchSize значение 5000, но ничего не изменилось.Увеличение BulkCopyTimeout до еще большего значения только решит время ожидания.Я действительно хотел бы знать, почему сеть не используется полностью.

У кого-нибудь еще была эта проблема?Будем благодарны за любые предложения по созданию сетей или массовых копий.И, пожалуйста, дайте мне знать, если вам нужна дополнительная информация.

Спасибо.

ОБНОВЛЕНИЕ

Я настроил несколько параметров, которые повышают производительность SqlBulkCopy,например, установление простого ведения журнала транзакций и обеспечение блокировки таблицы для SqlBulkCopy вместо блокировки строки по умолчанию.Также некоторые таблицы лучше оптимизированы для определенных размеров партий.В целом, продолжительность копирования была уменьшена примерно на 15%.И что мы будем делать, так это выполнять копии каждой базы данных одновременно на разных серверах.Но при копировании одной из баз данных у меня по-прежнему возникает тайм-аут.

При копировании одной из более крупных баз данных существует таблица, для которой я последовательно получаю следующее исключение:

System.Data.SqlClient.SqlException: Timeout expired.  The timeout period elapsed prior to completion of the operation or the server is not responding. 

Бросается через 16 минут после начала копирования таблицы, которой нет рядом с моим BulkCopyTimeout.Даже если я получаю исключение, таблица полностью копируется в конце.Кроме того, если я усекаю эту таблицу и перезапускаю процесс только для этой таблицы, таблицы копируются без каких-либо проблем.Но процесс копирования всей этой базы данных завершается неудачно всегда для этой таблицы.

Я пытался выполнить весь процесс и сбросить соединение перед копированием этой неисправной таблицы, но оно все равно было с ошибкой.Мой SqlBulkCopy и Reader закрываются после каждой таблицы.Любые предложения относительно того, что еще может вызывать сбой сценария в точке каждый раз?

CREATE TABLE [dbo].[badTable](
[someGUID] [uniqueidentifier] NOT NULL,
[xxx] [uniqueidentifier] NULL,
[xxx] [int] NULL,
[xxx] [tinyint] NOT NULL,
[xxx] [datetime] NOT NULL,
[xxx] [datetime] NOT NULL,
[xxx] [datetime] NOT NULL,
[xxx] [datetime] NULL,
[xxx] [uniqueidentifier] NOT NULL,
[xxx] [uniqueidentifier] NULL,
CONSTRAINT [PK_badTable] PRIMARY KEY NONCLUSTERED 
(
[someGUID] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

Нет индексов для этой таблицы в целевой БД.

Ответы [ 3 ]

0 голосов
/ 18 декабря 2010

Рассматривали ли вы удаление индексов, вставку, а затем переиндексацию?

0 голосов
/ 21 декабря 2010

SqlBulk Copy - безусловно, самый быстрый способ копирования данных в таблицы SQL.Вы должны получать скорость свыше 10000 строк в секунду.Чтобы проверить функциональность массового копирования, попробуйте DBSourceTools.(http://dbsourcetools.codeplex.com)Эта утилита предназначена для сценария баз данных на диск, а затем воссоздать их на целевом сервере.При копировании данных DBSourceTools сначала экспортирует все данные в локальный XML-файл, а затем выполняет групповое копирование в целевую базу данных.Это поможет дополнительно определить ваше узкое место, разбив процесс на два этапа: один для чтения и один для записи.

0 голосов
/ 16 декабря 2010

Я использовал набор данных и хотел бы знать, будет ли это быстрее:

$ds=New-Object system.Data.DataSet
$da=New-Object system.Data.SqlClient.SqlDataAdapter($cmd)
[void]$da.fill($ds)
bulkData.WriteToServer($ds.Tables[0])
...