Mindig meglepem saját magam azzal, hogy újra és újra felfedezek egy olyan szolgáltatást/funkciót az SQL Server-ben, amit már használtam és bevállt, de már régóta nem volt rá szükségem. Mostanság a Policy-Based Management funkciót fedeztem fel ismét. Tavaly a DBCC CHECKDB parancsot “házasítottam” össze a PBM-el, most egy nagyon egyszerű dolgot fogok: szabad hely monitorozása egy adatbázisban. Ráadásul szeretnék erről értesítést is kapni, amikor elér egy bizonyos szintet.
Kezdjünk neki: az első dolog, hogy létrehozok egy adatbázist, fix, előre lefoglalt lemezterülettel, ami legyen 5 MB most és nem is engedem tovább növekedni.
USE [master];
GO
IF DATABASEPROPERTY('foo','Version') > 0
DROP DATABASE [foo];
GO
CREATE DATABASE [foo]
ON PRIMARY
(
NAME = 'foo_data',
FILENAME = 'C:\temp\foo_data.mdf',
SIZE = 5120 KB,
MAXSIZE = 5120 KB
)
LOG ON
(
NAME = 'foo_log',
FILENAME = 'C:\temp\foo_log.ldf'
)
GO
EXEC sp_cycle_errorlog;
GO
Következő lépésben, létre fogok hozni egy Condition-t, ami azt fogja vizsgálni, hogy az adott adat file teljes méretéhez képest, hány százaléknyi terület van használatban. Ezt SSMS-ben is meg lehet csinálni így:
- Menjen a Server/Management/Policy Management/Conditions menüpontra, majd jelölje ki.
- Nyomja meg a jobb egérgombot, majd válssza New Condtion menüpontot.
- Adjon meg egy nevet, pl.: PCT FREE SPACE <= 40
- A Facet melletti legördülő menüből válassza ki a Data File elemet.
- Az Expression részen a Field oszlopnál írja be a következőt: Divide(@UsedSpace, @AvailableSpace)
- Az Operator értéke legyen <=
- A Value legyen 0.6
- a végén nyomja meg az Ok gombot.
vagy az alábbi script segítségével is:
Declare @condition_id int
EXEC msdb.dbo.sp_syspolicy_add_condition @name=N'PCT FREE SPACE <= 40', @description=N'', @facet=N'DataFile', @expression=N'<Operator>
<TypeClass>Bool</TypeClass>
<OpType>LE</OpType>
<Count>2</Count>
<Function>
<TypeClass>Numeric</TypeClass>
<FunctionType>Divide</FunctionType>
<ReturnType>Numeric</ReturnType>
<Count>2</Count>
<Attribute>
<TypeClass>Numeric</TypeClass>
<Name>UsedSpace</Name>
</Attribute>
<Attribute>
<TypeClass>Numeric</TypeClass>
<Name>AvailableSpace</Name>
</Attribute>
</Function>
<Constant>
<TypeClass>Numeric</TypeClass>
<ObjType>System.Double</ObjType>
<Value>0.6</Value>
</Constant>
</Operator>', @is_name_condition=0, @obj_name=N'', @condition_id=@condition_id OUTPUT
Select @condition_id
GO
Ha ezzel megvagyunk, akkor jöhet a Policy:
- Menjen a Server/Management/Policy Management/Policies menüpontra, majd jelölje ki.
- Nyomja meg a jobb egérgombot, majd válssza New Policy menüpontot.
- Adjon meg egy nevet, pl.: DB FILE FREE SPACE
- A Check Condition menüpontban válassza ki a fenti Condition-t.
- Az Against targetsmenüpontnál
- jelölje ki, hogy minden File, minden Filegroup esetén legyen ellenőrizve,
- legyen beállítva minden adatbázis, vagy hozzon létre egy Condition-t a megfelelő adatbázisra (lásd képen)
- Az Evaluation Mode menüpontban állítsa be, hogy időzítve – On schedule – legyen az ellenőrzése, majd a Schedule menüpontnál válassza ki/hozzon létre egy ütemezést.
A fentieket természetesen létre lehet hozni script segítségével is.
A lényegi résszel tulajdonképpen meg is vagyunk: van egy PBM elemünk, ami azt fogja vizsgálni, hogy az adatbázsiban a szabad terület 40% vagy attól kevesebb. De ezt csak negyedóránként fogja megtenni: ehhez az SQL Server Agent-tel ütemezett feladat fogja végrehajtani, ami a syspolicy_check_schedule_{schedule_uid} nevet fogja kapni. A schedule_uid egy GUID, ami az msdb adatbázisban a [dbo].[sysschedules] táblában található schedule_uid értéke. Az ütemezett feladat egy PowerShell script-et fog meghívni, amivel ellenőrzi a Policy által meghatározott paramétereket.
Értesítéseket az alábbi módon kaphatunk: hozzunk létre értesítéseket – Alert – a 34052 esemény kódra. Ez akkor van, amikor egy ütemezett Policy ellenőrzés során mért paraméterek nem felelnek meg a leírásban megadottakkal.
Itt tennék egy kis kitérő: négy típusa van a Policy ellenőrzéseknek:
- On Change: prevent: ez azt jelenti, hogy a Policy-ban meghatározott értékeket kell teljesíteni a célobjektumoknak, nem engedi azt megváltoztani. Igen hasznos tud lenni, ha ki akarok kényszeríteni pl. névkonvenciót – a táblák neve mindig kezdődjön tbl_-al egy bizonyos adatbázisban.
- On Change: log only: ebben az esetben “csak” beírja a változást az SQL Server Error log-ba, de nem akadályozza meg, mint az 1. pont esetén.
- On demand: manuális ellenőrzés, vagy PowerShell vagy SSMS segítségével lehet a Policy ellenőrzést elindítani.
- On Schedule: időzített ellenőrzés.
Minden PBM szabálysértés esetén bekerül egy bejegyzés az SQL Server Error Log-ba, az alábbiak szerint:
- Error 34050 On Change: prevent esetén
- Error 34051 On Change: log only esetén
- Error 34052 On Schedule esetén
- Error 34053 On Demand esetén.
Most, hogy minden információnk adott, hozzuk létre az értesítéseket az alábbi kód segítségével:
/*============================================================================
File: PostInstall-SetUpPBMAlerts.sql
Summary: This script sets up alerts for PBM violations
SQL Server Version: 10.50.2500.0 (SQL Server 2008 R2 SP1)
------------------------------------------------------------------------------
Written by Janos Berke, IamBerke.com
For more scripts and sample code, check out http://www.IamBerke.com
THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF
ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED
TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
PARTICULAR PURPOSE.
============================================================================*/
--switch to SQLCMD mode by using ALT + Q + M
:setvar operator "DBA_GROUP"
USE [msdb]
GO
EXEC msdb.dbo.sp_add_alert @name=N'Error_34050',
@message_id=34050,
@severity=0,
@enabled=1,
@delay_between_responses=0,
@include_event_description_in=1,
@job_id=N'00000000-0000-0000-0000-000000000000';
GO
EXEC msdb.dbo.sp_add_notification @alert_name=N'Error_34050', @operator_name=N'$(operator)', @notification_method = 1
GO
EXEC msdb.dbo.sp_add_alert @name=N'Error_34051',
@message_id=34051,
@severity=0,
@enabled=1,
@delay_between_responses=0,
@include_event_description_in=1,
@job_id=N'00000000-0000-0000-0000-000000000000';
GO
EXEC msdb.dbo.sp_add_notification @alert_name=N'Error_34051', @operator_name=N'$(operator)', @notification_method = 1
GO
EXEC msdb.dbo.sp_add_alert @name=N'Error_34052',
@message_id=34052,
@severity=0,
@enabled=1,
@delay_between_responses=0,
@include_event_description_in=1,
@job_id=N'00000000-0000-0000-0000-000000000000';
GO
EXEC msdb.dbo.sp_add_notification @alert_name=N'Error_34052', @operator_name=N'$(operator)', @notification_method = 1
GO
EXEC msdb.dbo.sp_add_alert @name=N'Error_34053',
@message_id=34053,
@severity=0,
@enabled=1,
@delay_between_responses=0,
@include_event_description_in=1,
@job_id=N'00000000-0000-0000-0000-000000000000';
GO
EXEC msdb.dbo.sp_add_notification @alert_name=N'Error_34053', @operator_name=N'$(operator)', @notification_method = 1
GO
Ha ezekkel megvagyunk, térjünk vissza a foo nevü adatbázishoz. Először is hozzunk létre egy teszt táblát:
USE [foo];
GO
CREATE TABLE Table1
(
Col1 char(8000) DEFAULT('a')
)
GO
Majd nézzük meg, hogy mekkora helyet foglal az adatbázisunk:
USE [foo];
GO
SELECT
SUM(used_pages) * 8 AS [space_usage_kb]
FROM
sys.allocation_units A
JOIN
sys.partitions P ON (A.[type] = 2 AND P.[partition_id] = A.[container_id]) OR (A.[type] IN (1,3) AND P.[hobt_id] = A.[container_id])
GO
Itt nekem 1128KB-ot mutat. Ennek alapján könnyű kiszámolni, hogy akkor fog értesítést küldeni a fenti kód, ha elérjük a 3072KB-ot, amihez 1944KB hiányzik. A tábla adattípusa alapján 243 sor létrehozása elegendő lesz, de biztosra megyek és 245 sort adok hozzá:
INSERT INTO Table1 DEFAULT VALUES;
GO 245
Majd ismét lekérdezem az adatbázis méretét, mely során 3096KB-ot kapok. Ez már magasabb érték annál, mint amit engedni szeretnék. Ha időközben nem futott volna le az időzített PBM ellenőrzés, indítsuk el manuálisan: jobb gomb a Policy-n majd kattintson az Evaluate menüpontra.
Ezek után, ha a Database Mail be van állítva, már küldi is az email értesítőt, illetve az alábbi kód segítségével az SQL Server Error Log-ból is ki lehet olvasni:
EXEC sp_readerrorlog 0,1,'Policy';
EXEC sp_readerrorlog 0,1,'34052';
Az alábbi két file tartalmazza a demó kódot és az exportált Policy definiciót: