Les instances SQL Server hébergent des bases de données contenant les données de la pile principale d'un modèle commercial ou des données de configuration pour des applications particulières. Quel que soit le cas d'utilisation, une instance possède un ensemble de valeurs/paramètres qui doivent être réglés pour suivre les meilleures pratiques.
Le but de la procédure stockée que je présente dans cet article est de présenter au DBA un ensemble de paramètres/valeurs importants à ne pas négliger. De plus, je partagerai une fonctionnalité intéressante qui aide les DBA à garder le contrôle de tout paramètre/valeur particulier qui a été récemment changé/modifié.
Considérations initiales
Assurez-vous que le compte que vous utiliserez pour exécuter cette procédure stockée dispose de suffisamment de privilèges. Je sais que demander un utilisateur avec le privilège sysadmin semble beaucoup trop, mais c'est le moyen le plus simple de le faire fonctionner correctement, car le SP utilise xp_cmdshell et d'autres procédures système spéciales stockées pour faire le travail. Ou, vous pouvez ajuster les droits de l'utilisateur pour adhérer au principe du moindre privilège.
Comment utiliser la procédure stockée SQL ?
- Copiez et collez le code SP TSQL fourni dans cet article.
- Le SP attend 1 paramètre uniquement :@ storeValuesInTable
Oui est si le DBA souhaite enregistrer la sortie dans une table cible, et N est si le DBA ne veut voir que la sortie directement.
Champs présentés et leurs significations
- version_sql – la version actuelle de SQL Server de l'instance.
- sql_edition – l'édition SQL Server actuelle de l'instance.
- build_number – le numéro de build actuel de l'instance.
- min_server_memory – la valeur actuelle (en Mo) attribuée à la mémoire minimale du serveur.
- max_server_memory – la valeur actuelle (en Mo) attribuée à la mémoire maximale du serveur.
- server_memory – la valeur actuelle (en Mo) dont dispose le serveur hébergeant l'instance SQL Server.
- server_cores – la quantité de cœurs vCPU dont dispose le serveur hébergeant l'instance SQL Server.
- sql_cores – la quantité de cœurs vCPU que l'instance SQL Server a attribuée pour son utilisation.
- cost_threshold_for_parallelism – la valeur actuelle attribuée au paramètre Seuil de coût pour le parallélisme.
- max_degree_of_parallelism – la valeur actuelle attribuée au paramètre Degré maximal de parallélisme.
- lpim_enabled – 0 si Verrouiller les pages en mémoire paramètre est désactivé et 1 s'il est activé.
- ifi_enabled – 0 si initialisation instantanée du fichier est désactivé et 1 si activé.
- installed_date – la date et l'heure d'installation de l'instance SQL Server.
- sql_service_account – le compte de service qui exécutera le service DB Engine.
- sql_agent_service_account – le compte de service qui exécutera le service Agent.
- startup_time – valeur de date et d'heure lorsque l'instance SQL Server a récemment démarré.
- data_collection_timestamp – visible uniquement si Y est transmis au SP. Il est utilisé pour définir quand le SP a été exécuté et a enregistré avec succès les informations dans les InstanceValues tableau.
Tests d'exécution de la procédure stockée en SQL
Je vais vous montrer quelques exécutions de la procédure stockée afin que vous ayez une idée de ce que vous pouvez en attendre.
EXEC DBA_InstanceValues @storeValuesInTable = 'N'
EXEC DBA_InstanceValues @storeValuesInTable = 'Y'
Pour cette exécution particulière, la sortie sera enregistrée dans une table appelée InstanceValues . Il sera créé dans la base de données cible s'il n'existe pas.
La table a presque la même structure que sur la capture d'écran ci-dessus, avec une petite différence :elle inclut un champ appelé data_collection_timestamp tout au bout du tableau.
Le data_collection_timestamp champ est utile à plusieurs fins :
- pour vous dire quand le SP a été exécuté pour collecter les données sauvegardées (assez évident).
- Pour rechercher les différences dans une plage de temps particulière pour un champ de paramètre particulier.
Pour prouver que c'est utile, permettez-moi de vous présenter un exemple rapide.
J'ai exécuté le SP une fois, en passant le Y paramètre. L'enregistrement respectif a été inséré dans les InstanceValues table. Ensuite, je change cost_threshold_for_parallelism valeur dans mon instance à 50 , puis exécutez à nouveau le script.
Comme vous pouvez le voir, la modification a été enregistrée avec succès dans les InstanceValues table. Maintenant, comment cela peut-il être utile ?
Si vous créez un travail d'agent qui exécute quotidiennement cette procédure stockée, vous pouvez créer un mécanisme d'audit interne pour garder une trace du moment où une valeur de réglage particulière est modifiée, comme je l'ai démontré. Ainsi, vous pouvez garder un contrôle total sur votre instance SQL Server. Si vous me demandez, c'est quelque chose d'extrêmement utile.
Le code complet de la procédure stockée
Au tout début du script, vous verrez la valeur par défaut. La procédure stockée l'assume si aucune valeur n'est transmise au paramètre.
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author : Alejandro Cobar
-- Create date: 2021-05-15
-- Description: SP to retrieve important instance settings/values
-- =============================================
CREATE PROCEDURE [dbo].[DBA_InstanceValues]
@storeValuesInTable CHAR(1) = 'N'
AS
BEGIN
SET NOCOUNT ON;
DECLARE @sqlCommand VARCHAR(4096)
SET @sqlCommand = ''
IF(@storeValuesInTable = 'Y')
BEGIN
IF NOT EXISTS (SELECT * FROM dbo.sysobjects where id = object_id(N'[InstanceValues]') and OBJECTPROPERTY(id, N'IsTable') = 1)
BEGIN
CREATE TABLE InstanceValues(
[sql_version] [VARCHAR](32) NOT NULL,
[sql_edition] [VARCHAR](64) NOT NULL,
[build_number] [VARCHAR](32) NOT NULL,
[min_server_memory] [DECIMAL](15,2) NOT NULL,
[max_server_memory] [DECIMAL](15,2) NOT NULL,
[server_memory] [DECIMAL](15,2) NOT NULL,
[server_cores] [SMALLINT] NOT NULL,
[sql_cores] [SMALLINT] NOT NULL,
[cost_threshold_for_parallelism][SMALLINT] NOT NULL,
[max_degree_of_parallelism] [SMALLINT] NOT NULL,
[lpim_enabled] [TINYINT] NOT NULL,
[ifi_enabled] [TINYINT] NOT NULL,
[installed_date] [DATETIME] NOT NULL,
[sql_service_account] [VARCHAR](64) NOT NULL,
[sql_agent_service_account] [VARCHAR](64) NOT NULL,
[startup_time] [DATETIME] NOT NULL,
[data_collection_timestamp] [DATETIME] NOT NULL
) ON [PRIMARY]
END
END
CREATE TABLE #CPUValues(
[index] SMALLINT,
[description] VARCHAR(128),
[server_cores] SMALLINT,
[value] VARCHAR(5)
)
CREATE TABLE #MemoryValues(
[index] SMALLINT,
[description] VARCHAR(128),
[server_memory] DECIMAL(10,2),
[value] VARCHAR(64)
)
INSERT INTO #CPUValues
EXEC xp_msver 'ProcessorCount'
INSERT INTO #MemoryValues
EXEC xp_msver 'PhysicalMemory'
CREATE TABLE #IFI_Value(DataOut VarChar(2000))
DECLARE @show_advanced_options INT
DECLARE @xp_cmdshell_enabled INT
DECLARE @xp_regread_enabled INT
SELECT @show_advanced_options = CONVERT(INT, ISNULL(value, value_in_use))
FROM master.sys.configurations
WHERE name = 'show advanced options'
IF @show_advanced_options = 0
BEGIN
EXEC sp_configure 'show advanced options', 1
RECONFIGURE WITH OVERRIDE
END
SELECT @xp_cmdshell_enabled = CONVERT(INT, ISNULL(value, value_in_use))
FROM master.sys.configurations
WHERE name = 'xp_cmdshell'
IF @xp_cmdshell_enabled = 0
BEGIN
EXEC sp_configure 'xp_cmdshell', 1
RECONFIGURE WITH OVERRIDE
END
INSERT INTO #IFI_Value
EXEC xp_cmdshell 'whoami /priv | findstr `"SeManageVolumePrivilege`"'
IF @xp_cmdshell_enabled = 0
BEGIN
EXEC sp_configure 'xp_cmdshell', 0
RECONFIGURE WITH OVERRIDE
END
IF @show_advanced_options = 0
BEGIN
EXEC sp_configure 'show advanced options', 0
RECONFIGURE WITH OVERRIDE
END
IF (SELECT CONVERT(INT, (REPLACE(SUBSTRING(CONVERT(NVARCHAR, SERVERPROPERTY('ProductVersion')), 1, 2), '.', '')))) > 10
BEGIN
IF(@storeValuesInTable = 'Y')
BEGIN
SET @sqlCommand = '
INSERT INTO InstanceValues
'
END
SET @sqlCommand += '
SELECT
v.sql_version,
(SELECT SUBSTRING(CONVERT(VARCHAR(255),SERVERPROPERTY(''EDITION'')),0,CHARINDEX(''Edition'',CONVERT(VARCHAR(255),SERVERPROPERTY(''EDITION'')))) + ''Edition'') AS sql_edition,
CONVERT(VARCHAR,SERVERPROPERTY(''ProductVersion'')) AS build_number,
(SELECT CONVERT(DECIMAL(10,2),[value]) FROM sys.configurations WHERE name LIKE ''%min server memory%'') min_server_memory,
(SELECT CONVERT(DECIMAL(10,2),[value]) FROM sys.configurations WHERE name LIKE ''%max server memory%'') max_server_memory,
(SELECT ROUND(CONVERT(DECIMAL(10,2),server_memory/1024.0),1) FROM #MemoryValues) AS server_memory,
server_cores,
(SELECT COUNT(*) AS ''sql_cores'' FROM sys.dm_os_schedulers WHERE status = ''VISIBLE ONLINE'') AS sql_cores,
(SELECT CONVERT(SMALLINT,[value]) FROM sys.configurations WHERE name LIKE ''%cost threshold for parallelism%'') AS cost_threshold_for_parallelism,
(SELECT CONVERT(SMALLINT,[value]) FROM sys.configurations WHERE name LIKE ''%max degree of parallelism%'') AS max_degree_of_parallelism,
(SELECT CASE locked_page_allocations_kb WHEN 0 THEN 0 ELSE 1 END FROM sys.dm_os_process_memory) AS lpim_enabled,
(SELECT COUNT(1) FROM #IFI_Value WHERE DataOut LIKE ''%SeManageVolumePrivilege%Enabled%'') AS ifi_enabled,
(SELECT create_date FROM sys.server_principals WHERE sid = 0x010100000000000512000000) AS installed_date,
(SELECT service_account FROM sys.dm_server_services WHERE servicename = {fn CONCAT({fn CONCAT(''SQL Server ('',CONVERT(VARCHAR(32),ISNULL(SERVERPROPERTY(''INSTANCENAME''),''MSSQLSERVER'')))},'')'')}) AS sql_service_account,
(SELECT service_account FROM sys.dm_server_services WHERE servicename = {fn CONCAT({fn CONCAT(''SQL Server Agent ('',CONVERT(VARCHAR(32),ISNULL(SERVERPROPERTY(''INSTANCENAME''),''MSSQLSERVER'')))},'')'')}) AS sql_agent_service_account,
(SELECT login_time FROM sys.sysprocesses WHERE spid = 1) AS startup_time'
IF(@storeValuesInTable = 'Y')
BEGIN
SET @sqlCommand += '
,GETDATE() AS data_collection_timestamp
'
END
SET @sqlCommand += '
FROM #CPUValues
LEFT JOIN (
SELECT
CASE
WHEN CONVERT(VARCHAR(128), SERVERPROPERTY (''PRODUCTVERSION'')) LIKE ''8%'' THEN ''SQL Server 2000''
WHEN CONVERT(VARCHAR(128), SERVERPROPERTY (''PRODUCTVERSION'')) LIKE ''9%'' THEN ''SQL Server 2005''
WHEN CONVERT(VARCHAR(128), SERVERPROPERTY (''PRODUCTVERSION'')) LIKE ''10.0%'' THEN ''SQL Server 2008''
WHEN CONVERT(VARCHAR(128), SERVERPROPERTY (''PRODUCTVERSION'')) LIKE ''10.5%'' THEN ''SQL Server 2008 R2''
WHEN CONVERT(VARCHAR(128), SERVERPROPERTY (''PRODUCTVERSION'')) LIKE ''11%'' THEN ''SQL Server 2012''
WHEN CONVERT(VARCHAR(128), SERVERPROPERTY (''PRODUCTVERSION'')) LIKE ''12%'' THEN ''SQL Server 2014''
WHEN CONVERT(VARCHAR(128), SERVERPROPERTY (''PRODUCTVERSION'')) LIKE ''13%'' THEN ''SQL Server 2016''
WHEN CONVERT(VARCHAR(128), SERVERPROPERTY (''PRODUCTVERSION'')) LIKE ''14%'' THEN ''SQL Server 2017''
WHEN CONVERT(VARCHAR(128), SERVERPROPERTY (''PRODUCTVERSION'')) LIKE ''15%'' THEN ''SQL Server 2019''
ELSE ''UNKNOWN''
END AS sql_version
) AS v ON 1 = 1
'
EXECUTE(@sqlCommand)
END
ELSE
BEGIN
DECLARE @instanceName VARCHAR(100)
SET @instanceName = CONVERT(VARCHAR,SERVERPROPERTY ('InstanceName'))
IF (@instanceName) IS NULL
BEGIN
DECLARE @agentAccount NVARCHAR(128);
EXEC master.dbo.xp_regread
'HKEY_LOCAL_MACHINE',
'SYSTEM\CurrentControlSet\services\SQLSERVERAGENT',
'ObjectName',
@agentAccount OUTPUT;
DECLARE @engineAccount NVARCHAR(128);
EXEC master.dbo.xp_regread
'HKEY_LOCAL_MACHINE',
'SYSTEM\CurrentControlSet\services\MSSQLSERVER',
'ObjectName',
@engineAccount OUTPUT;
END
ELSE
BEGIN
DECLARE @SQL NVARCHAR (500)
SET @SQL = 'EXEC master.dbo.xp_regread ''HKEY_LOCAL_MACHINE'', ''SYSTEM\CurrentControlSet\services\SQLAgent$'[email protected]+''',''ObjectName'', @serviceAccount OUTPUT;'
EXECUTE sp_executesql @SQL,N'@serviceAccount NVARCHAR(128) OUTPUT',@[email protected] OUTPUT
SET @SQL = 'EXEC master.dbo.xp_regread ''HKEY_LOCAL_MACHINE'', ''SYSTEM\CurrentControlSet\services\MSSQL$'[email protected]+''',''ObjectName'', @serviceAccount OUTPUT;'
EXECUTE sp_executesql @SQL,N'@serviceAccount NVARCHAR(128) OUTPUT',@[email protected] OUTPUT
END
IF(@storeValuesInTable = 'Y')
BEGIN
SET @sqlCommand = '
INSERT INTO InstanceValues
'
END
SET @sqlCommand += '
SELECT
v.sql_version,
(SELECT SUBSTRING(CONVERT(VARCHAR(255),SERVERPROPERTY(''EDITION'')),0,CHARINDEX(''Edition'',CONVERT(VARCHAR(255),SERVERPROPERTY(''EDITION'')))) + ''Edition'') AS sql_edition,
CONVERT(VARCHAR,SERVERPROPERTY(''ProductVersion'')) AS build_number,
(SELECT CONVERT(DECIMAL(10,2),[value]) FROM sys.configurations WHERE name LIKE ''%min server memory%'') min_server_memory,
(SELECT CONVERT(DECIMAL(10,2),[value]) FROM sys.configurations WHERE name LIKE ''%max server memory%'') max_server_memory,
(SELECT ROUND(CONVERT(DECIMAL(10,2),server_memory/1024.0),1) FROM #MemoryValues) AS server_memory,
server_cores,
(SELECT COUNT(*) AS sql_cores FROM sys.dm_os_schedulers WHERE status = ''VISIBLE ONLINE'') AS sql_cores,
(SELECT CONVERT(SMALLINT,[value]) FROM sys.configurations WHERE name LIKE ''%cost threshold for parallelism%'') AS cost_threshold_for_parallelism,
(SELECT CONVERT(SMALLINT,[value]) FROM sys.configurations WHERE name LIKE ''%max degree of parallelism%'') AS max_degree_of_parallelism,
(SELECT CASE locked_page_allocations_kb WHEN 0 THEN 0 ELSE 1 END FROM sys.dm_os_process_memory) AS lpim_enabled,
(SELECT COUNT(1) FROM #IFI_Value WHERE DataOut LIKE ''%SeManageVolumePrivilege%Enabled%'') AS ifi_enabled,
(SELECT create_date FROM sys.server_principals WHERE sid = 0x010100000000000512000000) AS installed_date,
(SELECT '+CHAR(39)[email protected]+CHAR(39)+' AS sql_service_account) AS sql_service_account,
(SELECT '+CHAR(39)[email protected]+CHAR(39)+' AS sql_agent_service_account) AS sql_agent_service_account,
(SELECT login_time FROM sys.sysprocesses WHERE spid = 1) AS startup_time'
IF(@storeValuesInTable = 'Y')
BEGIN
SET @sqlCommand += '
,GETDATE() AS data_collection_timestamp
'
END
SET @sqlCommand += '
FROM #CPUValues
LEFT JOIN (
SELECT
CASE
WHEN CONVERT(VARCHAR(128), SERVERPROPERTY (''PRODUCTVERSION'')) LIKE ''8%'' THEN ''SQL Server 2000''
WHEN CONVERT(VARCHAR(128), SERVERPROPERTY (''PRODUCTVERSION'')) LIKE ''9%'' THEN ''SQL Server 2005''
WHEN CONVERT(VARCHAR(128), SERVERPROPERTY (''PRODUCTVERSION'')) LIKE ''10.0%'' THEN ''SQL Server 2008''
WHEN CONVERT(VARCHAR(128), SERVERPROPERTY (''PRODUCTVERSION'')) LIKE ''10.5%'' THEN ''SQL Server 2008 R2''
WHEN CONVERT(VARCHAR(128), SERVERPROPERTY (''PRODUCTVERSION'')) LIKE ''11%'' THEN ''SQL Server 2012''
WHEN CONVERT(VARCHAR(128), SERVERPROPERTY (''PRODUCTVERSION'')) LIKE ''12%'' THEN ''SQL Server 2014''
WHEN CONVERT(VARCHAR(128), SERVERPROPERTY (''PRODUCTVERSION'')) LIKE ''13%'' THEN ''SQL Server 2016''
WHEN CONVERT(VARCHAR(128), SERVERPROPERTY (''PRODUCTVERSION'')) LIKE ''14%'' THEN ''SQL Server 2017''
WHEN CONVERT(VARCHAR(128), SERVERPROPERTY (''PRODUCTVERSION'')) LIKE ''15%'' THEN ''SQL Server 2019''
ELSE ''UNKNOWN''
END AS sql_version
) AS v ON 1 = 1
'
EXECUTE(@sqlCommand)
--SELECT @sqlCommand
END
DROP TABLE #CPUValues
DROP TABLE #MemoryValues
DROP TABLE #IFI_Value
END
Conclusion
La procédure stockée personnalisée présentée dans cet article vous permet de créer un mécanisme d'alerte pour notifier les modifications de toutes les valeurs d'un champ particulier au fil du temps.
Vous pouvez déployer ce SP dans chaque instance SQL Server sous votre support et mettre en œuvre le mécanisme d'audit sur l'ensemble de votre pile d'instances prises en charge.
L'importance primordiale des informations présentées serait de vérifier si l'instance SQL Server a des valeurs qui sont conformes aux meilleures pratiques recommandées. Il vous aide également à vérifier si une activité/modification récente a eu lieu pour mettre à jour l'un des paramètres (soit intentionnellement, soit par erreur).