За получение списка БД на сервере отвечает функция GetDbList. Она принимает в качестве опционального параметра имя экземпляра SQL-сервера. Если имя не указано, подключение идет к экземпляру по умолчанию. Для каждой базы данных получаем ее имя, состояние и принадлежность к системным базам.

Однако во время отладки выявилась одна неприятная особенность — получение списка таким способом занимало более двух с половиной минут для 120 баз данных. При этом аналогичный SQL-запрос отрабатывал задачу практически мгновенно. Отладка в профайлере SQL показала, что при выполнении кода, показанного ниже, SMO генерируют множество запросов к каждой БД вместо одного простого, что и приводит к потере производительности.

$SqlServer = New-Object ("Microsoft. SqlServer. Management.

SMO. Server") $Instance $DbList = $SqlServer. Databases | Select-Object Name, Status, IsSystemObject

Оказалось, что это проблема известная и существует способ ее решения [10]. Нужно заранее указать SMO, к каким полям БД мы будем обращаться, что позволит им генерировать оптимальные SQL-запросы. Сделать это можно с помощью метода SetDefaultlnitFields.

SMO всегда запрашивают имя и схему базы данных, поэтому нам требуется указать только два поля, которые нужно дополнительно получить при запросе к SQL: состояние БД Status и ее принадлежность к системным объектам IsSystemObject. Однако метод SetDefaultlnitFields принимает список параметров только в том случае, если это коллекция строк (StringCollection из. Net), а строки в PowerShell таковыми не являются. Поэтому необходимо создать объект с коллекцией строк, добавить в него наши поля, передать методу и уже после этого пытаться получить список баз.

[array]$Preload ="Status", "IsSystemObject"

$StrCol = New-Object System. Collections. Specialized.

StringCollection

$StrCol. AddRange ($Preload)

$SqlServer. SetDefaultlnitFields ([Microsoft. SqlServer.

Management. SMO. Database], $StrCol)

После такой оптимизации получение списка баз данных стало занимать порядка 13 секунд.

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

$SqlServer= Get-Item SqlServer:SQLServerNameDefault

[array]$Preload ="Status", "IsSystemObject"

$StrCol = New-Object System. Collections. Specialized.

StringCollection

$StrCol. AddRange ($Preload)

$SqlServer. SetDefaultlnitFields ([Microsoft. SqlServer.

Management. SMO. Database], $StrCol)

$SqlServer. Databases | Select Name, Status, IsSystemObject

Запускутилиты SQL Server Compressed Backup

Привычный способ запуска внешних утилит с использованием символа амперсанда «&», который указывает Powershell не обрабатывать идущие за ним символы как имя командлета или строку, а выполнить ее как внешнюю команду, не работает в случае с SQL Server Compressed Backup. Дело в том, что утилита активно применяет кавычки внутри параметров, а при использовании «&» PowerShell передает все аргументы как одну строку, оборачивая их в кавычки. В большинстве случаев это работает, однако в данном варианте парсер командной строки в программе не справляется с подобной конструкцией. Поэтому следует воспользоваться командлетом Start-Process, который является надстройкой над. NET методом Process. Start. Он позволяет запускать процессы напрямую, минуя обработчик PowerShell.

$BackupJob = Start-Process — FilePath $script: BackupExe

-ArgumentList $LaunchString — NoNewWindow — Wait — PassThru

При этом сохраняется возможность получать код возврата утилиты для проверки успешности резервного копирования.

if ($BackupJob. ExitCode) {

Write-Log "Произошла ошибка при бэкапе $DbName"

} else

{

Write-Log "Бэкап базы $DbName занял $BackupTime

}

Предыдущая статьяОбзор возможностей SQL Server Compressed Backup
Следующая статьяПровайдер WMI