sql >> Database >  >> RDS >> Sqlserver

Proactieve SQL Server-statuscontroles, deel 3:instantie- en database-instellingen

Onze bespreking van proactieve taken die uw database gezond houden, gaat verder in dit bericht terwijl we server- en database-opties aanpakken. Je denkt misschien al dat dit een snelle post zal zijn - wie verandert er zo vaak server- of database-opties? Het zou je verbazen, vooral als je veel mensen hebt die toegang hebben tot de SQL Server. Server- en database-opties zouden niet vaak moeten veranderen - voor het grootste deel worden deze ingesteld bij installatie en met rust gelaten. Maar zo nu en dan is er een goede reden om een ​​wijziging aan te brengen - of het nu prestatiegerelateerd is, vanwege een wijziging in de applicatiecode, of misschien omdat er de eerste keer iets verkeerd is ingesteld. Test deze wijzigingen eerst en leg de juiste statistieken vast voor en na de wijziging. Het lijkt vrij eenvoudig en duidelijk, toch? U denkt misschien van wel, maar als u geen proces voor wijzigingsbeheer heeft dat strikt wordt gevolgd, is dat niet zo.

In de meeste omgevingen heeft meer dan één persoon toegang tot SQL Server en heeft meer dan één persoon de privileges die nodig zijn om server- of databaseopties te wijzigen. Als de verkeerde instelling wordt gewijzigd, kan de impact op de prestaties aanzienlijk zijn. (Heb je ooit per ongeluk de maximale geheugeninstelling ingesteld op een waarde in GB in plaats van MB? Voor het geval je je afvraagt, is 128 MB niet genoeg geheugen nodig om een ​​SQL Server-instantie te starten. Bekijk het bericht van Ted Krueger over hoe je dit kunt oplossen , mocht u ooit die fout maken.) Andere wijzigingen kunnen kleinere problemen veroorzaken die nog steeds lastig en soms moeilijk op te sporen zijn (het uitschakelen van Auto Create Statistics is een goed voorbeeld). Je zou kunnen denken dat deze veranderingen goed gecommuniceerd zouden zijn (soms ben je zo druk met het blussen van branden die je vergeet) of gemakkelijk op te merken (niet altijd). Om dit te voorkomen, houden we de instellingen bij en vervolgens, bij het uitvoeren van onze regelmatige controles (of bij het oplossen van een probleem), controleren we of er niets is veranderd.

De gegevens vastleggen

In tegenstelling tot het vorige bericht over onderhoudstaken, waar we op msdb vertrouwden om de gegevens waar we om gaven vast te houden, moeten we bijvoorbeeld gegevensvastlegging en database-instellingen instellen. We maken dagelijks snapshots van sys.configurations en sys.database_info naar tabellen in onze Baselines-database en gebruiken vervolgens query's om te zien of er iets is veranderd en wanneer.

USE [Baselines];
GO
 
IF OBJECT_ID(N'dbo.SQLskills_ConfigData', N'U') IS NULL
BEGIN
  CREATE TABLE [dbo].[SQLskills_ConfigData] 
  (
    [ConfigurationID] [int] NOT NULL ,
    [Name] [nvarchar](35) NOT NULL ,
    [Value] [sql_variant] NULL ,
    [ValueInUse] [sql_variant] NULL ,
    [CaptureDate] [datetime] NOT NULL DEFAULT SYSDATETIME()
  ) ON [PRIMARY];
GO
 
CREATE CLUSTERED INDEX [CI_SQLskills_ConfigData] 
  ON [dbo].[SQLskills_ConfigData] ([CaptureDate],[ConfigurationID]);
GO
 
