В прошлой статье об инструменте для мониторинга Foglight for Databases мы рассказывали о возможностях контроля из единого интерфейса SQL Server, Oracle, PostgreSQL, MySQL, SAP ASE, DB2, Cassandra и MongoDB. Сегодня разберём подходы к быстрому выявлению причин нештатной работы Microsoft SQL Server:

  • Поиск источника блокировки;
  • Сравнение настроек БД «было-стало» с привязкой к метрикам производительности;
  • Поиск изменений в структуре БД, из-за которых снизилась производительность.

Подробности под катом.

Foglight for Databases — инструмент мониторинга за производительностью и изменениями в популярных базах данных. Если вы не знакомы с этим продуктом — рекомендуем прочитать предыдущую статью. А ниже мы привели скриншоты из интерфейса для демонстрации возможностей Foglight и простоты поиска проблем в БД.

Поиск источника блокировки


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

image

Дежурный администратор, который уже получил уведомление, переходит в представление SQL PI (Performance Investigator). В столбце Workload заметно красное поле, которое означает ненулевое значение параметра Lock Wait.

image

После клика по графику Workload открывается детальное представление источников нагрузки на БД, а в столбце слева меню для проведения многомерного анализа производительности. Здесь, как и на скриншоте выше видно, что блокировка вызывает большую утилизацию ресурсов. В меню слева есть специальное представление Locked Objects, в котором и обнаружится заблокированный объект.

image

В Locked Objects хранятся заблокированные объекты. В правой части экрана причины блокировок: длительность, с какого сервера (или рабочей станции), какой программой, от какого пользователя и исполняемый объект, который привёл к блокировке.

image

При переходе на исполняемый объект, откроется новое представление с возможностью просмотра содержимого этого объекта. И после нажатия на View Batch Text откроется исполненный код.

image

Ускорение времени диагностики — залог успешной работы команды ИТ.

Сравнение настроек БД «было-стало»


К драматическому снижению производительности могут также приводить изменения, произведенные разработчиками или администраторами БД. Но в момент проблемы неважно кто это сделал — важно что произошло. С этим и попробуем разобраться. Открываем контекстное меню проблемного экземпляра БД.

image

В открывшемся меню нужно перейти на SQL PI (Performance Investigator), чтобы открыть представление с многомерным анализом.

image

Перейдём на представление Baseline для оценки поведения метрики в сравнении с её обычными значениями.

image

На графике видно, что после 13:40 начался аномальный рост потребления ресурсов.

image

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

image

После выбора объектов для сравнения появится заветная кнопка Compare.

image

На среднем представлении видно, что аномальные значения наблюдались по метрикам: Active Time, Executions и Logins Rate. Начнём новое сравнение для выявления изменений.

image

Сравним значения метрик с самими собой, но день назад.

image

После выбора настроек, появится кнопка Compare, на которую нужно нажать.

image

Появится представление, на котором есть измерения для сравнения. Для демонстрации мы выберем пункт меню Programs. В разделе Statistics уже виден двукратный рост значения метрики Executions.

image

Слева и справа от шкалы в разделе меню Programs отображаются значения метрик. Здесь видим, что Active Time и Executions выросли почти в два раза, а это повод для проведения детального разбора ситуации.

image

Таким же образом можно проводить сравнительный анализ и по другим метрикам, а любое представление выгрузить в PDF-отчёт.

Поиск изменений в структуре БД


Изменения индексов, execution plans и других объектов может носить недокументированный характер. Разработчик или администратор БД вносит, казалось бы, незначительные изменения, о которых через некоторое время может забыть. В интерфейсе Foglight for Databases изменения конфигурации привязываются к изменениям производительности. Для выявления изменений переходим с главного экрана мониторинга БД на представление Workload.

image

Допустим, нам известно, что с какой-то клиентской машины генерируется большая нагрузка на БД. Раскрываем в представлении слева Client Machines.

image

Batches отсортированы в соответствии с создаваемой нагрузкой на БД. Перейдём на первый объект в списке и далее посмотрим изменения по нему (Change Tracking).

image

