Naše diskuse o proaktivních úkolech, které udržují vaši databázi v pořádku, pokračuje v tomto příspěvku, když řešíme možnosti serveru a databáze. Možná si už říkáte, že to bude rychlý příspěvek – kdo tak často mění možnosti serveru nebo databáze? Byli byste překvapeni, zvláště pokud máte mnoho lidí, kteří mají přístup k serveru SQL. Možnosti serveru a databáze by se měly měnit jen zřídka – většinou jsou nastaveny při instalaci a ponechány samotné. Ale čas od času se najde dobrý důvod pro provedení změny – ať už jde o výkon, kvůli změně kódu aplikace nebo možná proto, že bylo něco špatně nastaveno poprvé. Nejprve otestujte tyto změny a zaznamenejte vhodné metriky před změnou a po ní. Zdá se to docela jednoduché a zřejmé, že? Možná si to myslíte, ale pokud nemáte zavedený proces řízení změn, který je přísně dodržován, není tomu tak.
Ve většině prostředí má více než jedna osoba přístup k serveru SQL Server a více než jedna osoba má oprávnění nezbytná ke změně možností serveru nebo databáze. Pokud se změní nesprávné nastavení, může to mít významný dopad na výkon. (Už jste někdy nechtěně nastavili nastavení maximální paměti na hodnotu v GB místo v MB? V případě, že vás to zajímá, 128 MB není dostatek paměti potřebné pro spuštění instance SQL Server. Podívejte se na příspěvek Teda Kruegera o tom, jak to opravit , pokud byste někdy udělali takovou chybu.) Jiné změny mohou způsobit menší problémy, které jsou stále problematické a někdy je těžké je vystopovat (dobrým příkladem je zakázání automatického vytváření statistik). Možná si myslíte, že tyto změny by byly dobře sdělitelné (někdy jste tak zaneprázdněni hašením požárů, že zapomínáte) nebo že by si je bylo snadné všimnout (ne vždy). Abychom tomu zabránili, sledujeme nastavení a poté při provádění našich pravidelných kontrol (nebo při odstraňování problémů) ověřujeme, že se nic nezměnilo.
Zachycení dat
Na rozdíl od předchozího příspěvku o úlohách údržby, kde jsme se spoléhali na msdb, že uchovává data, na kterých nám záleželo, musíme nastavit například sběr dat a nastavení databáze. Denně budeme snímky sys.configurations a sys.database_info zaznamenávat do tabulek v naší databázi Baselines a poté pomocí dotazů zjistíme, zda se něco změnilo a kdy.
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
Skript pro vytvoření tabulky SQLskills_DBData je kompatibilní se serverem SQL Server 2014. U dřívějších verzí může být nutné upravit základní tabulku a dotaz na snímek (viz další sada kódu).
Jakmile budete mít tabulky vytvořené, vytvořte úlohu, která bude denně provádět následující dva dotazy. Opět bychom neočekávali, že by se tyto možnosti změnily více než jednou za den, a i když doufáme, že nikdo nezmění nastavení, pak ho změní zpět (proto se nezobrazí v zachycení), vždy je to možné . Pokud zjistíte, že tento sběr dat nevyhovuje vašim potřebám, protože nastavení se často nebo dočasně mění, možná budete chtít implementovat spouštěč nebo použít audit.
Chcete-li upravit možnosti serveru prostřednictvím (sp_configure), vyžaduje přihlášení oprávnění ALTER SETTINGS na úrovni serveru, které je zahrnuto, pokud jste členem role sysadmin nebo serveradmin. Chcete-li upravit většinu nastavení databáze (ALTER DATABASE SET), potřebujete oprávnění ALTER v databázi, i když některé možnosti vyžadují další práva, jako například CONTROL SERVER nebo možnost na úrovni serveru ALTER ANY DATABASE.
/* 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
Kontrola změn
Nyní, když zaznamenáváme tyto informace, jak najdeme změny? S vědomím, že se může změnit více nastavení a v různých datech, potřebujeme metodu, která se podívá na každý řádek. Není to těžké, ale negeneruje to nejhezčí kód. Pokud jde o možnosti serveru, není to špatné:
;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
Změněná nastavení instance
Pokud jde o možnosti databáze, dotaz je v uložené proceduře (protože byla tak nepraktická), kterou si můžete stáhnout zde. Spuštění uložené procedury:
EXEC dbo.usp_FindDBSettingChanges
Výstup bude seznam databáze a nastavení, které se změnilo, a také datum:
Změněné nastavení databáze
Tyto dotazy můžete spustit, když se objeví problémy s výkonem, abyste rychle zkontrolovali, zda se některá nastavení nezměnila, nebo můžete být o něco proaktivnější a spouštět je pravidelně v naplánované úloze, která vás upozorní, pokud se něco změnilo. Nezahrnul jsem kód T-SQL pro odeslání e-mailu pomocí databázové pošty, pokud dojde ke změně, ale to nebude těžké na základě zde poskytnutého kódu.
Použití Poradce pro výkon
SQL Sentry Performance Advisor tyto informace ve výchozím nastavení nesleduje, ale stále můžete zaznamenávat informace do databáze, poté nechat PA zkontrolovat, zda se některá nastavení nezměnila, a upozornit vás, pokud ano. Chcete-li to nastavit, vytvořte tabulky SQLskills_ConfigData a SQLskillsDBData a nastavte naplánovanou úlohu, která se má pravidelně vkládat do těchto tabulek. V rámci klienta SQL Sentry nastavte vlastní podmínku, jak jsme to udělali v dřívějším příspěvku této série, Proaktivní kontroly stavu SQL Serveru, Část 1:Příspěvek na disku.
V rámci Custom Condition máte dvě možnosti. Nejprve můžete spustit poskytnutý kód, který zkontroluje historická data, aby zjistil, zda se něco nezměnilo (a pak odeslat upozornění, pokud ano). Kontrola historických dat kvůli změnám je něco, co byste spouštěli denně, stejně jako u úlohy agenta. Případně můžete být proaktivnější a častěji porovnávat aktuální průběžné hodnoty s nejnovějšími údaji, např. jednou za hodinu hledat změny. Příklad kódu pro kontrolu aktuálního nastavení instance oproti nejnovějšímu zachycení:
;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
Shrnutí
Kontrola možností instance a databáze je přímočará a zřejmá a v některých situacích vám tyto historické informace mohou ušetřit značný čas při odstraňování problémů. Pokud tyto informace nikde nezachytáváte, doporučuji vám začít; vždy je lepší proaktivně hledat problémy, než reagovat, když hasíte a jste potenciálně ve stresu a nejste si jisti, co způsobuje problém ve vašem produkčním prostředí.