IF OBJECT_ID(N'dbo.SQLskills_DBData', N'U') IS NULL
BEGIN
  CREATE TABLE [dbo].[SQLskills_DBData]
  (
    [name] [sysname] NOT NULL,
    [database_id] [int] NOT NULL,
    [source_database_id] [int] NULL,
    [owner_sid] [varbinary](85) NULL,
    [create_date] [datetime] NOT NULL,
    [compatibility_level] [tinyint] NOT NULL,
    [collation_name] [sysname] NULL,
    [user_access] [tinyint] NULL,
    [user_access_desc] [nvarchar](60) NULL,
    [is_read_only] [bit] NULL,
    [is_auto_close_on] [bit] NOT NULL,
    [is_auto_shrink_on] [bit] NULL,
    [state] [tinyint] NULL,
    [state_desc] [nvarchar](60) NULL,
    [is_in_standby] [bit] NULL,
    [is_cleanly_shutdown] [bit] NULL,
    [is_supplemental_logging_enabled] [bit] NULL,
    [snapshot_isolation_state] [tinyint] NULL,
    [snapshot_isolation_state_desc] [nvarchar](60) NULL,
    [is_read_committed_snapshot_on] [bit] NULL,
    [recovery_model] [tinyint] NULL,
    [recovery_model_desc] [nvarchar](60) NULL,
    [page_verify_option] [tinyint] NULL,
    [page_verify_option_desc] [nvarchar](60) NULL,
    [is_auto_create_stats_on] [bit] NULL,
    [is_auto_update_stats_on] [bit] NULL,
    [is_auto_update_stats_async_on] [bit] NULL,
    [is_ansi_null_default_on] [bit] NULL,
    [is_ansi_nulls_on] [bit] NULL,
    [is_ansi_padding_on] [bit] NULL,
    [is_ansi_warnings_on] [bit] NULL,
    [is_arithabort_on] [bit] NULL,
    [is_concat_null_yields_null_on] [bit] NULL,
    [is_numeric_roundabort_on] [bit] NULL,
    [is_quoted_identifier_on] [bit] NULL,
    [is_recursive_triggers_on] [bit] NULL,
    [is_cursor_close_on_commit_on] [bit] NULL,
    [is_local_cursor_default] [bit] NULL,
    [is_fulltext_enabled] [bit] NULL,
    [is_trustworthy_on] [bit] NULL,
    [is_db_chaining_on] [bit] NULL,
    [is_parameterization_forced] [bit] NULL,
    [is_master_key_encrypted_by_server] [bit] NOT NULL,
    [is_published] [bit] NOT NULL,
    [is_subscribed] [bit] NOT NULL,
    [is_merge_published] [bit] NOT NULL,
    [is_distributor] [bit] NOT NULL,
    [is_sync_with_backup] [bit] NOT NULL,
    [service_broker_guid] [uniqueidentifier] NOT NULL,
    [is_broker_enabled] [bit] NOT NULL,
    [log_reuse_wait] [tinyint] NULL,
    [log_reuse_wait_desc] [nvarchar](60) NULL,
    [is_date_correlation_on] [bit] NOT NULL,
    [is_cdc_enabled] [bit] NOT NULL,
    [is_encrypted] [bit] NULL,
    [is_honor_broker_priority_on] [bit] NULL,
    [replica_id] [uniqueidentifier] NULL,
    [group_database_id] [uniqueidentifier] NULL,
    [default_language_lcid] [smallint] NULL,
    [default_language_name] [nvarchar](128) NULL,
    [default_fulltext_language_lcid] [int] NULL,
    [default_fulltext_language_name] [nvarchar](128) NULL,
    [is_nested_triggers_on] [bit] NULL,
    [is_transform_noise_words_on] [bit] NULL,
    [two_digit_year_cutoff] [smallint] NULL,
    [containment] [tinyint] NULL,
    [containment_desc] [nvarchar](60) NULL,
    [target_recovery_time_in_seconds] [int] NULL,
    [CaptureDate] [datetime] NOT NULL DEFAULT SYSDATETIME()
) ON [PRIMARY];
GO
 
CREATE CLUSTERED INDEX [CI_SQLskills_DBData] 
  ON [dbo].[SQLskills_DBData] ([CaptureDate],[database_id]);