На графике, согласно легенде справа, отмечены соответствующие изменения за выбранный период. Первое изменение здесь — удаление индекса, второе — добавление нового execution plan. Как видно, после удаления индекса резко возросла нагрузка Other Wait — фиолетовая зона (к ней также относится выполнения batch job). Четвертое изменение — увеличение значения уровня параллелизма, что потенциально привело к повышение количества запросов (IO Wait — голубая зона). Рассмотрим последствия добавления нового execution Plan.

image

После перехода открылись детали нового execution plan. Теперь сравним произошедшие изменения.

image

После перехода открылись детали нового execution plan.

image

Этот же execution plan можно открыть в Management Studio прямо из интерфейса Quest Foglight.

image

Так он выглядит в консоли Management Studio.

image

При переходе на представление History можно увидеть изменения метрик во времени.

image

Представление History можно использовать для оценки влияния изменений на ту или иную метрику. Далее переходим на представление Other.

image

На этом представлении видно какие batches повлияли на нагрузку БД. Они уже отсортированы в порядке убывания.

image

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

Если вам понравился Foglight for Databases и вы хотели бы его попробовать на своих БД — оставьте заявку на получение дистрибутивов и триального ключа в форме обратной связи на нашем сайте. Стабильной работы баз данных и быстрой локализации нештатной работы!

