Nasza dyskusja na temat proaktywnych zadań, które utrzymują Twoją bazę danych w dobrym stanie, jest kontynuowana w tym poście, ponieważ zajmujemy się opcjami serwera i bazy danych. Być może już myślisz, że będzie to szybki post – kto tak często zmienia opcje serwera lub bazy danych? Byłbyś zaskoczony, zwłaszcza jeśli masz wiele osób, które mają dostęp do SQL Server. Opcje serwera i bazy danych powinny się rzadko zmieniać – w większości są one ustawiane podczas instalacji i pozostawiane same sobie. Ale od czasu do czasu istnieje dobry powód, aby dokonać zmiany – czy to związane z wydajnością, ze względu na zmianę kodu aplikacji, czy może dlatego, że coś zostało nieprawidłowo ustawione za pierwszym razem. Najpierw przetestuj te zmiany i przechwyć odpowiednie metryki przed zmianą i po niej. Wydaje się to całkiem proste i oczywiste, prawda? Możesz tak myśleć, ale jeśli nie masz ściśle przestrzeganego procesu zarządzania zmianami, to tak nie jest.
W większości środowisk więcej niż jedna osoba ma dostęp do SQL Server i więcej niż jedna osoba ma uprawnienia niezbędne do zmiany opcji serwera lub bazy danych. Zmiana niewłaściwego ustawienia może mieć znaczny wpływ na wydajność. (Czy kiedykolwiek przypadkowo ustawiłeś ustawienie maksymalnej pamięci na wartość w GB zamiast MB? Jeśli się zastanawiasz, 128 MB to za mało pamięci potrzebnej do uruchomienia instancji SQL Server. Sprawdź post Teda Kruegera, jak to naprawić , jeśli kiedykolwiek popełnisz ten błąd). Inne zmiany mogą spowodować mniejsze problemy, które nadal są kłopotliwe i czasami trudne do wyśledzenia (dobrym przykładem jest wyłączenie statystyk automatycznego tworzenia). Możesz pomyśleć, że te zmiany będą dobrze komunikowane (czasami jesteś tak zajęty gaszeniem pożarów, o których zapominasz) lub łatwe do zauważenia (nie zawsze). Aby tego uniknąć, śledzimy ustawienia, a następnie, przeprowadzając nasze regularne kontrole (lub rozwiązując problem), weryfikujemy, czy nic się nie zmieniło.
Przechwytywanie danych
W przeciwieństwie do poprzedniego postu o zadaniach konserwacyjnych, w których polegaliśmy na msdb, aby przechowywać dane, na których nam zależało, musimy skonfigurować przechwytywanie danych na przykład i ustawienia bazy danych. Będziemy codziennie tworzyć migawki sys.configuration i sys.database_info do tabel w naszej bazie danych Baselines, a następnie używać zapytań, aby sprawdzić, czy coś się zmieniło i kiedy.
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
Skrypt do tworzenia tabeli SQLskills_DBData jest zgodny z SQL Server 2014. W przypadku wcześniejszych wersji może być konieczne zmodyfikowanie tabeli bazowej i zapytania migawki (patrz następny zestaw kodu).
Po utworzeniu tabel utwórz zadanie, które będzie codziennie wykonywać następujące dwa zapytania. Ponownie, nie spodziewalibyśmy się, że te opcje zmienią się częściej niż raz dziennie i chociaż mamy nadzieję, że nikt nie zmieni ustawienia, a następnie nie zmieni go z powrotem (dlatego nie pojawiłoby się to w przechwyceniu), jest to zawsze możliwe . Jeśli stwierdzisz, że przechwytywanie danych nie odpowiada Twoim potrzebom, ponieważ ustawienia zmieniają się często lub tymczasowo, możesz zaimplementować wyzwalacz lub skorzystać z audytu.
Aby edytować opcje serwera za pomocą (sp_configure), logowanie wymaga uprawnienia na poziomie serwera ZMIEŃ USTAWIENIA, które jest dołączane, jeśli jesteś członkiem ról sysadmin lub serveradmin. Aby edytować większość ustawień bazy danych (ALTER DATABASE SET), potrzebujesz uprawnienia ALTER w bazie danych, chociaż niektóre opcje wymagają dodatkowych uprawnień, takich jak CONTROL SERVER lub opcja na poziomie serwera 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
Sprawdzanie zmian
Teraz, gdy przechwytujemy te informacje, jak znajdujemy zmiany? Wiedząc, że może zostać zmienionych wiele ustawień i w różnych terminach, potrzebujemy metody, która patrzy na każdy wiersz. Nie jest to trudne, ale nie generuje najładniejszego kodu. Jeśli chodzi o opcje serwera, nie jest tak źle:
;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
Zmienione ustawienia instancji
W przypadku opcji bazy danych zapytanie znajduje się w procedurze składowanej (ponieważ była tak nieporęczna), którą można pobrać tutaj. Aby uruchomić procedurę składowaną:
EXEC dbo.usp_FindDBSettingChanges
Wynik wyświetli listę bazy danych i zmienione ustawienie, a także datę:
Zmienione ustawienia bazy danych
Możesz uruchomić te zapytania, gdy pojawią się problemy z wydajnością, aby szybko sprawdzić, czy zmieniły się jakieś ustawienia, lub możesz być nieco bardziej proaktywny i uruchamiać je regularnie w zaplanowanym zadaniu, które powiadamia Cię, jeśli coś się zmieniło. Nie dołączyłem kodu T-SQL do wysłania wiadomości e-mail przy użyciu poczty z bazy danych, jeśli nastąpi zmiana, ale nie będzie to trudne do zrobienia w oparciu o podany tutaj kod.
Korzystanie z doradcy wydajności
Doradca wydajności programu SQL Sentry nie śledzi domyślnie tych informacji, ale nadal można przechwycić informacje w bazie danych, a następnie sprawdzić PA, aby sprawdzić, czy zmieniły się jakiekolwiek ustawienia, i powiadomić o tym. Aby to skonfigurować, utwórz tabele SQLskills_ConfigData i SQLskillsDBData i skonfiguruj zaplanowane zadanie do regularnego wstawiania do tych tabel. W kliencie SQL Sentry skonfiguruj warunek niestandardowy, tak jak to zrobiliśmy we wcześniejszym poście z tej serii, Proaktywne kontrole stanu serwera SQL Server, część 1:wpis o miejscu na dysku.
W ramach Warunku niestandardowego masz dwie opcje. Po pierwsze, możesz po prostu wykonać dostarczony kod, który sprawdza dane historyczne, aby zobaczyć, czy coś się zmieniło (a następnie wysłać powiadomienie, jeśli tak). Sprawdzanie danych historycznych pod kątem zmian to coś, co można uruchamiać codziennie, tak jak w przypadku pracy agenta. Alternatywnie możesz być bardziej proaktywny i częściej porównywać bieżące, bieżące wartości z najnowszymi danymi, np. raz na godzinę, aby szukać zmian. Przykładowy kod sprawdzający bieżące ustawienia instancji z najnowszym przechwyceniem:
;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
Podsumowanie
Sprawdzanie opcji instancji i bazy danych jest proste i oczywiste, aw niektórych sytuacjach te historyczne informacje mogą zaoszczędzić sporo czasu podczas rozwiązywania problemów. Jeśli nigdzie nie przechwytujesz tych informacji, zachęcam do rozpoczęcia; zawsze lepiej proaktywnie szukać problemów niż reagować, gdy walczysz z ogniem i potencjalnie jesteś zestresowany, nie mając pewności, co powoduje problem w Twoim środowisku produkcyjnym.