MSMQ 3.0 в Кластере

Здесь будет идти речь о кластере Windows Server 2003 Enterprise Edition и о запуске в кластере службы MSMQ. MSMQ, как кластерный ресурс, зависит от двух кластерных ресурсов: сетевого имени и физического диска. Зависимость от сетевого имени позволяет идентифицировать кластерную группу по IP адресу, и позволяет клиентам обращаться к группе как к виртуальному серверу. Физический диск нужен для хранилища сообщений и очередей.

Без кластера, клиенты из сети должны подключаться к серверу по имени или IP адресу, подключаясь к приложению или службе. Служба кластера позволяет создать виртуальные сервера. В дополнение к клиентам MSMQ, работающим со стандартным, не кластерным сервером MSMQ, который обслуживается на узле кластера, написанное для работы в составе кластера приложение MSMQ может связаться с сервером MSMQ, который работает в контексте виртуального сервера. Виртуальный сервер MSMQ, это кластерная группа, состоящая из кластерного ресурса MSMQ и его зависимых ресурсов, о которых уже упоминалось выше. Виртуальный сервер MSMQ не привязан с определенному компьютеру, и в случае отказа он будет перемещён на другой узел, который станет обслуживать клиентов. Очереди создаются на виртуальном сервере, и сообщения можно посылать в очереди виртуального сервера, используя обычный синтаксис VirtualServerName\QueueName.

При создании и настройке MSMQ в кластере, нужно установить MSMQ 3.0 на каждом узле. Кластер должен быть создан до установки MSMQ 3.0 на любом из узлов кластера. MSMQ должен быть установлен до создания кластерного ресурса MSMQ, и набор компонент на каждом узле должен быть одним и тем же.

После установки MSMQ 3.0 на всех узлах кластера можно приступать к созданию кластерного ресурса MSMQ. Можно создавать несколько ресурсов MSMQ, но работа таких ресурсов выходит за рамки поддержки Майкрософт. Поэтому, желательно создавать только один ресурс MSMQ и потом его не переименовывать. После выбора ресурса физического диска в группу MSMQ (он должен быть доступен всем узлам кластера), на этом диске будет создано хранилище очередей, которое желательно создать в папке \msmq\storage. После создания хранилища, местоположение папки хранилища изменять не следует.

В кластерной конфигурации запуск службы MSMQ установлен ручным, т.е. после перезапуска компьютера служба MSMQ не запустится автоматически. Однако ресурсы MSMQ станут активными автоматически.

Если в процессе установки ресурса MSMQ возникнут проблемы, обратитесь к файлу журнала кластера, который обычно расположен по этой ссылке: %systemroot%\Cluster\cluster.log.

Для создания и настройки кластерного ресурса и группы MSMQ в качестве виртуального сервера выполните следующие действия:

  1. Нажмите Пуск (Start), выберете пункт Программы (All Programs), пункт Администрирование (Administrative Tools), и затем запустите программу Cluster Administrator.
  2. В пункте Open Connection to Cluster нужно выбрать соответствующее имя кластера.
  3. В дереве кластерных групп нужно выбрать ту кластерную группу, которой должен принадлежать ресурс MSMQ.
  4. После выбора группы, в пункте меню File нужно выбрать New, а затем щелкнуть Resource.
  5. В мастере New Resource Wizard заполните поля Name и Description, и выберете Message Queuing в списке Resource type. Потом нажмите Next.
  6. В поле Group укажите ту группу, которой Вы хотите, чтобы принадлежал ресурс MSMQ.
  7. На закладке возможных владельцев, добавьте те узлы, которые смогут обслуживать ресурс MSMQ.
  8. На странице зависимостей (Dependencies в Available resources) добавьте ресурс сетевого имени и физического диска.
  9. Нажмите Finish.
  10. В дереве кластерных групп нужно выбрать Resources, а затем в окне подробностей выделить ресурс MSMQ.
  11. В меню File, выберите Bring Online.
  12. В дереве кластерных групп нужно выбрать ту кластерную группу, которой должен принадлежит ресурс MSMQ. Нажать New, а затем щелкнуть Resource, чтобы запустился мастера создания нового ресурса.
  13. В текстовом поле Resource Name введите название: "Computer Management".
  14. В списке Resource Type, выберите Generic Application, и затем нажмите Next.
  15. В поле Group укажите ту группу, которой принадлежит ресурс MSMQ.
  16. На закладке Possible Owners, выберите возможных владельцев и нажмите Next.
  17. На странице зависимостей добавьте ресурс сетевого имени и ресурс MSMQ, который Вы перед этим создавали. Нажмите Next.
  18. В командной строке введите: mmc compmgmt.msc
  19. В Current Directory введите: %windir%\system32
  20. Нужно выбрать Use Network Name для имени компьютера, и Allow application to interact with desktop. Нажмите Next, а затем Finish.
  21. В дереве кластерных групп нужно выбрать Resources, а затем в окне подробностей выделить ресурс Computer Management, который Вы только что создали.
  22. В меню File, выберите Bring Online.

Для управление виртуальным сервером, Вы должны подключиться к нулевой сессии, т.е. Console Session (Для подключения через RDP к Session 0 нужно запустить следующую команду: %systemroot%\system32\mstsc.exe /Admin). Также для управления очередями MSMQ в кластерной среде можно использовать утилиту MMCV.exe. Для получения более подробной информации об этой утилите ознакомьтесь со статьёй How to use the Mmcv.exe utility to manage clustered Message Queuing resources. Однако, мне чаще всего хватало тривиальной оснастки mmc, правда для подключения именно к виртуальной очереди MSMQ следует явно подключиться в Computer Management к виртуальному имени, от которого зависит кластерный ресурс MSMQ. После настройки MSMQ для работе в качестве виртуальной службы кластера, не забывайте дать необходимые права на саму виртуальную службу тем учётным записям пользователей, которые будут создавать очереди, а также раздать права к тем очередям, которые будут вами созданы.

Если установка и настройка MSMQ в кластере выполнена правильно, на каждом из узлов кластера должна появиться вторая, дополнительная служба MSMQ. Службы MSMQ локальные для каждого узла не обязательно должны быть запущены. Если Вы не планируете их использование в своих приложениях, можно отменить их автоматический запуск. Для виртуальной службы MSMQ достаточно того, что необходимые компоненты были установлены на каждом из узлов кластера.

Если необходимо, чтобы в случае административного или из-за отказа перемещения ресурсов MSMQ на другой узел, содержимое очереди не очищалось, создавайте очередь транзакционной и обрамляйте отправку сообщений транзакциями (в терминах Windows, а не MSSQL).

Полезные ссылки:

Posted by gladchenko | 1 comment(s)
Filed under:

SQL Server: Методика тестирования дисковой подсистемы

(на примере полки с 14 одинаковыми дисками)

Введение

В качестве утилиты для эталонного тестирования дисковой подсистемы используется разработанная Майкрософт программа SQLIO, подробное описание которой представлено в статье Эталонный тест дисковой подсистемы SQLIO.

В методике используется ограниченный набор параметров вызова SQLIO. Давайте рассмотрим назначение параметров на примере:

sqlio -kR -s300 -b64 -f1 -i2000000 -o1 -t1 -R1 -LP -a0xf –BN

Параметр -k определяет, будет ли производиться чтение (R) или запись (W). Параметр -s задаёт продолжительность теста, указываемую в секундах. Параметр -b задаёт размер блока ввода-вывода в килобайтах.  Параметр -f определяет число блоков в строке. Параметр –i определяет число строк. С помощью параметров -b, -f и -i

Рис.1.

Параметр -o указывает количество отправляемых в одном потоке запросов ввода-вывода, т.е. глубину очереди. Практика показывает, что программа SQLIO при глубине очереди 64 и выше может вести себя нестабильно, поэтому число 64 не превышалось. Параметр -t задаёт число используемых в тесте потоков, максимальное значение 256. В настоящей методике этот параметр не превышает числа ядер процессоров. Параметр -R задаёт номера LUN сырых (RAW) разделов дисков. Параметр –L задаёт таймер теста, в методике используется таймер процессоров. Параметр -a задаёт маску используемых в тесте процессоров. Параметр –B используется для отключения аппаратного и программного кэширования (кэш дисков и дисковых контроллеров будет отключён, если ими такая возможность поддерживается).

В отчёте по каждому из единичных тестов, выполненных утилитой SQLIO, кроме численных параметров рабочей нагрузки данного теста указаны и вычисленные показатели производительности. Кроме метрик задержки, можно увидеть две величины: IOs/sec и MBs/sec. Первая является ни чем иным, как IOPS (Input-Output Operations Per Second), и показывает количество операций ввода-вывода в секунду, которые было обработано тестируемой дисковой подсистемой. Эта величина лучше всего характеризует производительность обслуживания коротких запросов, характерных для OLTP-нагрузки (8KB). Если приложение, для которого тестируется дисковая подсистема, использует в своей работе преимущественно такую нагрузку, может оказаться, что сравнения полученных в разных конфигурациях результатов стоит делать по этой метрике. Один диск на сегодняшний день может обслуживать от 50 IOs/sec для SATA и до 200 IOs/sec для FC дисков.

Второй метрикой является производительность передачи данных, так называемый Traffic Throughput. Это основная метрика настоящей методики, поскольку большинству приложений баз данных характерны укрупнённые запросы (например, упреждающее чтение способно использовать запросы ввода-вывода в 64 и 128 КБ).

Этап №0. Подготовка

Инсталляцию дисковой подсистемы нужно выполнять таким образом, чтобы было обеспечено сбалансированное и равномерное распределение дисков между контроллерами и по физическим шинам. Важно, чтобы на обслуживающей дисковый контроллер шине не было других, более медленных устройств, иначе, это может привести к снижению скорости обмена по шине для выравнивания с более медленным устройством. Дисковые контроллеры должны регистрироваться системой после встроенных контроллеров, которые обслуживают диск или диски операционной системы (иметь большие номера). В наших тестах, которые описаны в настоящей статье, это контроллер с номером 0, который обслуживает диск, пронумерованный операционной системой, как нулевой. После любых изменений конфигурации дисковой подсистемы нужно выполнять сохранение конфигурации в фал, который потом попадёт в отчёты. Важен, также, учет особенностей нумерации дисков в ОС.

Во время конфигурации виртуальных дисков/массивов, нужно отключать всякого рода кэширование (сквозная запись, отсутствие упреждающего чтения) и включать оптимизацию для баз данных, если таковая предусмотрена. Все созданные виртуальные диски должны быть зарегистрированы в mmc оснастке управления дисками.

Этап №1. Калибровка дисков

Задача: На этом этапе мы должны убедиться, что используемые диски работоспособны, определить разброс скоростей чтения и записи по дискам, чтобы потом учитывать возможности каждого диска при распределении дисков в массивах.

Возникает резонный вопрос, почему бы не воспользоваться стандартными в таких случаях стресс - тестами, которые, как правило, предоставляются вендором. Объяснение простое. Чаще всего мне доводилось работать с серверами удалённо, а в таких условиях не всегда удаётся добиться оперативной реакции обслуживающего аппаратную часть персонала. В таких случаях проще сделать быстрый тест на "вшивость". К тому же, не всегда тесты охватывают сразу все уровни системы, они могут ограничится только дисками или тестировать контроллер вместе с дисками. Существуют также специализированные тесты, которые позволяют тестировать систему в целом и определять её пригодность к использованию для того - либо иного приложения. У Майкрософт, к слову, есть подобный стресс - тест, который позволяет протестировать дисковую систему и сервер. Называется эта утилита: SQLIOSim.

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

  1. С помощью поставляемых с дисковым контроллером специализированных утилит, конфигурируем все диски полки как 14 массивов RAID0, каждый из которых должен состоять из одного диска, размер каждого массива выбирается равным всему доступному размеру диска, размер блока низкоуровневой разметки (размер сегмента) выбираем равным 64Кб, политики кэширования должны исключать кэширование чтения и записи. В некоторых контроллерах дисковых массивов выбор размера сегмента может быть ограничен несколькими предопределёнными значениями. Можно встретить рекомендованные для типовых конфигураций значения, например, для баз данных предлагают установить размер блока в 128Кб, а для хранения видеофильмов задать 256Кб. В этих случаях резонно выбрать рекомендованные вендором значения.
  2. С помощью оснастки управления дисками, входящей в состав mmc-консоли управления компьютером, и системной утилиты DISKPART необходимо создать для каждого физического диска полки RAW-раздел (без форматирования NTFS) величиной на весь диск, и без присвоения буквы диска (буквы присваивать можно, но это не обязательно, к тому же, букв в алфавите может оказаться меньше числа дисков). Большие диски (более двух Терабайт) может потребоваться предварительно перевести в состояние Online, и конвертировать в GPT (GUID Partition Table). Для выравнивания начального смещения за счёт MBR используйте следующие команды DISKPART:

SELECT DISK=1
CREATE PARTITION PRIMARY ALIGN=128

В этом примере выбран диск 1 и смещение установлено в 128Кб. Выбор смещения зависит от размера сегмента.

  1. Установить программу SQLIO. Везде по тексту настоящей статьи местоположение программы sqlio.exe выбрано следующее: C:\SQLIO\ sqlio.exe
  2. Подготовьте командный файл, который будет запускать программу sqlio.exe в разных режимах для каждого диска и сохранять результаты в файлы. Пример командного файла можно найти в Приложении 1.
  3. Запустите командный файл на исполнении, а потом сведите собранные в файлы результаты в общую таблицу, для дальнейшего сравнения и анализа.

Пример аппаратной конфигурации дисков представлен в Таблице 1.

Таблица 1. Конфигурация дисковых массивов для калибровки дисков.

Номер диска

Тип массива

Размер

Имя устройства

Политика чтения

Политика записи

Политика кэша

Размер блока полосы

1:0

RAID-0

136.62GB

Windows Disk 0

без упреждения

прямая запись

Direct I/O

64 KB

1:1

RAID-0

136.62GB

Windows Disk 1

без упреждения

прямая запись

Direct I/O

64 KB

1:5

RAID-0

136.62GB

Windows Disk 2

без упреждения

прямая запись

Direct I/O

64 KB

0:9

RAID-0

136.62GB

Windows Disk 3

без упреждения

прямая запись

Direct I/O

64 KB

0:10

RAID-0

136.62GB

Windows Disk 4

без упреждения

прямая запись

Direct I/O

64 KB

0:11

RAID-0

136.62GB

Windows Disk 5

без упреждения

прямая запись

Direct I/O

64 KB

0:12

RAID-0

136.62GB

Windows Disk 6

без упреждения

прямая запись

Direct I/O

64 KB

0:13

RAID-0

136.62GB

Windows Disk 7

без упреждения

прямая запись

Direct I/O

64 KB

0:14

RAID-0

136.62GB

Windows Disk 8

без упреждения

прямая запись

Direct I/O

64 KB

0:15

RAID-0

136.62GB

Windows Disk 9

без упреждения

прямая запись

Direct I/O

64 KB

1:2

RAID-0

136.62GB

Windows Disk 10

без упреждения

прямая запись

Direct I/O

64 KB

1:3

RAID-0

136.62GB

Windows Disk 11

без упреждения

прямая запись

Direct I/O

64 KB

1:4

RAID-0

136.62GB

Windows Disk 12

без упреждения

прямая запись

Direct I/O

64 KB

1:8

RAID-0

136.62GB

Windows Disk 13

без упреждения

прямая запись

Direct I/O

64 KB

 

На Рисунке 2 показано, как должны выглядеть 14 дисков, подготовленные к тестированию.

Рис.2.

Ниже представлен сокращённый пример командного файла для запуска калибровочного теста. В этом файле каждый вызов программы sqlio.exe имеет одинаковые аргументы, кроме аргумента R, который изменяется от 1 до 14. Каждый диск тестируется на чтение и, после 30 секундной паузы, на запись (аргумент k). Время тестирования каждого диска 300 секунд (аргумент s), размер блока 64Кб (аргумент b), Число блоков в строке равно единице (аргумент f), число строк равно 2000000 (аргумент i), число очередей тоже равно единице (аргумент o), число потоков равно единице (аргумент t). Суммарный размер файла рабочей нагрузки на каждом диске составляет 128Гб, что почти совпадает с размером диска.

sqlio -kR -s300 -b64 -f1 -i2000000 -o1 -t1 -R1 -LP -a0xf -BN > R01-b64-f1-i2000000-o1-t1.log

timeout /T 30

sqlio -kW -s300 -b64 -f1 -i2000000 -o1 -t1 -R1 -LP -a0xf -BN > W01-b64-f1-i2000000-o1-t1.log

timeout /T 30

sqlio -kR -s300 -b64 -f1 -i2000000 -o1 -t1 -R2 -LP -a0xf -BN > R02-b64-f1-i2000000-o1-t1.log

timeout /T 30

sqlio -kW -s300 -b64 -f1 -i2000000 -o1 -t1 -R2 -LP -a0xf -BN > W02-b64-f1-i2000000-o1-t1.log

timeout /T 30

……

sqlio -kR -s300 -b64 -f1 -i2000000 -o1 -t1 -R13 -LP -a0xf -BN > R13-b64-f1-i2000000-o1-t1.log

timeout /T 30

sqlio -kW -s300 -b64 -f1 -i2000000 -o1 -t1 -R13 -LP -a0xf -BN > W13-b64-f1-i2000000-o1-t1.log

timeout /T 30

sqlio -kR -s300 -b64 -f1 -i2000000 -o1 -t1 -R14 -LP -a0xf -BN > R14-b64-f1-i2000000-o1-t1.log

timeout /T 30

sqlio -kW -s300 -b64 -f1 -i2000000 -o1 -t1 -R14 -LP -a0xf -BN > W14-b64-f1-i2000000-o1-t1.log

Ниже представлен пример отчёта о тесте операций записи для первого диска:

sqlio v1.5.SG

calibrating timestamp counter for latency timings... done (MHz measured at 2359)

1 thread reading for 300 secs from file 1:

                        using 64KB IOs over 64KB stripes with 2000000 IOs per run

                        enabling multiple I/Os per thread with 1 outstanding

                        buffering set to not use file nor disk caches (as is SQL Server)

                        affinity mask is 0xf (15)

initialization done

CUMULATIVE DATA:

throughput metrics:

IOs/sec:   999.67

MBs/sec:    66.91

latency metrics:

Min_Latency(ms): 0

Avg_Latency(ms): 0

Max_Latency(ms): 802

histogram:

ms: 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24+

%: 87 13  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0

 

В этом отчёте нас интересует метрика скорости чтения, именно эту метрику мы будем сводить в общий график (MBs/sec: 66.91). Метрика IOs/sec практически линейно зависит от MBs/sec, поскольку в каждом из тестов у нас будет фиксированный размер запроса ввода-вывода. Метрики для задержки запроса ввода-вывода (latency) могут быть интересны вкупе с MBs/sec для сравнения разных дисковых подсистем. Нас такое сравнение не интересует, поэтому метрики MBs/sec вполне достаточно.

Автоматизировать извлечение из файлов с результатами тестов необходимых для дальнейших оценок значений показателей производительности можно, например, с помощью PowerShell. В примере ниже показана команда, которая сохраняет в CSV-файле имена файлов и соответствующее им значение MBs/sec:

(Select-String -Pattern MBs/sec: -Path *.log | format-table `

{$_.Filename -replace ".log", ""}, `

{($_.Line).replace(‘.’, ‘,’) -replace "MBs/sec: ", ";"} `

-HideTableHeaders) | Out-File SQLIO.csv -Encoding ASCII –Append

Если результаты сильно выбиваются из общей массы, желательно для такого диска повторить измерения, существенно (например, в два раза) увеличив время теста (аргумент s). На полученные результаты может сильно влиять посторонняя активность на сервере. Старайтесь не подключаться к консоли сервера или посещать его в терминальном режиме, пока не будет закончен очередной пакет тестов. Кроме того, постарайтесь отключить на время тестирования любую другую постороннюю активность на сервере.

На Рисунке 3 показан результат калибровочного тестировании 13 дисков.

Рис. 3.

Наиболее важной задачей нагрузочного тестирования является выявление дисков, характеристики которых существенно отличаются от остальных. На Рисунке 2 диски практически идентичны, как по записи, так и по чтению. Однако, при тестировании большого числа дисков вероятность столкнуться с «подозрительными» дисками много выше. Например, такой пример показан на Рисунке 4. Обратите внимание на четырнадцатый диск.

Рис. 4.

Совсем не обязательно, что в плохих или, наоборот, невероятно хороших результатах повинен сам диск. Причиной может стать неисправность дискового контроллера, терминатора шины или электрических цепей шины дисковой «полки».

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

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

Особо хочется остановиться на вопросах документирования результатов измерений. Обратите внимание на заголовок таблиц каждого из представленных ранее двух результатов. Это строки:

 

sqlio -kRW -s300 -f1 -i2000000 -o1 -b64 -t1 -LP -R(2-14) -a0xff

sqlio -kRW -s300 -f1 -i2000000 -o1 -b64 -t1 -LP -R(0-13) -a0xff

 

Мне видится наиболее удобным и практичным именно такой вид описания тестовой конфигурации. Суть состоит в том, чтобы просто скопировать из командного файла строку запуска программы SQLIO и внести изменение в написание изменяемых параметров. В данном случае для параметра –R в скобках был задан диапазон изменения порядковых номеров дисков. В первом случае это диски со второго по четырнадцатый, а во втором случае – это диски с нулевого по тринадцатый. Подобные описатели конфигурации будут встречаться далее в этой статье для демонстрации результатов измерений.

Этап №2. Масштабирование дисков

Следующим этапом идёт выявление предельных возможностей дисковой подсистемы и калибровка её, как цельного компонента.

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

Производительность отдельных компонент дисковой подсистемы в данной методике не исследуется, хотя понятно, что абстрагироваться от этого полностью невозможно. В предлагаемой методике мы смотрим на дисковую подсистему, условно, как на "чёрный ящик". Ограничения, а также разного рода ошибки, могут быть совершенно в разных местах. Чтобы начать разговор об этом с администраторами дисковой подсистемы, нужно иметь аргументы. Масштабирование позволяет получить на руки факты именно из этой области. Кроме того, поскольку мы хотим получить в итоге некий эталон производительности, подобные измерения бывают весьма полезны.

В качестве подготовки к этому этапу, нужно убедиться, что сервер и полка подключены друг к другу оптимальным способом и задействованы все особенности подключений, позволяющие повысить производительность передачи данных между дисками и сервером. Достигается это, например, увеличением числа используемых «петель» подключений, выбором оптимальных способов балансирования нагрузки через множество путей ввода-вывода, выбором более производительных интерфейсов, режимом работы и способом привязки дисковых контроллеров и т.д. и т.п. Для получения полной картины возможностей оптимизации тестируемой системы, обратитесь к технической документации вендора.

Суть теста очень проста. Вначале файл рабочей нагрузки помещается только на один диск, точно так же, как это делалось в предыдущем, калибровочном тесте. Потом тестируется конфигурация, когда файл рабочей нагрузки размещён на двух дисках. В калибровочном тесте файл всегда был только на одном диске, менялись только сами диски. В этом же тесте диски не меняются, а в каждом тесте добавляется ещё один диск и на нём размещается ещё один файл. Таким образом, число тестируемых диско в представленном ниже на Рисунке 5 примере результата изменяется от одного до тринадцати.

Рис.5.

Для документирования подобного приращения числа дисков я использую сочетание символов «à». Т.о. для обозначения приращения дисков, которое начинается с диска под номером 2 в нумерации операционной системы и заканчивается обоймой из тринадцати дисков по диск номер 14 включительно, можно использовать следующую запись: -R(2->14).

В командном файле это выглядит примерно так:

sqlio -kR -s180 -b64 -f1 -i2000000 -o1 -t1 -R2 -LP -a0xf -BN > R2-b64-f1-i2000000-o1-t1.log

timeout /T 30

sqlio -kW -s180 -b64 -f1 -i2000000 -o1 -t1 -R2 -LP -a0xf -BN > W2-b64-f1-i2000000-o1-t1.log

timeout /T 30

sqlio -kR -s180 -b64 -f1 -i2000000 -o1 -t1 -R2,3 -LP -a0xf -BN > R23-b64-f1-i2000000-o1-t1.log

timeout /T 30

sqlio -kW -s180 -b64 -f1 -i2000000 -o1 -t1 -R2,3 -LP -a0xf -BN > W23-b64-f1-i2000000-o1-t1.log

timeout /T 30

… результаты сокращены…

sqlio -kR -s180 -b64 -f1 -i2000000 -o1 -t1 -R2,3,4,5,6,7,8,9,10,11,12,13 -LP -a0xf -BN > R2345678910111213-b64-f1-i2000000-o1-t1.log

timeout /T 30

sqlio -kW -s180 -b64 -f1 -i2000000 -o1 -t1 -R2,3,4,5,6,7,8,9,10,11,12,13 -LP -a0xf -BN > W2345678910111213-b64-f1-i2000000-o1-t1.log

timeout /T 30

sqlio -kR -s180 -b64 -f1 -i2000000 -o1 -t1 -R2,3,4,5,6,7,8,9,10,11,12,13,14 -LP -a0xf -BN > R234567891011121314-b64-f1-i2000000-o1-t1.log

timeout /T 30

sqlio -kW -s180 -b64 -f1 -i2000000 -o1 -t1 -R2,3,4,5,6,7,8,9,10,11,12,13,14 -LP -a0xf -BN > W234567891011121314-b64-f1-i2000000-o1-t1.log

 

Получив информацию о том, какова реальная пропускная способность вашей дисковой подсистемы, вы можете спланировать дальнейшие тестовые конфигурации. Выбор тестируемых конфигураций может быть обусловлен вашими бизнес - требованиями к доступности и готовности серверов, а также отводимыми на тестирование сроками (полный цикл тестирования согласно данной методике может занимать порядка 7 суток круглосуточной работы тестового сервера). Зная, какое количество шпинделей потенциально может «запрудить» шину или контроллер, вы можете выбрать, сколько дисков оптимально собирать в один массив. Кроме того, в целях оптимизации времени тестов, данная методика предполагает допущение, что сервер баз данных, как и утилита SQLIO, балансирует нагрузку между дисками лучше, чем контроллер дискового массива. Как вы помните, база данных может состоять из нескольких файлов, и SQL Server будет резервировать в этих файлах пространство под новые страницы пропорционально размеру файлов. Учитывая эту особенность, мы ограничим число создаваемых массивов только некоторыми избранными конфигурациями, которые в лучшей мере используют преимущества балансировки ввода-вывода с помощью SQL Server. Т.е. это будут те конфигурации, которые не противоречат здравому смыслу и предлагают максимальное количество файлов. Ещё одним допущением для данной методики является то, что в каждой из тестовых конфигураций число шпинделей остаётся неизменным. Это нужно для того, чтобы сравнивать производительность разных массивов при равной стоимости оборудования.

Лучше всего рассмотреть вариант подобной тестовой схемы на примере, с графическими изображениями сайзинга дисков в массиве. Поскольку у нас уже собрана самая простая, и, во многих случаях, самая эффективная конфигурация дисков в массивы, начнём с неё. Похожая конфигурация показана на рисунке 6, и условно обозначается noRAID.

Рис.6.

Современные дисковые контроллеры часто не предусматривают возможности конфигурирования отдельных дисков, однако, оставляют возможность создания RAID0 из одного диска.

Следующие конфигурации, показанные на рисунках 7 и 8, представляют RAID1 и RAID0.

Рис.7.

Рис.8.

Конфигурации массивов RAID5 и RAID10 тоже внешне очень похожи, у них будет одинаковое количество логических дисков (LUN).

Рис.9.

Рис.10.

Каждая из показанных на рисунках конфигурация используется для прогона тестов, которые описаны на этапе 4.

Этап №3. Выбор размера сегмента

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

В этой статье мы будем полагаться на то, что бизнес - требования наших приложений указывают на необходимость обеспечения высокой производительности запросов упреждающего чтения. Как известно, упреждающее чтение характерно тем, что размер запроса ввода – вывода чаще всего равняется 64 Кб. SQL Server пытается считывать данные не страницами, а экстентами, разумеется, если размер запроса соответствующий и фрагментация данных позволяет это сделать. Мы допускаем, что фрагментацию удаётся поддерживать в приемлемых рамках, а оптимизация запросов ввода-вывода, размер которых близок к размеру страницы 8 Кб, не представляется необходимой, поскольку такие запросы будут обслуживаться практически одинаково в разных конфигурациях в силу своих малых размеров. Также, мы будем опираться на очень распространённое бизнес-правило, что время резервного копирования и восстановления базы данных из резервной копии должны быть минимальными. В своих измерениях Вы можете полагаться на иные требования и правила. Чтобы помочь Вам сориентироваться в выборе размеров нагрузки, тут будет уместно привести Таблицу 2, в которой показано соотношение разных операций и размеров запросов.

Таблица 2. Характеристики для основных типов нагрузки ввода – вывода SQL Server

 

Характер нагрузки

Доступ:

случайный / последовательный

Преобладает:

чтение / запись

Размер запроса

ввода-вывода

Журнал транзакций OLTPсистемы

последовательный

запись

512 Б - 64 КБ

Файлы данныхOLTPсистемы

случайный

чтение - запись

8 КБ

Массовая вставка

последовательный

запись

от 8 КБ до 256 КБ

Упреждающее чтение, просмотр индекса

последовательный

чтение

от 8 КБ до 256 КБ

Резервное копирование

последовательный

чтение / запись

1 МБ

Отложенная запись

последовательный

запись

от 128 КБ до 2 МБ

Восстановление из копии

последовательный

чтение / запись

64 КБ

Контрольная точка

последовательный

запись

от 8 КБ до 128 КБ

CREATE DATABASE

последовательный

запись

512 КБ

CHECKDB

последовательный

чтение

8 КБ - 64 КБ

DBREINDEX

последовательный

чтение / запись

чтение:

от 8 КБ до 256 КБ

запись:

от 8 КБ до 128 КБ

SHOWCONTIG

последовательный

чтение

8 KБ - 64 КБ

 

Как правило, выбор размера сегмента не является сложной задачей и, зачастую, предсказуем. Например, ниже, на Рисунке 11 показана весьма распространённая зависимость производительности одного диска от размера сегмента.

Рис.11.

Многие специалисты рекомендуют устанавливать размер блока для форматирования NTFS раздела операционной системы Windows равным 64 Кб и делать такого же размера размер сегмента при монтировании дискового массива. Глядя на представленный Рисунком 11 график, становится понятно, откуда взялась эта рекомендация.

Этап №4. Сравнение производительности разных типов дисковых массивов

Заключительный этап позволяет выяснить возможности разных типов дисковых массивов, что может стать отличным подспорьем при определении наиболее оптимальной конфигурации дисков, а также позволит предсказать, какие характеристики будут у разных конфигураций дисковой подсистемы. По результатам таких тестов можно будет осознанно разместить файлы сервера баз данных на дисковой подсистеме. Такую операцию на IT-жаргоне принято называть сайзингом.

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

Каждый уровень RAID будет подвержен пяти тестовым сериям измерения скорости чтения и записи, для разных размеров блока. Размер блока (который задаётся параметром –b) будет принимать следующий набор значений: 1024, 512, 256, 64, 8. Как вы, наверное, заметили, размеры блока соответствуют размерам основных типов запросов ввода-вывода. Выбор размеров блока для тестирования важен, поскольку не стоит включать в тест те размеры запросов ввода – вывода, которые не важны, или не характерны для ваших приложений. Например, если в вашей промышленной среде существуют достаточно продолжительные окна для проведения технологических планов обслуживания баз данных, тогда можно исключить из теста размер блока в 128Кб. Если время создания базы данных тоже не критично (например, если вы используете RAW-партиции), можно убрать тест с размером блока 512Кб.

Кроме изменения размера блока (под блоком будем понимать размер запроса ввода-вывода), данная методика предполагает изменение ещё нескольких, критически важных характеристик рабочей нагрузки. Нам нужно оценить производительность не только для одного запроса, но и в условиях относительно глубоких очередей запросов ввода-вывода, а также распараллеливания этих запросов. Глубина очереди будет увеличиваться до 64. Шаг приращения величины очереди тоже стоит выбирать таким, какой характерен для ваших приложений или, как это будет показано в нашем примере, это могут быть отдельные, характерные для ваших задач значения. Мы будем использовать следующие параметры очереди: о1, о2, о4, о8, о16, о32, о64.

Число потоков у нас будет изменяться от одного до четырёх, ровно столько на тестовом сервере имеется ядер процессора. Синхронно с числом потоков будет изменяться страйп-фактор. Здесь, под числом страйпов (страйп-фактор) понимается число блоков в строке файла нагрузки. Значение переменной основного цикла программы (число страйпов в файле нагрузки) тоже будет меняться, оно вычисляется каждый раз таким образом, чтобы при текущем размере блока и числе блоков в страйпе, размер файла нагрузки был близок к ёмкости диска. Поскольку число вычислений значений параметра i (основной цикл) достаточно велико, лучше заранее подготовить небольшие таблички, охватывающую все выбранные для тестирования варианты параметров и конфигурации. Например, на рисунке 12 представлена подобная таблица.

Рис.12.

Здесь, в ячейке A1 указан размер раздела диска (в данном случае у всех дисков он одинаков). Количество строк файла нагрузки, помещаемого на каждый из задействованных дисков, вычисляется делением размера раздела в Кб на размер блока (b), потом на число потоков (t) блоков в страйпе (f).

Настоящая методика использует несколько эмпирических допущений, которые существенно уменьшают объём выполняемых тестов. Рисунок 12 как раз и демонстрирует одно из таких допущений. Т.е. мы тестируем не все возможные варианты сочетаний параметров запуска SQLIO, а только те, которые перечислены в таблице. Т.е. Значения для параметров t и f могут быть 1,2,4,8,16. Поскольку максимальное значение для параметра t рекомендуется избирать не выше числа ядер процессоров (а в пример на рисунке 12 их число было 16). Значение f не должно превышать значение t, диапазон изменения этих параметров будет именно такой, как вы видите на рисунке. В колонке A, начиная со строки 2, заданы размеры запросов ввода вывода, которые характерны для приложения. Эти значения используются для параметра b. В таблице не хватает только одного из определяющих конфигурацию каждого теста параметра, это глубина очереди, задающаяся параметром o. Как и в нашем случае, в примере на рисунке 12 использовались следующие параметры очереди: о1, о2, о4, о8, о16, о32, о64.

Документирование конфигурации проще показать и подробно разобрать на следующем примере:

f(1,2,4) -i(1950,975,487) -o(1-64) -b1024 -t(1,2,4) -LP -R2,3,4 -a0xf

Здесь, размер блока был установлен в 1024Кб. Число блоков в страйпе файла нагрузки изменялось синхронно с числом потоков, т.е. значения были равны, и составляли: 1, 2 и 4. В зависимости от последнего числа изменяется число страйпов файла рабочей нагрузки. В этом тесте для мегабайтного размера блока значения такие: i1950, i975, i487. Глубина очереди изменялась так, как я показывал ранее, от единицы до 64.

В Таблице 3 показаны результаты теста, полученные для разных значений изменяемых параметров.

Таблица 3. RAID1:

Чтение

f1-t1

f2-t2

f4-t4

o1

373,23

371,05

345,67

o2

373,49

326,56

331,87

o4

373,45

325,20

330,36

o8

373,01

331,09

318,53

o16

371,91

321,52

281,54

o32

368,80

290,96

264,18

o64

351,11

276,80

262,61

2585,00

2243,18

2134,76

6962,94

Среднее:

331,57

Запись

f1-t1

f2-t2

f4-t4

o1

185,52

307,15

290,45

o2

307,73

259,25

257,31

o4

336,09

328,68

255,48

o8

337,55

254,93

241,74

o16

335,02

245,59

209,88

o32

322,65

219,26

214,20

o64

287,12

215,73

211,50

2111,68

1830,59

1680,56

5622,83

Среднее:

267,75

В таблицах с четвёртой по седьмую представлены значения для других размеров блока. Поскольку подобные тесты проводятся для всех тестируемых уровней RAID, и каждый такой тест содержит по пять таблиц, тут мы ограничимся демонстрацией результатов только для RAID1.

Таблица 4. RAID1: f(1,2,4) -i(3900,1900,970) -o(1-64) -b512 -t(1,2,4) -LP -R2,3,4 -a0xf

Чтение

f1-t1

f2-t2

f4-t4

o1

373,15

372,56

361,55

o2

373,13

261,15

313,54

o4

372,56

268,08

307,82

o8

373,04

235,48

253,12

o16

373,07

237,75

237,83

o32

371,31

236,25

237,08

o64

367,76

230,83

231,77

2604,02

1842,10

1942,71

6388,83

Среднее:

304,23

Запись

f1-t1

f2-t2

f4-t4

o1

156,97

265,91

265,18

o2

268,31

251,29

206,90

o4

332,29

325,32

180,68

o8

340,85

249,96

182,40

o16

332,81

190,25

172,63

o32

328,80

185,35

173,92

o64

317,41

183,24

176,61

2077,44

1651,32

1358,32

5087,08

Среднее:

242,24

 Таблица 5. RAID1: f(1,2,4) -i(500000,250000,125000) -o(1-64) -b256 -t(1,2,4) -LP -R2,3,4 -a0xf

Чтение

f1-t1

f2-t2

f4-t4

o1

374,15

243,60

248,95

o2

375,00

309,89

290,07

o4

375,03

306,97

291,95

o8

374,98

313,63

313,85

o16

375,03

306,96

304,26

o32

374,97

304,35

234,59

o64

374,12

301,15

255,86

2623,28

2086,55

1939,53

6649,36

Среднее:

316,64

Запись

f1-t1

f2-t2

f4-t4

o1

121,68

172,75

167,27

o2

191,64

311,50

261,88

o4

313,80

328,33

157,86

o8

331,46

332,86

145,59

o16

336,23

326,75

160,41

o32

334,63

193,98

159,45

o64

330,98

186,63

160,22

1960,42

1852,80

1212,68

5025,90

Среднее:

239,33

 Таблица 6. RAID1: f(1,2,4) -i(2000000,1000000,500000) -o(1-64) -b64 -t(1,2,4) -LP -R2,3,4 -a0xf

Чтение

f1-t1

f2-t2

f4-t4

o1

348,86

167,24

371,95

o2

371,32

279,76

338,58

o4

370,44

202,74

344,97

o8

370,53

223,38

371,38

o16

374,59

205,17

323,17

o32

374,90

170,97

191,85

o64

374,86

156,27

171,86

2585,50

1405,53

2113,76

6104,79

Среднее:

290,70

Запись

f1-t1

f2-t2

f4-t4

o1

107,37

135,34

147,57

o2

141,84

154,48

169,75

o4

165,56

170,44

174,16

o8

187,45

192,70

173,17

o16

193,43

193,40

179,14

o32

193,92

193,75

176,27

o64

194,66

193,26

176,17

1184,23

1233,37

1196,23

3613,83

Среднее:

172,09

 Таблица 7. RAID1: f(1,2,4) -i(16000000,8000000,4000000) -o(1-64) -b8 -t(1,2,4) -LP -R2,3,4 -a0xf

Чтение

f1-t1

f2-t2

f4-t4

o1

123,89

101,73

87,55

o2

169,70

116,12

91,55

o4

184,15

118,78

87,39

o8

211,35

129,39

81,27

o16

216,18

111,26

91,28

o32

185,17

121,52

94,14

o64

172,73

123,32

94,16

1263,17

822,12

627,34

2712,63

Среднее:

129,17

Запись

f1-t1

f2-t2

f4-t4

o1

33,37

44,20

36,90

o2

53,05

37,09

53,80

o4

68,42

68,16

78,35

o8

79,19

78,15

78,50

o16

79,48

78,59

73,41

o32

79,35

75,58

87,38

o64

88,29

87,56

87,42

481,15

469,33

495,76

1446,24

Среднее:

68,87

 

По каждому из пяти режимов тестирования мы считаем среднее значение. Моя практика показывает, что такой простой формулы оказывается вполне достаточно, однако, это не исключает таких конфигураций, когда потребуется более взвешенный выбор статистических методов. Для каждого из тестируемых уровней RAID средние значения сводятся в общую таблицу, по которой уже можно строить график, удобный для сравнения эффективности разных уровней RAID в используемой тестовой среде.

На Рисунке 13 показан график средних значений производительности троек массивов для разных уровней RAID. Разными цветами обозначены размеры блоков. Шкала показывает производительность в Мб/сек.

Рис.13.

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

 При выборе другого оборудования или в условиях другого характера нагрузки, например, OLTP, график вполне может стать другим. На Рисунке 14 показан график для другой аппаратной платформы, у которой можно было создавать массивы RAID10.

Рис.14.

На рисунках 14 и 15 показаны результаты для варианта прямого подключения дисковой подсистемы. На рисунке 16 показаны результаты тестирования дисковой подсистемы и сервера  другого вендора, и в варианте подключения SAN.

Рис.15.

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

Выводы

Сегодня типичные объёмы обслуживаемых СУБД данных настолько велики, что для дисковых подсистем уже недостаточно нескольких дисков, всё чаще, типовое приложение оперирует дисковой полкой в 14 или 15 дисков, а объёмы дисковых массивов достигают Терабайта. В таких условиях задачи сайзинга становятся очень важны, и грамотное распределение файлов вкупе с правильным выбором дисковых массивов позволяют существенно повысить производительность приложений, а также добиться требуемых значений производительности без лишних издержек энергопотребления.

В технических изданиях и в документации вендоров часто можно видеть рекомендации по выбору разных уровней RAID, и сайзингу файлов. Как правило, предлагаются универсальные решения, не позволяющие достичь максимальной эффективности вложений в аппаратные средства. Кроме того, в случае использования бюджетных контроллеров и дисков высока вероятность того, что их реальные характеристики будут сильно отличаться от ожидаемых или максимальных значений, используемых веднорами для рекламы своих продуктов. Предлагаемая методика даст вам возможность более реалистично оценить возможности предоставленной в ваше распоряжение дисковой подсистемы.

Одно из практических наблюдений при тестировании бюджетных дисковых контроллеров я хотел бы выделить особо. Как показывает практика многочисленных тестов, возможности балансирования нагрузки ввода вывода между физическими дисками у SQL Server лучше, чем у аппаратных средств. Т.е. часто отказ от использования RAID-массивов позволяет в итоге получить более высокую производительность, чем на том же количестве шпинделей, но собранных в RAID любого уровня.

Приложение 1. Пример командного файла.

 

Благодарности

 

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

Posted by gladchenko | 1 comment(s)
Filed under:

Tips for DBA: Log Flush Performance

Одной из распространённых задач систем с высокой транзакционной загрузкой является определение того, достаточно ли производительна подсистема ввода-вывода, обслуживающая журнал транзакций. Часто «узким местом» становиться дисковая подсистема, используемая в качестве долговременного носителя для файла журнала транзакций обслуживаемой SQL Server базы данных. Одним из важных параметров дисковой подсистемы является время доступа к данным на диске. Современным дисковым подсистемам характерно время доступа порядка 1 – 5 ms. Проверить, какое время доступа у используемой для размещения файла журнала транзакций дисковой подсистемы можно с помощью административного динамического представления: sys.dm_os_wait_stats (Transact-SQL). Данные в этом представлении накапливаются с момента последнего запуска службы SQL Server, поэтому, рекомендуется очистить эту статистику. Сделать это можно следующей командой:

    DBCC SQLPERF ('sys.dm_os_wait_stats', CLEAR);
    GO

В качестве единственно важного для нас типа ожидания нужно использовать WRITELOG, которое имеет место при ожидании завершения записи журнала. Обычно запись журнала вызывается такими операциями, как контрольные точки и фиксации транзакций. В упрощённом виде формализовать проверку производительности сброса страниц журнала на диск можно с помощью следующего сценария:

    SELECT      (wait_time_ms - signal_wait_time_ms) / waiting_tasks_count AS [Время отклика долговременного носителя журнала (ms)]
                  ,    max_wait_time_ms AS [Максимальное время ожидания (ms)]
    FROM        sys.dm_os_wait_stats
    WHERE       wait_type = 'WRITELOG' AND waiting_tasks_count > 0;

Здесь:

     

  • wait_time_ms - общее время ожидания данного типа в миллисекундах. Это время включает в себя время signal_wait_time_ms.
  • signal_wait_time_ms - разница между временем сигнализации ожидающего потока и временем начала его выполнения.
  • waiting_tasks_count - число ожиданий данного типа. Этот счетчик наращивается каждый раз при начале ожидания.
  • max_wait_time_ms - максимальное время ожидания данного типа.

     

В публичном документе Майкрософт: «Diagnosing Transaction Log Performance Issues and Limits of the Log Manager» (автор: Mike Ruthruff) рекомендовано чтобы время отклика долговременного носителя журнала было в диапазоне от 1ms до 5ms.

Posted by gladchenko | 1 comment(s)
Filed under:

Tips for DBA: Percentage of work completed for DBA commands

Как вы наверняка знаете, повторное исполнение команды KILL для сеанса показывает процент завершения отката прерванной инструкции. Это замечательная возможность, которая позволяет сберечь нервы администратора баз данных. Однако, есть и другие долгоиграющие команды, процент завершения которых тоже интересно было бы отслеживать. Ну, например, примерно таким же образом, как сообщает о прогрессе своей работы команда BACKUP. Вашему вниманию предлагается сценарий, который позволяет отслеживать прогресс исполнения следующих команд:

  • ALTER INDEX REORGANIZE
  • AUTO_SHRINK с ALTER DATABASE
  • BACKUP DATABASE
  • CREATE INDEX
  • DBCC CHECKDB
  • DBCC CHECKFILEGROUP
  • DBCC CHECKTABLE
  • DBCC INDEXDEFRAG
  • DBCC SHRINKDATABASE
  • DBCC SHRINKFILE
  • KILL (Transact-SQL)
  • RESTORE DATABASE
  • UPDATE STATISTICS

В сценарии использованы следующие административные представления и функции:

Текст сценария:

    -- Процент исполнения длительного запроса ввода-вывода
    SELECT ost.session_id
         , DB_NAME(ISNULL(s.dbid,1)) AS dbname
         , er.command
         , er.percent_complete
         , er.status
         , osth.os_thread_id
         , ost.pending_io_count
         , ost.scheduler_id
         , osth.creation_time
         , ec.last_read
         , ec.last_write
         , s.text
         , owt.exec_context_id
         , owt.wait_duration_ms
         , owt.wait_type
    FROM   master.sys.dm_os_tasks AS ost
    JOIN   master.sys.dm_os_threads AS osth ON ost.worker_address = osth.worker_address
    AND    ost.pending_io_count > 0 AND ost.session_id IS NOT NULL
    JOIN   master.sys.dm_exec_connections AS ec ON ost.session_id = ec.session_id
    CROSS  APPLY master.sys.dm_exec_sql_text(ec.most_recent_sql_handle) AS s
    JOIN   master.sys.dm_os_waiting_tasks AS owt ON ost.session_id = owt.session_id
    AND    owt.wait_duration_ms > 0
    JOIN   master.sys.dm_exec_requests AS er ON ost.session_id = er.session_id
    AND    er.percent_complete > 0
    ORDER BY ost.session_id
    GO

Posted by gladchenko | 1 comment(s)
Filed under:

Tips for DBA: Logical Disk FreeSpace Notification

В SQL Server 2008 с помощью службы SQL Server Agent и PowerShell можно достаточно просто соорудить задание, которое будет заглядывать в метаданные WMI локального или удалённого сервера, и сообщать по электронной почте, в случае если свободное место на указанном диске перешагнуло заданный порог. Ниже представлен облегчённый концепт сценария подобного задания (расписаний в нём нет и данные берутся по локальному серверу). Вам нужно будет заменить фиктивный адрес на реальный и указать почтовый профиль, если нельзя воспользоваться профилем по умолчанию.

    USE [msdb]
    GO
    DECLARE @jobId BINARY(16)
    EXEC msdb.dbo.sp_add_job
         @job_name=N'Наблюдение за местом на диске С: текущего сервера',
         @enabled=1,
         @notify_level_eventlog=0,
         @notify_level_email=0,
         @notify_level_netsend=0,
         @notify_level_page=0,
         @delete_level=0,
         @category_name=N'[Uncategorized (Local)]',
         @owner_login_name=N'sa', @job_id = @jobId OUTPUT
    EXEC msdb.dbo.sp_add_jobstep
         @job_id=@jobId,
         @step_name=N'1',
         @step_id=1,
         @cmdexec_success_code=0,
         @on_success_action=1,
         @on_success_step_id=0,
         @on_fail_action=3,
         @on_fail_step_id=0,
         @retry_attempts=0,
         @retry_interval=0,
         @os_run_priority=0,
         @subsystem=N'PowerShell',
         @command=N'$RemoteHost = "."
    $FreeSpace=((gwmi CIM_LogicalDisk -computerName $RemoteHost -filter "DeviceID = '
    'C:''").FreeSpace)/(1024*1024*1024)
    IF ($FreeSpace -lt 1000) {
    $conn = new-object system.data.oledb.oledbconnection
    $connstring = "provider=sqloledb;data source=.;initial catalog=tempdb;integrated security=SSPI"
    $conn.connectionstring = $connstring
    $conn.open()
    $cmd = New-Object system.data.oledb.oledbcommand
    $cmd.connection = $conn
    $FreeSpace = "'
    '"+$FreeSpace+"''"
    $sqlquery = "EXEC msdb.dbo.sp_send_dbmail @recipients='
    'AlexanderGladchenko@domen.com'',@subject=$FreeSpace"
    $cmd.commandtext = $sqlquery
    $cmd.executenonquery() > NULL
    $cmd = New-Object system.data.oledb.oledbcommand
    $conn.close()
    } Else {$FreeSpace}'
    ,
         @database_name=N'master',
         @flags=0
    EXEC msdb.dbo.sp_add_jobserver
         @job_id = @jobId,
         @server_name = N'(local)'
    GO

Posted by gladchenko | with no comments
Filed under: ,

Tips for DBA: Table operational/physical stats

Вашему вниманию предлагается сценарий, который для каждой таблицы текущей базы данных показывает статистику по операциям INSERT, UPDATE и DELITE. Кроме этого, вы может оценить, к чему эти операции приводят, с точки зрения роста строк данных, занимаемых страниц и фрагментации. Сценарий основан на использовании двух функций динамического управления: sys.dm_db_index_operational_stats и sys.dm_db_index_physical_stats

    /* Внимание!!! Запрос исполняется несколько минут */
    SELECT  
    t.name AS [TableName]
          , fi.page_count AS [Pages]
          , fi.record_count AS [Rows]
          , CAST(fi.avg_record_size_in_bytes AS int) AS [AverageRecordBytes]
          , CAST(fi.avg_fragmentation_in_percent AS int) AS [AverageFragmentationPercent]
          , SUM(iop.leaf_insert_count) AS [Inserts]
          , SUM(iop.leaf_delete_count) AS [Deletes]
          , SUM(iop.leaf_update_count) AS [Updates]
          , SUM(iop.row_lock_count) AS [RowLocks]
          , SUM(iop.page_lock_count) AS [PageLocks]
    FROM    sys.dm_db_index_operational_stats(DB_ID(),NULL,NULL,NULL) AS iop
    JOIN    sys.indexes AS i
    ON      ((iop.index_id = i.index_id) AND (iop.object_id = i.object_id))
    JOIN    sys.tables AS t
    ON      i.object_id = t.object_id
    AND     i.type_desc IN ('CLUSTERED', 'HEAP')
    JOIN    sys.dm_db_index_physical_stats(DB_ID(), NULL, NULL, NULL, 'SAMPLED') AS fi
    ON      fi.object_id=CAST(t.object_id AS int)
    AND     fi.index_id=CAST(i.index_id AS int)
    AND     fi.index_id < 2
    GROUP BY t.name, fi.page_count, fi.record_count
          , fi.avg_record_size_in_bytes, fi.avg_fragmentation_in_percent
    ORDER BY [TableName]

Posted by gladchenko | 4 comment(s)
Filed under:

Недокументированная процедура sp_tablecollations_100

Копался сегодня в одной из трассировок клиентских запросов и наткнулся на недокументированную системную хранимую процедуру (SQL Server 2008, на предыдущих не смотрел), которая позволяет узнать порядок сортировки для каждой из колонок таблицы. Вызывается она просто и результат очевиден:

Posted by gladchenko | with no comments
Filed under:

Tips for DBA: INSERT Overclocking

Одной из трудно оптимизируемых задач SQL Server является вставка. Не раз мне приходилось сталкиваться с ситуациями, когда уже и схема оптимизирована под вставку, и сайзинг файлов вставке не препятствует, а желаемой производительности массовой или не массовой вставки достичь не удаётся. Не хватает совсем немногого…

Разработчики SQL Server 2008 позаботились о том, чтобы предоставить нам с вами в распоряжение некую «палочку – выручалочку», которая призвана как раз снизить затраты на вставку, путём её не полного журналирования. Для этого предлагается задействовать на серверах флаг трассировки 610, который по моим наблюдениям действительно может немного облегчить вставку. Флаг, и его побочные эффекты, подробно описан тут: http://msdn.microsoft.com/ru-ru/library/dd425070(en-us).aspx

Ещё одна мера, в дополнение к включению флага трассировки 610, описана в документе вендора: http://technet.microsoft.com/ru-ru/library/cc917672(en-us).aspx. Там, среди прочего, подробно описано исследование того, что будет эффективней, вставка в таблицу с единственным некластеризованным индексом, или вставка в таблицу с единственным кластеризованным индексом. Кластеризация данных может дать выигрыш на вставке до 3%.

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

Posted by gladchenko | 1 comment(s)
Filed under:

Tips for DBA: Signal Waits vs. Resource Waits

Прочитал сегодня интересный рецепт, как быстро определить, кто даёт слабину, процессор или дисковая подсистема. Ну и заодно в очередной раз убедился в полезности книжки: Проектирование и оптимизация доступа к базам данных Microsoft SQL Server 2005. Учебный курс Microsoft (+ CD-ROM)

Авторы этого учебного курса считают, что соотношение суммарных ожиданий процессоров и ввода-вывода можно использовать для того, чтобы определить, кто из них из-за кого простаивает. Впрочем, вот выдержка из этой замечательной книги, со страницы 400:

Одной из самых сложных задач, с которыми сталкиваются разработчики баз данных, является прогнозирование поведения приложения в реальных условиях. Чтобы иметь точное представление о характеристиках производительности приложения, разработчик должен знать конкретную причину любого состояния ожидания, которое возникает во время выполнения приложения. На самом общем уровне состояния ожидания можно разбить на две категории: ожидание сигнала и ожидание ресурса. В SQL Server ожидание сигнала происходит, когда планировщик ждет процессор, чтобы запланировать задачу, а ожидание ресурса возникает, когда задача получила время процессора, но находится в ожидании ресурсов диска или памяти. При исследовании состояний ожидания в приложении нужно иметь в виду следующее. Если отношение времени ожидания сигнала ко времени ожидания ресурса велико (т.е. если состояний ожидания сигнала значительно больше, чем состояний ожидания ресурса), это может служить показателем неэффективного использования процессора. Если же велик коэффициент отношения времени ожидания ресурса ко времени ожидания сигнала, это может указывать на неэффективное использование ресурсов диска. Приступая к оценке производительности приложения, разработчики должны понимать, какой из типов ожидания преобладает. К счастью, SQLOS предоставляет "окно" в систему, достаточно прозрачное для того, чтобы разработчики могли использовать его для ответа на этот вопрос.

Представляю вам слегка модифицированный запрос из примера в этой книге, который использует динамическое административное представление sys.dm_os_wait_states, чтобы запросить у SQLOS информацию о суммарных временах ожидания ресурса и сигнала:

    USE master
    GO
    --DBCC SQLPERF ('sys.dm_os_wait_stats', CLEAR);
    --GO
    WITH ByWaitTypes([Тип ожидания], [ожидания сигнала %], [ожидания ресурса %], [ожидания ms]) AS
    (
    SELECT TOP 20 wait_type
       , cast(100.0 * sum(signal_wait_time_ms)/sum(wait_time_ms) AS NUMERIC (20,2))
       , cast(100.0 * sum(wait_time_ms - signal_wait_time_ms)/sum(wait_time_ms) AS NUMERIC(20,2))
       , sum(wait_time_ms)
    FROM sys.dm_os_wait_stats
    WHERE wait_time_ms <> 0
    GROUP BY wait_type
    ORDER BY sum(wait_time_ms) DESC
    )
    SELECT TOP 1 'Тип ожидания' = N'BCE!'
       , 'ожидания сигнала %' = (SELECT cast(100.0 * sum(signal_wait_time_ms)/
        sum (wait_time_ms) AS NUMERIC (20,2)) FROM sys.dm_os_wait_stats)
       , 'ожидания ресурса %' =(SELECT cast(100.0 * sum(wait_time_ms - signal_wait_time_ms)/
        sum(wait_time_ms) AS NUMERIC(20,2)) FROM sys.dm_os_wait_stats)
       , 'ожидания ms' =(SELECT sum(wait_time_ms) FROM sys.dm_os_wait_stats)
    FROM sys.dm_os_wait_stats
    UNION
    SELECT [Тип ожидания], [ожидания сигнала %], [ожидания ресурса %], [ожидания ms]
    FROM ByWaitTypes
    ORDER BY 'ожидания ms' DESC

Один из моих подопечных серверов вернул следующие результаты:

Тип ожидания ожидания сигнала % ожидания ресурса % ожидания ms
BCE! 10.18 89.82 109070003
LCK_M_U 0.19 99.81 63195933
BROKER_TASK_STOP 0.14 99.86 4831680
LAZYWRITER_SLEEP 0.02 99.98 4768764
REQUEST_FOR_DEADLOCK_SEARCH 100.00 0.00 4764971
XE_TIMER_EVENT 100.00 0.00 4741221
LOGMGR_QUEUE 4.04 95.96 4729823
FT_IFTS_SCHEDULER_IDLE_WAIT 0.00 100.00 4680082
CHECKPOINT_QUEUE 0.00 100.00 4519827
WRITELOG 21.61 78.39 2546141
SLEEP_TASK 0.26 99.74 2398521
BROKER_TO_FLUSH 0.03 99.97 2384867
XE_DISPATCHER_WAIT 0.00 100.00 1770518
PAGEIOLATCH_EX 0.75 99.25 1307584
CXPACKET 14.20 85.80 955856
PAGELATCH_EX 84.97 15.03 486757
IO_COMPLETION 2.24 97.76 270499
SLEEP_BPOOL_FLUSH 2.22 97.78 224846
PAGEIOLATCH_SH 1.04 98.96 151759
SOS_SCHEDULER_YIELD 99.89 0.11 133034
ASYNC_NETWORK_IO 5.06 94.94 79275

Результирующий набор будет содержать суммарное время ожидания и процентное соотношение этих значений. В верхней строке сумма по всем типам ожиданий (такой же результат даёт запрос из книжки), я ниже расположены уточняющие сведения, т.е. группировка по самой прожорливой десятке типов ожиданий.

В книге утверждается что, как правило, системы, имеющие низкий показатель ожидания сигнал/ресурс демонстрируют лучшую общую производительность. Так ли это, я надеюсь, обсудить вместе с вами, поскольку мои наблюдения говорят о том, сто слишком низкие показатели тоже говорят о проблемах (например, ввода-вывода). А как обстоит дело на ваших серверах?

Posted by gladchenko | 8 comment(s)
Filed under:

Tips for DBA: Store Performance Counters in Database (Job-Step: Power Shell)

Остались в прошлом те времена, когда средствами SQL Server можно было получить состояния счётчиков производительности, которые относились только к самому SQL Server. Для этого традиционно использовались системные представления sys.sysperfinfo и sys.dm_os_performance_counters.

С помощью Power Shell и нового в SQL Server 2008 типа шага в заданиях по расписанию, который позволяет запускать под управлением SQL Server Agent сценарии  Power Shell, теперь можно получить абсолютно любые счётчики производительности. Причём, сделать это можно как для локального, так и удалённого в сети сервера. А получение сведений о счётчиках посредством WMI избавляет от необходимости агрегации сырых значений, что делает этот метод простым и понятным.

Ниже представлен макет сценария, который создаёт администраторскую базу данных и в ней таблицу для хранения данных о двух счётчиках производительности: PercentDiskTime и PercentProcessorTime. Данные в эту таблицу поставляет создаваемое в сценарии задание по расписанию, в единственном шаге которого запускается сценарий Power Shel. Это сценарий подключается к указанному серверу, посредством WMI получает значения заданных счётчиков и записывает эти значения в созданную ранее таблицу.

Чтобы протестировать этот метод, в примере сценария замените имена серверов и учётных записей на те, которые действительны в вашей тестовой среде.

 

USE [master]

GO

 

CREATE DATABASE [_DBA_]

GO

ALTER DATABASE [_DBA_] SET COMPATIBILITY_LEVEL = 100

GO

 

USE [_DBA_]

GO

SET ANSI_NULLS ON

SET QUOTED_IDENTIFIER ON

SET ANSI_PADDING OFF

GO

CREATE TABLE [dbo].[HostUtilization](

      [countertime] [datetime] NOT NULL,

      [PercentDiskTime] [tinyint] NOT NULL,

      [PercentProcessorTime] [tinyint] NOT NULL,

      [Host] [varchar](30) NOT NULL,

 CONSTRAINT [PK_HostUtilization] PRIMARY KEY CLUSTERED

(

      [Host] ASC,

      [countertime] ASC

))

GO

SET ANSI_PADDING OFF

GO

ALTER TABLE [dbo].[HostUtilization]

ADD  CONSTRAINT [DF_HostUtilization_countertime] 

DEFAULT (getdate()) FOR [countertime]

GO

ALTER TABLE [dbo].[HostUtilization]

ADD  CONSTRAINT [DF_HostUtilization_PercentDiskTime] 

DEFAULT ((100)) FOR [PercentDiskTime]

GO

ALTER TABLE [dbo].[HostUtilization]

ADD  CONSTRAINT [DF_HostUtilization_PercentProcessorTime] 

DEFAULT ((100)) FOR [PercentProcessorTime]

GO

ALTER TABLE [dbo].[HostUtilization]

ADD  CONSTRAINT [DF_HostUtilization_Host] 

DEFAULT ('.') FOR [Host]

GO

 

 

USE [msdb]

GO

DECLARE @jobId BINARY(16)

EXEC msdb.dbo.sp_add_job

     @job_name=N'HostUtilization',

     @enabled=1,

     @notify_level_eventlog=2,

     @notify_level_email=0,

     @notify_level_netsend=0,

     @notify_level_page=0,

     @delete_level=0,

     @description=N'Monitoring server name: MICROSOFT'

     @category_name=N'[Uncategorized (Local)]',

     @owner_login_name=N'RU\AGladchenko',

     @job_id = @jobId OUTPUT

EXEC msdb.dbo.sp_add_jobstep @job_id=@jobId, @step_name=N'1',

     @step_id=1,

     @cmdexec_success_code=0,

     @on_success_action=3,

     @on_success_step_id=0,

     @on_fail_action=3,

     @on_fail_step_id=0,

     @retry_attempts=0,

     @retry_interval=0,

     @os_run_priority=0,

     @subsystem=N'PowerShell',

     @command=N'$RemoteHost = "MICROSOFT"

$PercentDiskTime=(gwmi Win32_PerfFormattedData_PerfDisk_PhysicalDisk -computerName $RemoteHost -filter "name = ''_Total''").PercentDiskTime

$PercentProcessorTime=(gwmi Win32_PerfFormattedData_PerfOS_Processor -computerName $RemoteHost -filter "name = ''_Total''").PercentProcessorTime

$conn = new-object system.data.oledb.oledbconnection

$connstring = "provider=sqloledb;data source=MYSUPERPUPERSERVERNAME;initial catalog=_DBA_;integrated security=SSPI"

$conn.connectionstring = $connstring

$conn.open()

$RemoteHost = "''"+$RemoteHost+"''"

$sqlquery = "INSERT INTO [_DBA_].[dbo].[HostUtilization] ([countertime],[PercentDiskTime],[PercentProcessorTime],[Host] ) VALUES (DEFAULT, $PercentDiskTime, $PercentProcessorTime, $RemoteHost)"

$cmd = New-Object system.data.oledb.oledbcommand

$cmd.connection = $conn

$cmd.commandtext = $sqlquery

$cmd.executenonquery() > NULL

$conn.close()',

     @database_name=N'master',

     @flags=32

EXEC msdb.dbo.sp_update_job

     @job_id = @jobId,

     @start_step_id = 1

EXEC msdb.dbo.sp_add_jobschedule @job_id=@jobId, @name=N'1',

     @enabled=1,

     @freq_type=4,

     @freq_interval=1,

     @freq_subday_type=2,

     @freq_subday_interval=30,

     @freq_relative_interval=0,

     @freq_recurrence_factor=0,

     @active_start_date=20090206,

     @active_end_date=99991231,

     @active_start_time=0,

     @active_end_time=235959,

     @schedule_uid=N'1b20bdf0-4627-4d31-8036-d85ff30cd664'

 

EXEC msdb.dbo.sp_add_jobserver

     @job_id = @jobId,

     @server_name = N'(local)'

GO

 

Posted by gladchenko | with no comments
Filed under: ,

Tips for DBA: SQL Server Inventory (PowerShell)

В трудовых буднях администратора баз данных не редко встречается задача инвентаризации своего серверного хозяйства или инвентаризации принимаемого на обслуживание сервера. Благодаря существованию WMI эта задача может быть частично или полностью автоматизирована. А благодаря PowerShell автоматизация становиться очень простой. В подтверждение этих слов приведу две ссылки:

Однако, поглядев на возможности WMI возникает резонный вопрос, что из этого многообразия свойств объектов стоит сохранять в инвентаризационной описи?

Вашему вниманию предлагается макет упрощённого PS-сценария, который делает опись текущего компьютера. Если нужно инвентаризировать удалённый компьютер, то присвойте переменной $srv не точку, а имя нужного сервера. Вывод информации происходит в файл, путь к которому тоже задаётся переменной и может быть изменён по необходимости.

    $srv = "."
    $Day = get-date -format "yyyyMMdd"
    $Time = get-date -format "HH"
    $LogFile = "c:\temp\Inventory_"+$srv + "_" + $Day + $Time + ".txt"
    "--------------------------- Computer  System --------------------------------------------------------------------------" | out-File "$LogFile" –append
    Get-WmiObject "Win32_ComputerSystem" -computer $srv | Format-Table -Wrap -Property Domain,PrimaryOwnerName,DNSHostName,
    Model,SystemType,NumberOfLogicalProcessors,NumberOfProcessors,TotalPhysicalMemory | out-File "$LogFile" –append
    "---------------------------     Network      --------------------------------------------------------------------------" | out-File "$LogFile" –append
    Get-WmiObject -class "Win32_NetworkAdapter" -computer $srv | Format-Table -Wrap -Property Name,AdapterType,DeviceID,
    Manufacturer,ServiceName | out-File "$LogFile" –append
    Get-WmiObject "Win32_NetworkAdapterConfiguration" -computer $srv | Format-Table -Wrap -Property IP | out-File "$LogFile" –append
    "---------------------------   Disk Drives    --------------------------------------------------------------------------" | out-File "$LogFile" –append
    Get-WmiObject "Win32_DiskDrive" -computer $srv | Format-Table -Wrap -Property Name,Model,InterfaceType,Partitions,SCSIBus,
    SCSILogicalUnit,SCSIPort,SCSITargetId,Size,BytesPerSector,SectorsPerTrack,TracksPerCylinder,TotalCylinders,TotalSectors,
    TotalTracks,TotalHeads | out-File "$LogFile" –append
    Get-WmiObject "Win32_DiskPartition" -computer $srv | Format-Table -Wrap -Property Name,Type,Index,BootPartition,
    PrimaryPartition,BlockSize,StartingOffset,NumberOfBlocks,Size | out-File "$LogFile" –append
    Get-WmiObject "Win32_Volume" -computer $srv | Format-Table -Wrap -Property Name,SerialNumber,DriveType,FileSystem,Capacity,
    FreeSpace,BlockSize,Compressed | out-File "$LogFile" –append
    Get-WmiObject -class "Win32_Share" -computer $srv | Format-Table -Wrap -Property Name,Path | out-File "$LogFile" –append
    "---------------------------    Processors    --------------------------------------------------------------------------" | out-File "$LogFile" –append
    Get-WmiObject "Win32_Processor" -computer $srv | Format-Table -Wrap -Property Name,DeviceID,CurrentClockSpeed,ExtClock,
    DataWidth,L2CacheSize,Version | out-File "$LogFile" –append
    "--------------------------- Operating System --------------------------------------------------------------------------" | out-File "$LogFile" –append
    Get-WmiObject "Win32_OperatingSystem" -computer $srv | Format-Table -Wrap -Property Name,Version,ServicePackMajorVersion,
    ProductType,TotalVisibleMemorySize,PAEEnabled | out-File "$LogFile" –append
    "---------------------------    Sql Server    --------------------------------------------------------------------------" | out-File "$LogFile" –append
    [System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.Smo") | Out-Null
    $server=new-object("Microsoft.SqlServer.Management.Smo.Server") $srv
    $server | Format-Table -Wrap -Property Product,Name,InstanceName,VersionString,Edition,InstallDataDirectory,PerfMonMode,
    ProductLevel,SqlCharSetName,SqlDomainGroup,NumberOfLogFiles,BackupDirectory | out-File "$LogFile" –append
    $server | Format-Table -Wrap -Property LoginMode,AuditLevel,ProxyAccount,TcpEnabled,NamedPipesEnabled,Collation,
    SqlSortOrderName,Language,IsCaseSensitive | out-File "$LogFile" –append
    "Services" | out-File "$LogFile" –append
    $server | Format-Table -Wrap -Property IsClustered,ServiceAccount,SrviceInstanceId,ServiceName,ServiceStartMode,
    BrowserServiceAccount,BrowserStartMode,IsFullTextInstalled,FilestreamLevel | out-File "$LogFile" –append

Posted by gladchenko | with no comments
Filed under: ,

Tips for DBA: The Spy for stored procedures

Вашему вниманию предлагается макет сценария и методики, позволяющей организовать учёт исполнения хранимых процедур пользовательской базы данных. Пример сценария само-достаточен, т.е. для его успешной работы необходимо только заменить в тексте сценария слово 'ТУТДОЛЖНОБЫТЬИМЯВАШЕЙБАЗЫДАННЫХ!!!!!!!!!!!!!!!!' на имя вашей базы данных, использование процедур которой необходимо отслеживать. Сценарий создаёт задание Агента SQL Server, которое по установленному расписанию (расписание подбирается в зависимости от нагрузки сервера) исполняет сценарий T-SQL. Исполняемый заданием сценарий создаёт по необходимости в базе TEMPDB таблицу Activproc, и потом записывает в ней статистику использования процедур, получая актуальные на момент исполнения метаданные сервера. Для того, чтобы понять принципы работы сценария, ознакомьтесь с теми разделами BOL, в которых описаны задействованные в сценарии административные динамические представления и функции.

Предлагаемая методика отслеживания активности процедур не гарантирует 100% точности собираемой статистики. Она полагается на то, что метаданные об исполнении процедур будут достаточно долго доступны и попадут в таблицу. Для сильно нагруженных серверов этого может не произойти. Однако, преимуществом этой методики является тот факт, что она не так нагружает сервер, как трассировка.

В примере сценария местом размещения таблицы статистики процедур выбрана база данных TEMPDB. Этот факт нужно учитывать, поскольку при каждом запуски службы SQL Server эта база данных создаётся заново, и информация в таблице статистики будет утеряна.

Пример сценария:

    USE [msdb]
    GO
    DECLARE @jobId BINARY(16)
    
    EXEC msdb.dbo.sp_add_job @job_name=N'Activproc', 
    	@enabled=1, 
    	@notify_level_eventlog=0, 
    	@notify_level_email=2, 
    	@notify_level_netsend=0, 
    	@notify_level_page=0, 
    	@delete_level=0, 
    	@description=N'Собирает простую статистику по использованию хранимых процедур', 
    	@category_name=N'Database Maintenance', 
    	@owner_login_name=N'sa', 
    --	@notify_email_operator_name=N'MS-SQL-Admins', 
    	@job_id = @jobId OUTPUT
    		
    EXEC msdb.dbo.sp_add_jobstep @job_id=@jobId, 
    	@step_name=N'Activproc 1', 
    	@step_id=1, 
    	@cmdexec_success_code=0, 
    	@on_success_action=1, 
    	@on_success_step_id=0, 
    	@on_fail_action=2, 
    	@on_fail_step_id=0, 
    	@retry_attempts=0, 
    	@retry_interval=0, 
    	@os_run_priority=0, 
    	@subsystem=N'TSQL', 
    	@command=N'IF NOT EXISTS (SELECT * FROM tempdb.sys.objects WHERE name = ''Activproc'')
    CREATE TABLE tempdb.[dbo].[Activproc]
    	(
    		[SP_Name] sysname NOT NULL,
    		[last_execution_time] datetime NOT NULL,
    		[avg_elapsed_time_sec] money NOT NULL
    	)
    DECLARE @SP_Name sysname, @last_execution_time datetime, @avg_elapsed_time_sec money
    DECLARE c_Activproc CURSOR GLOBAL FAST_FORWARD READ_ONLY FOR
    SELECT TOP 100 PERCENT    OBJECT_NAME(s.objectid,s.dbid) AS SP_Name
    			, MAX(st.last_execution_time) AS last_execution_time
    			, SUM(CAST((st.total_elapsed_time * 1.0 /100000)/st.execution_count AS money)) 
    			  AS avg_elapsed_time_sec
             FROM master.sys.dm_exec_cached_plans AS c
      CROSS APPLY master.sys.dm_exec_query_plan (c.plan_handle) AS q
       INNER JOIN master.sys.dm_exec_query_stats AS st
               ON c.plan_handle = st.plan_handle
      CROSS APPLY master.sys.dm_exec_sql_text(sql_handle) AS s
            WHERE c.cacheobjtype = ''Compiled Plan''
              AND c.objtype = ''Proc''
              AND q.dbid = DB_ID()
         GROUP BY DB_NAME(q.dbid),OBJECT_NAME(s.objectid,s.dbid)  
         ORDER BY avg_elapsed_time_sec DESC
    
    OPEN GLOBAL c_Activproc
    WHILE 1 = 1
    BEGIN
    	FETCH c_Activproc INTO @SP_Name, @last_execution_time, @avg_elapsed_time_sec
    	IF @@fetch_status <> 0 BREAK
    	IF @SP_Name NOT IN (SELECT SP_Name FROM tempdb.dbo.Activproc WHERE SP_Name = @SP_Name)
    	BEGIN
    		INSERT INTO tempdb.dbo.Activproc (SP_Name, last_execution_time, avg_elapsed_time_sec) 
    		VALUES (@SP_Name, @last_execution_time, @avg_elapsed_time_sec)
    	END
    	ELSE
    	BEGIN
    		UPDATE tempdb.dbo.Activproc 
    		SET last_execution_time = @last_execution_time, avg_elapsed_time_sec = @avg_elapsed_time_sec
    		WHERE SP_Name = @SP_Name
    	END
    END
    CLOSE GLOBAL c_Activproc
    DEALLOCATE c_Activproc
    GO', 
    	@database_name=N'ТУТДОЛЖНОБЫТЬИМЯВАШЕЙБАЗЫДАННЫХ!!!!!!!!!!!!!!!!', 
    	@flags=4
    EXEC msdb.dbo.sp_update_job @job_id=@jobId, 
    	@start_step_id = 1
    EXEC msdb.dbo.sp_add_jobschedule @job_id=@jobId, 
    	@name=N'1', 
    	@enabled=1, 
    	@freq_type=4, 
    	@freq_interval=1, 
    	@freq_subday_type=4, 
    	@freq_subday_interval=1, 
    	@freq_relative_interval=0, 
    	@freq_recurrence_factor=0, 
    	@active_start_date=20090217, 
    	@active_end_date=99991231, 
    	@active_start_time=0, 
    	@active_end_time=235959, 
    --	@schedule_uid=N'ffb0a0d2-93bc-49d0-9fc7-4e35140bfd9f'
    EXEC msdb.dbo.sp_add_jobserver @job_id=@jobId, 
    	@server_name = N'(local)'
    GO
    

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

    SELECT   [SP_Name]
            ,[last_execution_time]
            ,[avg_elapsed_time_sec]
        FROM [tempdb].[dbo].[Activproc]
    ORDER BY [avg_elapsed_time_sec] DESC
    GO
    
Posted by gladchenko | 3 comment(s)
Filed under:

Tips for DBA: How to trace Deprecated Features

Если необходимо отследить статистику использования отключаемого в будущих версиях функционала SQL Server 2008, можно воспользоваться представленным ниже сценарием. За основу этого сценария взятя информация о статистике значений счётчиков производительности, извлекаемая из административного динамического представления sys.dm_os_performance_counters

SELECT instance_name   AS [Старый функционал]
     , sum(cntr_value) AS [Число использований]
FROM   sys.dm_os_performance_counters
WHERE  object_name = 'SQLServer:Deprecated Features'
AND    cntr_value <> 0
GROUP BY instance_name
ORDER BY [Число использований] DESC

Posted by gladchenko | with no comments
Filed under:

Типовой сценарий настройки обслуживания новой установки SQL Server 2005

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

USE master
GO

EXEC sp_configure 'show advanced options', 1
RECONFIGURE WITH OVERRIDE 
GO

USE [msdb]
GO
EXEC msdb.dbo.sp_add_operator @name=N'MS-SQL-Admins', 
		@enabled=1, 
		@weekday_pager_start_time=0, 
		@weekday_pager_end_time=235900, 
		@saturday_pager_start_time=0, 
		@saturday_pager_end_time=235900, 
		@sunday_pager_start_time=0, 
		@sunday_pager_end_time=235900, 
		@pager_days=127, 
		@email_address=N'MS-SQL-Admins@domain.ru', 
		@pager_address=N'MS-SQL-Admins@domain.ru', 
		@category_name=N'[Uncategorized]', 
		@netsend_address=N'servermonitoringa'
GO

EXEC msdb.dbo.sp_add_alert @name=N'Access denied', 
		@message_id=10011, 
		@severity=0, 
		@enabled=1, 
		@delay_between_responses=0, 
		@include_event_description_in=1, 
		@category_name=N'[Uncategorized]', 
		@job_id=N'00000000-0000-0000-0000-000000000000'
GO

EXEC msdb.dbo.sp_add_notification @alert_name=N'Access denied', 
		@operator_name=N'MS-SQL-Admins', 
		@notification_method = 1;
GO
EXEC msdb.dbo.sp_add_alert @name=N'Access is denied due to a password failure', 
		@message_id=3279, 
		@severity=0, 
		@enabled=1, 
		@delay_between_responses=0, 
		@include_event_description_in=0, 
		@category_name=N'[Uncategorized]', 
		@job_id=N'00000000-0000-0000-0000-000000000000'
GO
EXEC msdb.dbo.sp_add_notification @alert_name=N'Access is denied due to a password failure', 
		@operator_name=N'MS-SQL-Admins', 
		@notification_method = 1;
GO
EXEC msdb.dbo.sp_add_alert @name=N'Login fails', 
		@message_id=4060, 
		@severity=0, 
		@enabled=1, 
		@delay_between_responses=0, 
		@include_event_description_in=0, 
		@category_name=N'[Uncategorized]', 
		@job_id=N'00000000-0000-0000-0000-000000000000'
GO
EXEC msdb.dbo.sp_add_notification @alert_name=N'Login fails', 
		@operator_name=N'MS-SQL-Admins', 
		@notification_method = 1;
GO
EXEC msdb.dbo.sp_add_alert @name=N'Permission Denied', 
		@message_id=229, 
		@severity=0, 
		@enabled=1, 
		@delay_between_responses=0, 
		@include_event_description_in=0, 
		@category_name=N'[Uncategorized]', 
		@job_id=N'00000000-0000-0000-0000-000000000000'
GO
EXEC msdb.dbo.sp_add_notification @alert_name=N'Permission Denied', 
		@operator_name=N'MS-SQL-Admins', 
		@notification_method = 1;
GO
EXEC msdb.dbo.sp_add_alert @name=N'Server shut down', 
		@message_id=6006, 
		@severity=0, 
		@enabled=1, 
		@delay_between_responses=0, 
		@include_event_description_in=1,
		@database_name=N'', 
		@notification_message=N'Остановлена служба', 
		@event_description_keyword=N'Server shut down', 
		@category_name=N'[Uncategorized]', 
		@job_id=N'00000000-0000-0000-0000-000000000000'
GO
EXEC msdb.dbo.sp_add_notification @alert_name=N'Server shut down', 
		@operator_name=N'MS-SQL-Admins', 
		@notification_method = 1;
GO
EXEC msdb.dbo.sp_add_alert @name=N'Переполнен журнал транзакций', 
		@message_id=9002, 
		@severity=0, 
		@enabled=1, 
		@delay_between_responses=0, 
		@include_event_description_in=5, 
		@notification_message=N' ', 
		@category_name=N'[Uncategorized]', 
		@job_id=N'00000000-0000-0000-0000-000000000000'
GO
EXEC msdb.dbo.sp_add_notification @alert_name=N'Переполнен журнал транзакций', 
		@operator_name=N'MS-SQL-Admins', 
		@notification_method = 1;
GO
EXEC msdb.dbo.sp_add_alert @name=N'Sev. 19 Errors', 
		@message_id=0, 
		@severity=19, 
		@enabled=1, 
		@delay_between_responses=0, 
		@include_event_description_in=1, 
		@notification_message=N' ', 
		@category_name=N'[Uncategorized]', 
		@job_id=N'00000000-0000-0000-0000-000000000000'
GO
EXEC msdb.dbo.sp_add_notification @alert_name=N'Sev. 19 Errors', 
		@operator_name=N'MS-SQL-Admins', 
		@notification_method = 1;
GO
EXEC msdb.dbo.sp_add_alert @name=N'Sev. 20 Errors', 
		@message_id=0, 
		@severity=20, 
		@enabled=1, 
		@delay_between_responses=0, 
		@include_event_description_in=1, 
		@notification_message=N' ', 
		@category_name=N'[Uncategorized]', 
		@job_id=N'00000000-0000-0000-0000-000000000000'
GO
EXEC msdb.dbo.sp_add_notification @alert_name=N'Sev. 20 Errors', 
		@operator_name=N'MS-SQL-Admins', 
		@notification_method = 1;
GO
EXEC msdb.dbo.sp_add_alert @name=N'Sev. 21 Errors', 
		@message_id=0, 
		@severity=21, 
		@enabled=1, 
		@delay_between_responses=0, 
		@include_event_description_in=1, 
		@notification_message=N' ', 
		@category_name=N'[Uncategorized]', 
		@job_id=N'00000000-0000-0000-0000-000000000000'
GO
EXEC msdb.dbo.sp_add_notification @alert_name=N'Sev. 21 Errors', 
		@operator_name=N'MS-SQL-Admins', 
		@notification_method = 1;
GO
EXEC msdb.dbo.sp_add_alert @name=N'Sev. 22 Errors', 
		@message_id=0, 
		@severity=22, 
		@enabled=1, 
		@delay_between_responses=0, 
		@include_event_description_in=1, 
		@notification_message=N' ', 
		@category_name=N'[Uncategorized]', 
		@job_id=N'00000000-0000-0000-0000-000000000000'
GO
EXEC msdb.dbo.sp_add_notification @alert_name=N'Sev. 22 Errors', 
		@operator_name=N'MS-SQL-Admins', 
		@notification_method = 1;
GO
EXEC msdb.dbo.sp_add_alert @name=N'Sev. 23 Errors', 
		@message_id=0, 
		@severity=23, 
		@enabled=1, 
		@delay_between_responses=0, 
		@include_event_description_in=1, 
		@notification_message=N' ', 
		@category_name=N'[Uncategorized]', 
		@job_id=N'00000000-0000-0000-0000-000000000000'
GO
EXEC msdb.dbo.sp_add_notification @alert_name=N'Sev. 23 Errors', 
		@operator_name=N'MS-SQL-Admins', 
		@notification_method = 1;
GO
EXEC msdb.dbo.sp_add_alert @name=N'Sev. 24 Errors', 
		@message_id=0, 
		@severity=24, 
		@enabled=1, 
		@delay_between_responses=0, 
		@include_event_description_in=1, 
		@notification_message=N' ', 
		@category_name=N'[Uncategorized]', 
		@job_id=N'00000000-0000-0000-0000-000000000000'
GO
EXEC msdb.dbo.sp_add_notification @alert_name=N'Sev. 24 Errors', 
		@operator_name=N'MS-SQL-Admins', 
		@notification_method = 1;
GO
EXEC msdb.dbo.sp_add_alert @name=N'Sev. 25 Errors', 
		@message_id=0, 
		@severity=25, 
		@enabled=1, 
		@delay_between_responses=0, 
		@include_event_description_in=1, 
		@notification_message=N' ', 
		@category_name=N'[Uncategorized]', 
		@job_id=N'00000000-0000-0000-0000-000000000000'
GO
EXEC msdb.dbo.sp_add_notification @alert_name=N'Sev. 25 Errors', 
		@operator_name=N'MS-SQL-Admins', 
		@notification_method = 1;
GO
EXEC msdb.dbo.sp_add_alert @name=N'tempdb: full used space', 
		@message_id=0, 
		@severity=0, 
		@enabled=1, 
		@delay_between_responses=60, 
		@include_event_description_in=5, 
		@category_name=N'[Uncategorized]', 
		@performance_condition=N'SQLServer:Databases|Log File(s) Used Size (KB)|tempdb|>|9000000', 
		@job_id=N'00000000-0000-0000-0000-000000000000'
GO
EXEC msdb.dbo.sp_add_notification @alert_name=N'tempdb: full used space', 
		@operator_name=N'MS-SQL-Admins', 
		@notification_method = 1;
GO

USE master
GO

-- Компонент Database Mail
EXECUTE sp_configure 'show advanced options',1
RECONFIGURE
EXECUTE sp_configure 'Database Mail XPs',1
RECONFIGURE
EXEC sp_configure 'default trace enabled', 0
RECONFIGURE
EXECUTE sp_configure 'show advanced options',0
RECONFIGURE
GO
DECLARE @email_address nvarchar(50)
SELECT	@email_address = @@servername + '-MSSQL@domain.ru'
EXECUTE msdb.dbo.sysmail_add_account_sp
    @account_name = 'Administrator',
    @description = 'Mail account for administrative e-mail.',
	@replyto_address = 'MS-SQL-Admins@domain.ru',
    @email_address = @email_address,
    @display_name = @email_address,
    @mailserver_name = 'SMTP.domain.ru',
	@mailserver_type = 'SMTP',
	@port = 25,
	@use_default_credentials = 0;
GO
EXECUTE msdb.dbo.sysmail_add_profile_sp
       @profile_name = 'AlertProfile',
       @description = 'Profile used for administrative mail.' ;
GO
EXECUTE msdb.dbo.sysmail_add_profileaccount_sp
    @profile_name = 'AlertProfile',
    @account_name = 'Administrator',
    @sequence_number = 1 ;
GO
EXECUTE msdb.dbo.sysmail_add_principalprofile_sp
    @principal_name = 'public',
    @profile_name = 'AlertProfile',
    @is_default = 1 ;
GO


USE [msdb]
GO
EXEC msdb.dbo.sp_set_sqlagent_properties @email_save_in_sent_folder=1
GO
EXEC master.dbo.xp_instance_regwrite N'HKEY_LOCAL_MACHINE'
, N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent'
, N'UseDatabaseMail'
, N'REG_DWORD', 1
GO
EXEC master.dbo.xp_instance_regwrite N'HKEY_LOCAL_MACHINE'
, N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent'
, N'DatabaseMailProfile'
, N'REG_SZ'
, N'AlertProfile'
GO

EXECUTE msdb.sys.sp_helprolemember 'DatabaseMailUserRole';
--EXECUTE sp_addrolemember @rolename = 'DatabaseMailUserRole',@membername = '.......';
EXECUTE msdb.dbo.sysmail_help_queue_sp @queue_type = 'Mail';
EXECUTE msdb.dbo.sysmail_help_account_sp;
EXECUTE msdb.dbo.sysmail_help_profile_sp;
EXECUTE msdb.dbo.sysmail_help_profileaccount_sp @profile_name = 'AlertProfile'
EXECUTE msdb.dbo.sysmail_help_principalprofile_sp;
SELECT * FROM msdb.dbo.sysmail_event_log
SELECT * FROM msdb.dbo.sysmail_allitems
SELECT * FROM msdb.dbo.sysmail_faileditems
GO

USE master
GO

CREATE ENDPOINT SBEndpoint
  STATE = STARTED
  AS TCP 
    (
       LISTENER_IP = ALL, 
       LISTENER_PORT = 9669
    )
  FOR SERVICE_BROKER 
    (
       AUTHENTICATION = WINDOWS,
       MESSAGE_FORWARDING = DISABLED
    )
GO
CREATE ENDPOINT MirroringEndpoint
    STATE = STARTED
    AS TCP ( LISTENER_PORT = 7022, LISTENER_IP = ALL )
    FOR DATABASE_MIRRORING (
       AUTHENTICATION = WINDOWS KERBEROS,
       ENCRYPTION = SUPPORTED,
       ROLE=ALL);
GO


-- Открытие нового файла журнала ошибок SQL Server

USE [master]
GO
EXEC xp_instance_regwrite N'HKEY_LOCAL_MACHINE', 
	N'Software\Microsoft\MSSQLServer\MSSQLServer', 
	N'NumErrorLogs', 
	REG_DWORD, 21
GO
USE [msdb]
GO
DECLARE @jobId BINARY(16), @ReturnCode int
EXEC	@ReturnCode =  msdb.dbo.sp_add_job 
		@job_name=N'Открытие нового файла журнала ошибок SQL Server', 
		@enabled=1, 
		@notify_level_eventlog=0, 
		@notify_level_email=0, 
		@notify_level_netsend=0, 
		@notify_level_page=0, 
		@delete_level=0, 
		@description=N'--USE msdb ;
--GO
--EXEC dbo.sp_cycle_agent_errorlog ;
--GO
--EXEC sp_cycle_errorlog ;
--GO', 
		@category_name=N'Database Maintenance', 
		@owner_login_name=N'sa', @job_id = @jobId OUTPUT

EXEC	@ReturnCode = msdb.dbo.sp_add_jobstep @job_id=@jobId, 
		@step_name=N'sp_cycle_errorlog', 
		@step_id=1, 
		@cmdexec_success_code=0, 
		@on_success_action=1, 
		@on_success_step_id=0, 
		@on_fail_action=2, 
		@on_fail_step_id=0, 
		@retry_attempts=0, 
		@retry_interval=0, 
		@os_run_priority=0, @subsystem=N'TSQL', 
		@command=N'EXEC sp_cycle_errorlog', 
		@database_name=N'master', 
		@flags=0
EXEC	@ReturnCode = msdb.dbo.sp_update_job @job_id = @jobId, 
		@start_step_id = 1
EXEC	@ReturnCode = msdb.dbo.sp_add_jobschedule @job_id=@jobId, 
		@name=N'sp_cycle_errorlog', 
		@enabled=1, 
		@freq_type=32, 
		@freq_interval=1, 
		@freq_subday_type=1, 
		@freq_subday_interval=0, 
		@freq_relative_interval=1, 
		@freq_recurrence_factor=1, 
		@active_start_date=20080422, 
		@active_end_date=99991231, 
		@active_start_time=235900, 
		@active_end_time=235959
EXEC	@ReturnCode = msdb.dbo.sp_add_jobserver @job_id = @jobId, 
		@server_name = N'(local)'
GO

--

EXEC master..xp_regwrite 
     @rootkey='HKEY_LOCAL_MACHINE', 
     @key='SOFTWARE\Microsoft\Microsoft SQL Server\MSSQL.1\MSSQLServer', 
     @value_name='BackupDirectory', 
     @type='REG_SZ', 
     @value='D:\MSSQL\BACKUP' -- Тут нужно указать правильный путь к папке, куда решили класть копии


-- Шаблон задания для автоматического создания недостающих индексов

USE [msdb]
GO

IF NOT EXISTS (SELECT name FROM msdb.dbo.syscategories 
WHERE name=N'[Обслуживание индексов]' AND category_class=1)
BEGIN
EXEC	msdb.dbo.sp_add_category @class=N'JOB', 
		@type=N'LOCAL', 
		@name=N'[Обслуживание индексов]'
END

DECLARE @jobId BINARY(16)
EXEC	msdb.dbo.sp_add_job @job_name=N'Создание недостающих индексов', 
		@enabled=0, 
		@notify_level_eventlog=3, 
		@notify_level_email=2, 
		@notify_level_netsend=0, 
		@notify_level_page=0, 
		@delete_level=0, 
		@description=N'No description available.', 
		@category_name=N'[Обслуживание индексов]', 
		@owner_login_name=N'sa', 
		@notify_email_operator_name=N'MS-SQL-Admins', 
		@job_id = @jobId OUTPUT
EXEC	msdb.db