Комментарии (2)


  1. LaRN
    27.08.2019 08:34

    Требуются ли права sa для работы утилиты, ну или иначе: какие нужны права для работы этой утилиты?


    1. GalsSoftware Автор
      27.08.2019 10:53

      Права sa нужны только для создания специального пользователя для мониторинга и его объектов. Под спойлером скрипт. Однако, если используется технология mirroring, без прав dba не обойтись.

      Скрипт создания пользователя foglight для SQL Server
      use master;
      Declare	@LoginName				NVARCHAR(256) ,
      		@DBName					NVARCHAR(256) ,
      		@GrantSSISPermissions   bit,
      		@SQLStatement			NVARCHAR(4000);
      
      Select	@LoginName = ?, 			--	Please type the login name to be used for logging-in to SQL Server by the cartridge.
      		@GrantSSISPermissions = ?;  --  The input value for @GrantSSISPermissions should be 0 or 1. (1 - means that user has the SSIS permissions and 0 - means that user doesn't have the SSIS permissions.)
      
      If ( REPLACE ( CONVERT ( VARCHAR(2) , ServerProperty ( 'ProductVersion' ) ) , '.' , '' ) < 9 )
      Begin
      		--	Adding the sysadmin permissions
      
      		If Not Exists (	Select	*
      						From	[master].dbo.spt_values As spv, [master].dbo.sysxlogins As lgn
      						Where	spv.name = 'sysadmin'
      						And		lgn.[name] = @LoginName
      						And		spv.low = 0
      						And		spv.[type] = 'SRV'
      						And		lgn.srvid Is Null
      						And		spv.number & lgn.xstatus = spv.number )
      		Begin
      				Execute	[master].dbo.sp_addsrvrolemember	@LoginName , N'sysadmin';
      		End
      End
      Else
      Begin
      		If Not Exists	(	Select	*
      							From	sys.server_principals As A INNER JOIN sys.server_role_members As B
      									ON		A.principal_id = B.member_principal_id
      									INNER JOIN sys.server_principals As C
      									ON		B.role_principal_id = C.principal_id
      							Where	A.[name] = @LoginName
      							And		C.[name] = N'sysadmin' )
      		Begin
      				--	Granting Server permissions
      				use master;
      				If Not Exists (	Select	*
      								From	sys.server_principals As A INNER JOIN sys.server_permissions As B
      										ON		A.principal_id = B.grantee_principal_id
      								Where	A.[type] In ( 'S' , 'U' , 'G' , 'C' , 'K' )
      								And		A.[name] = @LoginName
      								And		B.permission_name = N'VIEW ANY DEFINITION'
      								And		B.[state] In ( 'G' , 'W' ) )
      				Begin
      						Select	@SQLStatement = N'GRANT VIEW ANY DEFINITION TO [' + @LoginName + N'];';
      						--print @SQLStatement;
      						Execute	( @SQLStatement );
      				End
      
      				If Not Exists (	Select	*
      								From	sys.server_principals As A INNER JOIN sys.server_permissions As B
      										ON		A.principal_id = B.grantee_principal_id
      								Where	A.[type] In ( 'S' , 'U' , 'G' , 'C' , 'K' )
      								And		A.[name] = @LoginName
      								And		B.permission_name = N'VIEW SERVER STATE'
      								And		B.[state] In ( 'G' , 'W' ) )
      				Begin
      						Select	@SQLStatement = N'GRANT VIEW SERVER STATE TO [' + @LoginName + N'];';
      						--print @SQLStatement;
      						Execute	( @SQLStatement );
      				End
      
      				--	Creating the user in each DB
      
      				Select	@DBName = N'';
      
      				While Exists (	Select	*
      								From	[master].sys.databases
      								Where	[name] > @DBName
      								And		HAS_DBACCESS ( [name] ) = 1
      								And		[state] = 0
      								And		is_read_only = 0 )
      				Begin
      						Select	@DBName = MIN ( [name] )
      						From	[master].sys.databases
      						Where	[name] > @DBName
      						And		HAS_DBACCESS ( [name] ) = 1
      						And		[state] = 0
      						And		is_read_only = 0;
      
      						Select	@SQLStatement = N'USE	[' + @DBName + N']
      												  If Not Exists (	Select	*
      																	From	[master].sys.server_principals As A INNER JOIN sys.database_principals As B
      																			ON		A.[sid] = B.[sid]
      																	Where	A.[name] = N''' + @LoginName + N''' )
      												  Begin try
      														CREATE USER [' + @LoginName + N'];
      												  End try
      												  begin catch
      												  end catch';
      
      												  --print @SQLStatement;
      
      						Execute	( @SQLStatement );
      				End
      
      				--	Granting EXECUTE Permissions on master
      				If Not Exists (	Select	*
      								From	[master].sys.server_principals As A INNER JOIN [master].sys.database_principals As B
      										ON		A.[sid] = B.[sid]
      										INNER JOIN [master].sys.database_permissions As C
      										ON		B.[principal_id] = C.[grantee_principal_id]
      										INNER JOIN [master].sys.all_objects As D
      										ON		C.[major_id] = D.[object_id]
      								Where	A.[name] = @LoginName
      								And		D.[name] = N'xp_enumerrorlogs'
      								And		C.[type] = 'EX'
      								And		C.[state] In ( 'G' , 'W' ) )
      				Begin
      						Select	@SQLStatement = N'USE	[master]
      												GRANT EXECUTE ON [master].dbo.xp_enumerrorlogs TO [' + @LoginName + N'];';
      						--print @SQLStatement;
      						Execute	( @SQLStatement );
      				End
      
      				If Not Exists (	Select	*
      								From	[master].sys.server_principals As A INNER JOIN [master].sys.database_principals As B
      										ON		A.[sid] = B.[sid]
      										INNER JOIN [master].sys.database_permissions As C
      										ON		B.[principal_id] = C.[grantee_principal_id]
      										INNER JOIN [master].sys.all_objects As D
      										ON		C.[major_id] = D.[object_id]
      								Where	A.[name] = @LoginName
      								And		D.[name] = N'xp_readerrorlog'
      								And		C.[type] = 'EX'
      								And		C.[state] In ( 'G' , 'W' ) )
      				Begin
      						Select	@SQLStatement = N'USE	[master]
      												GRANT EXECUTE ON [master].dbo.xp_readerrorlog TO [' + @LoginName + N'];';
      						--print @SQLStatement;
      						Execute	( @SQLStatement );
      				End
      
               --	Granting EXECUTE Permissions on msdb
      
                If Not Exists (	Select	*
                        From	[master].sys.server_principals As A INNER JOIN msdb.sys.database_principals As B
                            ON		A.[sid] = B.[sid]
                            INNER JOIN msdb.sys.database_permissions As C
                            ON		B.[principal_id] = C.[grantee_principal_id]
                            INNER JOIN msdb.sys.all_objects As D
                            ON		C.[major_id] = D.[object_id]
                        Where	A.[name] = @LoginName
                        And		D.[name] = N'agent_datetime'
                        And		C.[type] = 'EX'
                        And		C.[state] In ( 'G' , 'W' ) )
                Begin
                    Select	@SQLStatement = N'USE	[msdb]
                                GRANT EXECUTE ON msdb.dbo.agent_datetime TO [' + @LoginName + N'];';
      
                    Execute	( @SQLStatement );
                End
      
      				--	Granting SELECT Permissions on msdb
      
      				If Not Exists (	Select	*
      								From	[master].sys.server_principals As A INNER JOIN msdb.sys.database_principals As B
      										ON		A.[sid] = B.[sid]
      										INNER JOIN msdb.sys.database_permissions As C
      										ON		B.[principal_id] = C.[grantee_principal_id]
      										INNER JOIN msdb.sys.all_objects As D
      										ON		C.[major_id] = D.[object_id]
      								Where	A.[name] = @LoginName
      								And		D.[name] = N'log_shipping_monitor_primary'
      								And		C.[type] = 'SL'
      								And		C.[state] In ( 'G' , 'W' ) )
      				Begin
      						Select	@SQLStatement = N'USE	[msdb]
      												GRANT SELECT ON msdb.dbo.log_shipping_monitor_primary TO [' + @LoginName + N'];';
      						--print @SQLStatement;
      						Execute	( @SQLStatement );
      				End
      
      				If Not Exists (	Select	*
      								From	[master].sys.server_principals As A INNER JOIN msdb.sys.database_principals As B
      										ON		A.[sid] = B.[sid]
      										INNER JOIN msdb.sys.database_permissions As C
      										ON		B.[principal_id] = C.[grantee_principal_id]
      										INNER JOIN msdb.sys.all_objects As D
      										ON		C.[major_id] = D.[object_id]
      								Where	A.[name] = @LoginName
      								And		D.[name] = N'log_shipping_monitor_secondary'
      								And		C.[type] = 'SL'
      								And		C.[state] In ( 'G' , 'W' ) )
      				Begin
      						Select	@SQLStatement = N'USE	[msdb]
      												GRANT SELECT ON msdb.dbo.log_shipping_monitor_secondary TO [' + @LoginName + N'];';
      						--print @SQLStatement;
      						Execute	( @SQLStatement );
      				End
      	
      				If Not Exists (	Select	*
      								From	[master].sys.server_principals As A INNER JOIN msdb.sys.database_principals As B
      										ON		A.[sid] = B.[sid]
      										INNER JOIN msdb.sys.database_permissions As C
      										ON		B.[principal_id] = C.[grantee_principal_id]
      										INNER JOIN msdb.sys.all_objects As D
      										ON		C.[major_id] = D.[object_id]
      								Where	A.[name] = @LoginName
      								And		D.[name] = N'log_shipping_primaries'
      								And		C.[type] = 'SL'
      								And		C.[state] In ( 'G' , 'W' ) )
      				Begin
      						Select	@SQLStatement = N'USE	[msdb]
      												GRANT SELECT ON msdb.dbo.log_shipping_primaries TO [' + @LoginName + N'];';
      						--print @SQLStatement;
      						Execute	( @SQLStatement );
      				End
      
      				If Not Exists (	Select	*
      								From	[master].sys.server_principals As A INNER JOIN msdb.sys.database_principals As B
      										ON		A.[sid] = B.[sid]
      										INNER JOIN msdb.sys.database_permissions As C
      										ON		B.[principal_id] = C.[grantee_principal_id]
      										INNER JOIN msdb.sys.all_objects As D
      										ON		C.[major_id] = D.[object_id]
      								Where	A.[name] = @LoginName
      								And		D.[name] = N'log_shipping_secondaries'
      								And		C.[type] = 'SL'
      								And		C.[state] In ( 'G' , 'W' ) )
      				Begin
      						Select	@SQLStatement = N'USE	[msdb]
      												GRANT SELECT ON msdb.dbo.log_shipping_secondaries TO [' + @LoginName + N'];';
      						--print @SQLStatement;
      						Execute	( @SQLStatement );
      				End
      
      				If Not Exists (	Select	*
      								From	[master].sys.server_principals As A INNER JOIN msdb.sys.database_principals As B
      										ON		A.[sid] = B.[sid]
      										INNER JOIN msdb.sys.database_permissions As C
      										ON		B.[principal_id] = C.[grantee_principal_id]
      										INNER JOIN msdb.sys.all_objects As D
      										ON		C.[major_id] = D.[object_id]
      								Where	A.[name] = @LoginName
      								And		D.[name] = N'log_shipping_primary_secondaries'
      								And		C.[type] = 'SL'
      								And		C.[state] In ( 'G' , 'W' ) )
      				Begin
      						Select	@SQLStatement = N'USE	[msdb]
      												GRANT SELECT ON msdb.dbo.log_shipping_primary_secondaries TO [' + @LoginName + N'];';
      						--print @SQLStatement;
      						Execute	( @SQLStatement );
      				End
      				If Not Exists (	Select	*
      								From	[master].sys.server_principals As A INNER JOIN msdb.sys.database_principals As B
      										ON		A.[sid] = B.[sid]
      										INNER JOIN msdb.sys.database_permissions As C
      										ON		B.[principal_id] = C.[grantee_principal_id]
      										INNER JOIN msdb.sys.all_objects As D
      										ON		C.[major_id] = D.[object_id]
      								Where	A.[name] = @LoginName
      								And		D.[name] = N'sysalerts'
      								And		C.[type] = 'SL'
      								And		C.[state] In ( 'G' , 'W' ) )
      				Begin
      						Select	@SQLStatement = N'USE	[msdb]
      												GRANT SELECT ON msdb.dbo.sysalerts TO [' + @LoginName + N'];';
      						--print @SQLStatement;
      						Execute	( @SQLStatement );
      				End
      	
      				If Not Exists (	Select	*
      								From	[master].sys.server_principals As A INNER JOIN msdb.sys.database_principals As B
      										ON		A.[sid] = B.[sid]
      										INNER JOIN msdb.sys.database_permissions As C
      										ON		B.[principal_id] = C.[grantee_principal_id]
      										INNER JOIN msdb.sys.all_objects As D
      										ON		C.[major_id] = D.[object_id]
      								Where	A.[name] = @LoginName
      								And		D.[name] = N'syscategories'
      								And		C.[type] = 'SL'
      								And		C.[state] In ( 'G' , 'W' ) )
      				Begin
      						Select	@SQLStatement = N'USE	[msdb]
      												GRANT SELECT ON msdb.dbo.syscategories TO [' + @LoginName + N'];';
      						
      						--print @SQLStatement;
      						Execute	( @SQLStatement );
      				End
      
      				If Not Exists (	Select	*
      								From	[master].sys.server_principals As A INNER JOIN msdb.sys.database_principals As B
      										ON		A.[sid] = B.[sid]
      										INNER JOIN msdb.sys.database_permissions As C
      										ON		B.[principal_id] = C.[grantee_principal_id]
      										INNER JOIN msdb.sys.all_objects As D
      										ON		C.[major_id] = D.[object_id]
      								Where	A.[name] = @LoginName
      								And		D.[name] = N'sysjobactivity'
      								And		C.[type] = 'SL'
      								And		C.[state] In ( 'G' , 'W' ) )
      				Begin
      						Select	@SQLStatement = N'USE	[msdb]
      												GRANT SELECT ON msdb.dbo.sysjobactivity TO [' + @LoginName + N'];';
      						
      						--print @SQLStatement;
      						Execute	( @SQLStatement );
      				End
      	
      				If Not Exists (	Select	*
      								From	[master].sys.server_principals As A INNER JOIN msdb.sys.database_principals As B
      										ON		A.[sid] = B.[sid]
      										INNER JOIN msdb.sys.database_permissions As C
      										ON		B.[principal_id] = C.[grantee_principal_id]
      										INNER JOIN msdb.sys.all_objects As D
      										ON		C.[major_id] = D.[object_id]
      								Where	A.[name] = @LoginName
      								And		D.[name] = N'sysjobs'
      								And		C.[type] = 'SL'
      								And		C.[state] In ( 'G' , 'W' ) )
      				Begin
      						Select	@SQLStatement = N'USE	[msdb]
      												GRANT SELECT ON msdb.dbo.sysjobs TO [' + @LoginName + N'];';
      
      						--print @SQLStatement;
      						Execute	( @SQLStatement );
      				End
      
      				If Not Exists (	Select	*
      								From	[master].sys.server_principals As A INNER JOIN msdb.sys.database_principals As B
      										ON		A.[sid] = B.[sid]
      										INNER JOIN msdb.sys.database_permissions As C
      										ON		B.[principal_id] = C.[grantee_principal_id]
      										INNER JOIN msdb.sys.all_objects As D
      										ON		C.[major_id] = D.[object_id]
      								Where	A.[name] = @LoginName
      								And		D.[name] = N'sysjobhistory'
      								And		C.[type] = 'SL'
      								And		C.[state] In ( 'G' , 'W' ) )
      				Begin
      						Select	@SQLStatement = N'USE	[msdb]
      												GRANT SELECT ON msdb.dbo.sysjobhistory TO [' + @LoginName + N'];';
      						
      						--print @SQLStatement;
      						Execute	( @SQLStatement );
      				End
      
      
      				If ( Not Exists (	Select	*
      									From	[master].sys.server_principals As A INNER JOIN msdb.sys.database_principals As B
      											ON		A.[sid] = B.[sid]
      											INNER JOIN msdb.sys.database_permissions As C
      											ON		B.[principal_id] = C.[grantee_principal_id]
      											INNER JOIN msdb.sys.all_objects As D
      											ON		C.[major_id] = D.[object_id]
      									Where	A.[name] = @LoginName
      									And		D.[name] = N'dbm_monitor_data'
      									And		C.[type] = 'SL'
      									And		C.[state] In ( 'G' , 'W' ) )
      					And Exists (	Select	*
      									From	msdb.sys.all_objects
      									Where	[name] = N'dbm_monitor_data' )
      					And		REPLACE ( CONVERT ( VARCHAR(2) , ServerProperty ( 'ProductVersion' ) ) , '.' , '' ) = 9 )
      				Begin
      						Select	@SQLStatement = N'USE	[msdb]
      												GRANT SELECT ON msdb.dbo.dbm_monitor_data TO [' + @LoginName + N'];';
      						
      						--print @SQLStatement;
      						Execute	( @SQLStatement );
      				End
      
      				--	Adding the db_datareader permissions
      
      				Select	@DBName = N'';
      
      				While Exists (	Select	*
      								From	[master].sys.databases
      								Where	[name] > @DBName
      								And		HAS_DBACCESS ( [name] ) = 1
      								And		[state] = 0
      								And		is_read_only = 0 )
      				Begin
      						Select	@DBName = MIN ( [name] )
      						From	[master].sys.databases
      						Where	[name] > @DBName
      						And		HAS_DBACCESS ( [name] ) = 1
      						And		[state] = 0
      						And		is_read_only = 0;
      
      						Select	@SQLStatement = N'USE	[' + @DBName + N']
      												If Not Exists (	Select	*
      																From	[master].sys.server_principals As A INNER JOIN sys.database_principals As B
      																		ON		A.[sid] = B.[sid]
      																		INNER JOIN sys.database_role_members As C
      																		ON		B.principal_id = C.member_principal_id
      																		INNER JOIN sys.database_principals As D
      																		ON		C.role_principal_id = D.principal_id
      																Where	A.[name] = N''' + @LoginName + N'''
      																And		D.[name] = N''db_datareader'' )
      												Begin
      														Execute	sp_addrolemember N''db_datareader'' , N''' + @LoginName + N''';
      												End';
      
      						--print @SQLStatement;
      						Execute	( @SQLStatement );
      				End
      			
      
      				--	Adding the replmonitor permissions on all distribution databases
      				Select	@DBName = N'';
      				While (	Exists (	Select	name
      									From	[master].sys.databases
      									Where	[name] > @DBName 
      									And		is_distributor = 1 
      									and has_dbaccess(name) = 1))
      				Begin
      
      						Select	@DBName = MIN ( [name] )
      						From	[master].sys.databases
      						Where	[name] > @DBName 
      						And		is_distributor = 1 
      						And		has_dbaccess(name) = 1;
      
      						Select	@SQLStatement = N'USE	[' + @DBName + N']
      												Begin
      														Execute	sp_addrolemember N''replmonitor'' , N''' + @LoginName + N''';
      											End';
      						--print @SQLStatement;
      						Execute	( @SQLStatement );												
      						
      				End
      								
      				--	Adding the db_ddladmin permissions
      
      				Select	@DBName = N'';
      
      				While Exists (	Select	*
      								From	[master].sys.databases
      								Where	[name] > @DBName
      								And		HAS_DBACCESS ( [name] ) = 1
      								And		[state] = 0
      								And		is_read_only = 0 )
      				Begin
      						Select	@DBName = MIN ( [name] )
      						From	[master].sys.databases
      						Where	[name] > @DBName
      						And		HAS_DBACCESS ( [name] ) = 1
      						And		[state] = 0
      						And		is_read_only = 0;
      
      						Select	@SQLStatement = N'USE	[' + @DBName + N']
      												If Not Exists (	Select	*
      																From	[master].sys.server_principals As A INNER JOIN sys.database_principals As B
      																		ON		A.[sid] = B.[sid]
      																		INNER JOIN sys.database_role_members As C
      																		ON		B.principal_id = C.member_principal_id
      																		INNER JOIN sys.database_principals As D
      																		ON		C.role_principal_id = D.principal_id
      																Where	A.[name] = N''' + @LoginName + N'''
      																And		D.[name] = N''db_ddladmin'' )
      												Begin
      														Execute	sp_addrolemember N''db_ddladmin'' , N''' + @LoginName + N''';
      												End';
      						--print @SQLStatement;
      						Execute	( @SQLStatement );
      				End
      
      				--	Granting trace permissions
      
      				If Not Exists (	Select	*
      								From	sys.server_principals As A INNER JOIN sys.server_permissions As B
      										ON		A.principal_id = B.grantee_principal_id
      								Where	A.[type] In ( 'S' , 'U' , 'G' , 'C' , 'K' )
      								And		A.[name] = @LoginName
      								And		B.permission_name = N'ALTER TRACE'
      								And		B.[state] In ( 'G' , 'W' ) )
      				Begin
      						Select	@SQLStatement = N'use master;GRANT ALTER TRACE TO [' + @LoginName + N'];';
      						--print @SQLStatement;
      						Execute	( @SQLStatement );
      				End
      		End
      End
      
      --Role needed to inspect mirroring
      
      if (select count(*) from msdb.sys.database_principals where name='dbm_monitor') = 1
      begin
      	if (select count(*) from msdb.sys.database_principals where name=@LoginName) = 0
      	begin
      		set @SQLStatement=N'USE [msdb]
      							If Not Exists (	Select	*
      											From	[master].sys.server_principals As A INNER JOIN sys.database_principals As B
      													ON		A.[sid] = B.[sid]
      											Where	A.[name] = N''' + @LoginName + N''' )
      							Begin try
      								CREATE USER [' + @LoginName + N'];
      							End try
      							begin catch
      							end catch';
      	--print @SQLStatement;
      	exec (@SQLStatement);
      	end
      	if (select count(*) from msdb.sys.database_principals where name=@LoginName) = 1
      	begin 
      		If ( REPLACE ( CONVERT ( VARCHAR(2) , ServerProperty ( 'ProductVersion' ) ) , '.' , '' ) < 11 )
      			exec msdb..sp_addrolemember 'dbm_monitor', @LoginName
      		else
      		set @SQLStatement=N'USE [msdb]
      					ALTER ROLE [dbm_monitor] ADD MEMBER ['+@LoginName+N']';
      		 --print @SQLStatement;
      	exec (@SQLStatement);
      	end
      end
      
      if (select count(*) from sys.databases where name='SSISDB') = 1 and @GrantSSISPermissions = 1
      Begin
      		If Not Exists	(	Select	*
      							From	sys.server_principals As A INNER JOIN sys.server_role_members As B
      									ON		A.principal_id = B.member_principal_id
      									INNER JOIN sys.server_principals As C
      									ON		B.role_principal_id = C.principal_id
      							Where	A.[name] = @LoginName
      							And		C.[name] = N'sysadmin' )
      		Begin
      			--Granting SSIS permissions
      
      		
      			set @SQLStatement=N'USE [SSISDB]
      														  If Not Exists (	Select	*
      																		From	[master].sys.server_principals As A INNER JOIN sys.database_principals As B
      																				ON		A.[sid] = B.[sid]
      																		Where	A.[name] = N''' + @LoginName + N''' )
      													  Begin try
      															CREATE USER [' + @LoginName + N'];
      													  End try begin catch end catch;
      													  Begin try
      													  ALTER ROLE  [ssis_admin] ADD MEMBER [' + @LoginName + N'];
      													  End try begin catch end catch;
      						';
      						--print @SQLStatement;
      						exec (@SQLStatement);
               End
      
      End