Wprowadzenie
Zdarzają się sytuacje, w których aplikacje utrzymują połączenie z bazą danych przez długi czas. Wydaje się, że to nie jest ważne. Jeśli jednak ta aplikacja nawiązuje wiele połączeń lub istnieje kilka aplikacji zachowujących się w taki sposób — sytuacja się pogarsza.
Ten artykuł nie jest samouczkiem. Opisuje możliwe rozwiązania tego problemu. Jak zwykle z przyjemnością wysłucham wszelkich alternatywnych rozwiązań.
Rozwiązanie
1. Utwórz procedurę składowaną, która zamyka wszystkie połączenia lub połączenia określonego użytkownika z określoną bazą danych:
USE [DATABASE_NAME] GO SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO CREATE PROCEDURE [srv].[KillConnect] @databasename nvarchar(255), -- database @loginname nvarchar(255)=NULL -- login details AS BEGIN /* deletes connections for the specified database and login details access */ SET NOCOUNT ON; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; if(@databasename is null) begin ;THROW 50000, 'A database is not specified!', 0; end else begin declare @dbid int=db_id(@databasename); if(@dbid is NULL) begin ;THROW 50000, 'The database does not exist!', 0; end else if @dbid <= 4 begin ;THROW 50000, 'To delete connections to a system database is forbidden!', 0; end else begin declare @query nvarchar(max); set @query = ''; select @query=coalesce(@query,',' ) +'kill ' +convert(varchar, spid) +'; ' from master..sysprocesses where dbid=db_id(@databasename) and spid<>@@SPID and ([email protected] or @loginname is null); if len(@query) > 0 begin begin try exec(@query); end try begin catch end catch end end end END GO
Ta procedura składowana pomaga ręcznie wyłączyć wszystkie połączenia z bazą danych lub określonego użytkownika w celu wykonania dalszych działań z bazą danych.
2. Utwórz procedurę składowaną, aby usunąć wszystkie zablokowane procesy.
USE [DATABASE_NAME] GO SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO CREATE PROCEDURE [srv].[KillFullOldConnect] AS BEGIN /* It deletes the connections which were executed a day ago. Attention! System databases such as master, tempdb, model and msdb do not take part in this process. However, it does not affect database distribution for replication. */ SET NOCOUNT ON; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; declare @query nvarchar(max); set @query = ''; select @query=coalesce(@query,',' ) +'kill ' +convert(varchar, spid) +'; ' from master..sysprocesses where dbid>4 and [last_batch]<dateadd(day,-1,getdate()) order by [last_batch] if len(@query) > 0 begin begin try exec(@query); end try begin catch end catch end END GO
Ta procedura składowana usuwa połączenia, które zostały zakończone ponad 24 godziny temu. Ponadto ta procedura nie wpływa na główne bazy danych systemu (master, tempdb, model i msdb). Jeśli spróbujesz uzyskać dostęp do bazy danych, gdy połączenie jest wyłączone, zostanie utworzone nowe połączenie dla tej aplikacji.
Teraz konieczne jest uruchomienie procedury składowanej w zadaniu Agenta raz dziennie:
exec [DATABASE_NAME].[srv].[KillFullOldConnect];
Lepiej byłoby umieścić to zapytanie w bloku try-catch, aby przetworzyć możliwe wywołanie wyjątków.
Wynik
W tym artykule przeanalizowałem, jak zaimplementować procedury składowane przy zamykaniu połączenia z bazą danych (wszystkim lub określonym użytkownikiem) i usuwać zablokowane procesy na konkretnym przykładzie. Ponadto zbadałem na konkretnym przykładzie, jak codziennie automatycznie uruchamiać zadanie po usunięciu zablokowanych procesów. Pozwala zmniejszyć liczbę „martwych” połączeń z serwerem. Usunięcie wszystkich połączeń z bazą danych umożliwia modyfikację niektórych właściwości, a także zamknięcie procesu, który powoduje jakikolwiek problem.
Referencje:
» procesy systemowe
» zabij
» db_id
» @@SPID