GO

Het script om de SQLskills_DBData-tabel te maken is compatibel met SQL Server 2014. Voor eerdere versies moet u mogelijk de basistabel en de snapshot-query wijzigen (zie volgende set code).

Nadat u de tabellen hebt gemaakt, maakt u een taak die de volgende twee query's dagelijks uitvoert. Nogmaals, we zouden niet verwachten dat deze opties meer dan één keer per dag zouden veranderen, en hoewel we hopen dat niemand een instelling zou veranderen en dan terug zou veranderen (daarom zou het niet verschijnen in een opname), is dat altijd een mogelijkheid . Als u merkt dat deze gegevensverzameling niet aan uw behoeften voldoet, omdat instellingen vaak of tijdelijk veranderen, wilt u misschien een trigger implementeren of auditing gebruiken.

Om serveropties te bewerken via (sp_configure), heeft een login de ALTER SETTINGS-machtiging op serverniveau nodig, die is inbegrepen als u lid bent van de rollen sysadmin of serveradmin. Om de meeste database-instellingen te bewerken (ALTER DATABASE SET), hebt u de ALTER-machtiging in de database nodig, hoewel voor sommige opties aanvullende rechten zijn vereist, zoals CONTROL SERVER of de optie ALTER ANY DATABASE op serverniveau.

/* Statements to use in scheduled job */
 
INSERT INTO [dbo].[SQLskills_ConfigData]
(
  [ConfigurationID] ,
  [Name] ,
  [Value] ,
  [ValueInUse]
)
SELECT 
  [configuration_id] ,
  [name] ,
  [value] ,
  [value_in_use]
FROM [sys].[configurations];
GO
 
INSERT INTO [dbo].[SQLskills_DBData]
(
  [name],
  [database_id],
  [source_database_id],
  [owner_sid],
  [create_date],
  [compatibility_level],
  [collation_name],
  [user_access],
  [user_access_desc],
  [is_read_only],
  [is_auto_close_on],
  [is_auto_shrink_on],
  [state],
  [state_desc],
  [is_in_standby],
  [is_cleanly_shutdown],
  [is_supplemental_logging_enabled],
  [snapshot_isolation_state],
  [snapshot_isolation_state_desc],
  [is_read_committed_snapshot_on],
  [recovery_model],
  [recovery_model_desc],
  [page_verify_option],
  [page_verify_option_desc],
  [is_auto_create_stats_on],
  [is_auto_update_stats_on],
  [is_auto_update_stats_async_on],
  [is_ansi_null_default_on],
  [is_ansi_nulls_on],
  [is_ansi_padding_on],
  [is_ansi_warnings_on],
  [is_arithabort_on],
  [is_concat_null_yields_null_on],
  [is_numeric_roundabort_on],
  [is_quoted_identifier_on],
  [is_recursive_triggers_on],
  [is_cursor_close_on_commit_on],
  [is_local_cursor_default],
  [is_fulltext_enabled],
  [is_trustworthy_on],
  [is_db_chaining_on],
  [is_parameterization_forced],
  [is_master_key_encrypted_by_server],
  [is_published],
  [is_subscribed],
  [is_merge_published],
  [is_distributor],
  [is_sync_with_backup],
  [service_broker_guid],
  [is_broker_enabled],
  [log_reuse_wait],
  [log_reuse_wait_desc],
  [is_date_correlation_on],
  [is_cdc_enabled],
  [is_encrypted],
  [is_honor_broker_priority_on],
  [replica_id],
  [group_database_id],
  [default_language_lcid],
  [default_language_name],
  [default_fulltext_language_lcid],
  [default_fulltext_language_name],
  [is_nested_triggers_on],
  [is_transform_noise_words_on],
  [two_digit_year_cutoff],
  [containment],
  [containment_desc],
  [target_recovery_time_in_seconds]
)
SELECT
  [name],
  [database_id],
  [source_database_id],
  [owner_sid],
  [create_date],
  [compatibility_level],
  [collation_name],
  [user_access],
  [user_access_desc],
  [is_read_only],
  [is_auto_close_on],
  [is_auto_shrink_on],
  [state],
  [state_desc],
  [is_in_standby],
  [is_cleanly_shutdown],
  [is_supplemental_logging_enabled],
  [snapshot_isolation_state],
  [snapshot_isolation_state_desc],
  [is_read_committed_snapshot_on],
  [recovery_model],
  [recovery_model_desc],
  [page_verify_option],
  [page_verify_option_desc],
  [is_auto_create_stats_on],
  [is_auto_update_stats_on],
  [is_auto_update_stats_async_on],
  [is_ansi_null_default_on],
  [is_ansi_nulls_on],
  [is_ansi_padding_on],
  [is_ansi_warnings_on],
  [is_arithabort_on],
  [is_concat_null_yields_null_on],
  [is_numeric_roundabort_on],
  [is_quoted_identifier_on],
  [is_recursive_triggers_on],
  [is_cursor_close_on_commit_on],
  [is_local_cursor_default],
  [is_fulltext_enabled],
  [is_trustworthy_on],
  [is_db_chaining_on],
  [is_parameterization_forced],
  [is_master_key_encrypted_by_server],
  [is_published],
  [is_subscribed],
  [is_merge_published],
  [is_distributor],
  [is_sync_with_backup],
  [service_broker_guid],
  [is_broker_enabled],
  [log_reuse_wait],
  [log_reuse_wait_desc],
  [is_date_correlation_on],
  [is_cdc_enabled],
  [is_encrypted],
  [is_honor_broker_priority_on],
  [replica_id],
  [group_database_id],
  [default_language_lcid],
  [default_language_name],
  [default_fulltext_language_lcid],
  [default_fulltext_language_name],
  [is_nested_triggers_on],
  [is_transform_noise_words_on],
  [two_digit_year_cutoff],
  [containment],
  [containment_desc],
  [target_recovery_time_in_seconds]
FROM [sys].[databases];
GO

Controleren op wijzigingen

Nu we deze informatie aan het vastleggen zijn, hoe vinden we dan veranderingen? Wetende dat er meerdere instellingen kunnen worden gewijzigd en op verschillende datums, hebben we een methode nodig die naar elke rij kijkt. Dit is niet moeilijk om te doen, maar het genereert niet de mooiste code. Voor serveropties valt het mee:

;WITH [f] AS
( 
  SELECT
    ROW_NUMBER() OVER (PARTITION BY [ConfigurationID] ORDER BY [CaptureDate] ASC) AS [RowNumber],
    [ConfigurationID] AS [ConfigurationID],
    [Name] AS [Name],
    [Value] AS [Value],
    [ValueInUse] AS [ValueInUse],
    [CaptureDate] AS [CaptureDate]
  FROM [Baselines].[dbo].[ConfigData]
)
SELECT 
  [f].[Name] AS [Setting], 
  [f].[CaptureDate] AS [Date], 
  [f].[Value] AS [Previous Value], 
  [f].[ValueInUse] AS [Previous Value In Use],
  [n].[CaptureDate] AS [Date Changed], 
  [n].[Value] AS [New Value], 
  [n].[ValueInUse] AS [New Value In Use]
FROM [f]
LEFT OUTER JOIN [f] AS [n]
ON [f].[ConfigurationID] = [n].[ConfigurationID]
AND [f].[RowNumber] + 1 = [n].[RowNumber]
WHERE ([f].[Value] <> [n].[Value] OR [f].[ValueInUse] <> [n].[ValueInUse]);
GO

Instance-instellingen gewijzigd

Voor database-opties bevindt de query zich in een opgeslagen procedure (omdat deze zo onpraktisch was), die u hier kunt downloaden. Om de opgeslagen procedure uit te voeren:

EXEC dbo.usp_FindDBSettingChanges

De uitvoer toont de database en de instelling die is gewijzigd, evenals de datum:

Gewijzigde database-instellingen

U kunt deze query's uitvoeren wanneer er prestatieproblemen optreden, om snel te controleren of instellingen zijn gewijzigd, of u kunt wat proactiever zijn en ze regelmatig uitvoeren in een geplande taak die u op de hoogte stelt als er iets is gewijzigd. Ik heb de T-SQL-code niet toegevoegd om een ​​e-mail te verzenden via databasemail als er een wijziging is, maar dat zal niet moeilijk zijn op basis van de hier verstrekte code.

Prestatieadviseur gebruiken

SQL Sentry Performance Advisor houdt deze informatie niet standaard bij, maar u kunt de informatie nog steeds vastleggen in een database, vervolgens PA laten controleren of er instellingen zijn gewijzigd en u op de hoogte stellen als dat het geval is. Om dit in te stellen, maakt u de tabellen SQLskills_ConfigData en SQLskillsDBData en stelt u de geplande taak in om regelmatig in die tabellen in te voegen. Stel binnen de SQL Sentry-client een aangepaste voorwaarde in, zoals we hebben gedaan in een eerder bericht in deze serie, Proactieve SQL Server-statuscontroles, deel 1:bericht over schijfruimte.

Binnen de aangepaste voorwaarde hebt u twee opties. Ten eerste kunt u gewoon de verstrekte code uitvoeren die historische gegevens controleert om te zien of er iets is veranderd (en dan een melding sturen als dat zo is). Het controleren van historische gegevens op wijzigingen is iets dat u dagelijks zou doen, zoals u zou doen met een Agent Job. Als alternatief kunt u proactiever zijn en de huidige, lopende waarden vaker vergelijken met de meest recente gegevens, b.v. een keer per uur, om te zoeken naar wijzigingen. Voorbeeldcode om de huidige instellingen voor de instantie te vergelijken met de meest recente opname:

;WITH [lc] AS
(
  SELECT
    ROW_NUMBER() OVER (PARTITION BY [ConfigurationID] ORDER BY [CaptureDate] ASC) AS [RowNumber],
    [ConfigurationID] AS [ConfigurationID],
    [Name] AS [Name],
    [Value] AS [Value],
    [ValueInUse] AS [ValueInUse],
    [CaptureDate] AS [CaptureDate]
  FROM [Baselines].[ConfigData]
  WHERE [CaptureDate] = (SELECT MAX([CaptureDate]) FROM [Baselines].[ConfigData])
)
SELECT 
  [lc].[Name] AS [Setting], 
  [lc].[CaptureDate] AS [Date], 
  [lc].[Value] AS [Last Captured Value],
  [lc].[ValueInUse] AS [Last Captured Value In Use], 
  CURRENT_TIMESTAMP AS [Current Time],
  [c].[Value] AS [Current Value], 
  [c].[value_in_use] AS [Current Value In Use]
FROM [sys].[configurations] AS [c]
LEFT OUTER JOIN [lc]
ON [lc].[ConfigurationID] = [c].[configuration_id]
WHERE ([lc].[Value] <> [c].[Value] OR [lc].[ValueInUse] <> [c].[value_in_use]);
GO

Samenvatting

Het controleren van instance- en database-opties is eenvoudig en duidelijk, en in sommige situaties kan deze historische informatie u veel tijd besparen bij het oplossen van problemen. Als je deze informatie nergens vastlegt, raad ik je aan om te beginnen; het is altijd beter om proactief naar problemen te zoeken dan te reageren wanneer u aan het blussen bent en mogelijk gestrest bent, niet zeker van wat een probleem in uw productieomgeving veroorzaakt.


  1. Uitzondering verhogen in PL/SQL?

  2. SQL Server - voeg rijen samen in een door komma's gescheiden lijst

  3. PostgreSQL, SELECTEER van max id

  4. Door komma's gescheiden waarden met SQL Query