Pengantar
Hal ini sering terjadi ketika transaksi MS SQL Server dilupakan oleh inisiator. Contoh terbaiknya adalah sebagai berikut:skrip dieksekusi di SSMS yang, melalui instruksi 'begin tran', memulai transaksi dan terjadi kesalahan; namun, 'commit' atau 'rollback' tidak berhasil dan inisiator eksekusi telah meninggalkan kueri ini untuk waktu yang lama. Akibatnya, semakin banyak fluktuasi yang muncul saat memblokir kueri yang meminta akses ke sumber daya tertutup (tabel dan sumber daya server seperti RAM, CPU, dan sistem input-output).
Dalam artikel ini, kita akan melihat salah satu cara Anda dapat mengotomatiskan proses penghapusan transaksi yang terlupakan.
Solusinya
Mari kita definisikan transaksi yang terlupakan sebagai transaksi aktif (yang saat ini dijalankan) yang, selama rentang waktu T yang cukup besar, tidak memiliki kueri aktif (yang dijalankan saat ini).
Berikut algoritme umum untuk menghapus transaksi semacam itu:
- Membuat tabel untuk menyimpan dan menganalisis informasi tentang transaksi yang saat ini terlupakan serta tabel untuk mengurutkan dan mengarsipkan transaksi yang dipilih dari tabel pertama dengan tindakan penghapusan.
- Mengumpulkan informasi (transaksi dan sesinya yang tidak memiliki kueri, yaitu transaksi yang telah dieksekusi dan dilupakan dalam rentang waktu tertentu T.
- Menyegarkan tabel yang berisi semua transaksi yang saat ini terlupakan yang kita dapatkan di langkah 1 (jika transaksi yang terlupakan telah memperoleh kueri aktif, maka transaksi tersebut akan dihapus dari tabel ini).
- Mengambil sesi yang perlu kita hentikan (sesi memiliki setidaknya satu transaksi yang ditempatkan sebagai dilupakan ke dalam tabel dari langkah 1 K atau lebih kali dan sesi tersebut memiliki kueri aktif yang hilang dalam jumlah yang sama).
- Mengarsipkan data yang akan kami hapus (detail tentang sesi, koneksi, dan transaksi yang akan dihentikan).
- Menghapus sesi yang dipilih.
- Menghapus entri yang diproses bersama dengan entri yang tidak dapat dihapus dan terlalu lama berada di tabel dari langkah 1.
Sekarang, mari kita lihat bagaimana kita dapat mengimplementasikan algoritme ini.
Pertama-tama, kita perlu membuat tabel untuk menyimpan dan menganalisis informasi tentang semua transaksi yang saat ini terlupakan:
GUNAKAN [DB_NAME]GOSET ANSI_NULLS ONGOSET QUOTED_IDENTIFIER ONGOCREATE TABLE [srv].[SessionTran]( [SessionID] [int] NOT NULL, [TransactionID] [bigint] NOT NULL, [CountTranNotRequest] [SessionNotRequest] NULLyint] NOT NULL ] [tinyint] NOT NULL, [TransactionBeginTime] [datetime] NOT NULL, [InsertUTCDate] [datetime] NOT NULL, [UpdateUTCDate] [datetime] NOT NULL, CONSTRAINT [PK_SessionTran] PRIMARY KEY CLUSTERED ( [SessionID] ASC, [TransactionID] ASC)DENGAN (PAD_INDEX =OFF, STATISTICS_NORECOMPUTE =OFF, IGNORE_DUP_KEY =OFF, ALLOW_ROW_LOCKS =ON, ALLOW_PAGE_LOCKS =ON) ON [PRIMARY]) ON [PRIMARY]GOALTER TABLE [SeDF_SrvTran].[SeDF_Srv. 0)) UNTUK [CountTranNotRequest]GOALTER TABLE [srv].[SessionTran] ADD CONSTRAINT [DF_SessionTran_CountSessionNotRequest] DEFAULT ((0)) UNTUK [CountSessionNotRequest]GOALTER TABLE [srv].[SessionTran] TAMBAHKAN CONSTRAINT [DF_Insert. ) UNTUK [InsertUTCDate]GOALTER TABLE [srv].[Sesi Tran] ADD CONSTRAINT [DF_SessionTran_UpdateUTCDate] DEFAULT (getutcdate()) UNTUK [UpdateUTCDate]GO
Di sini:
1) SessionID — pengenal sesi
2) TransactionID — pengenal transaksi yang terlupakan
3) CountTranNotRequest — berapa kali transaksi telah didaftarkan sebagai terlupakan
4) CountSessionNotRequest — berapa kali suatu sesi tanpa query aktif telah terdaftar dan memiliki transaksi yang terlupakan
5) TransactionBeginTime — tanggal dan waktu inisiasi transaksi yang terlupakan
6) InsertUTCDate — tanggal dan waktu pembuatan entri (UTC)
7) UpdateUTCDate — tanggal dan waktu pembaruan entri (UTC)
Selanjutnya, kita akan membuat tabel untuk mengarsipkan dan mengurutkan transaksi dari tabel pertama berdasarkan tindakan penghapusan:
[expand title =”Kode “]
GUNAKAN [DB_NAME]GOSET ANSI_NULLS ONGOSET QUOTED_IDENTIFIER ONGOCREATE TABLE [srv].[KillSession]( [ID] [int] IDENTITY(1,1) NOT NULL, [session_id] [smallint] NOT NULL, [transaction_id] [bigint ] NOT NULL, [login_time] [datetime] NOT NULL, [host_name] [nvarchar](128) NULL, [program_name] [nvarchar](128) NULL, [host_process_id] [int] NULL, [client_version] [int] NULL , [client_interface_name] [nvarchar](32) NULL, [security_id] [varbinary](85) NOT NULL, [login_name] [nvarchar](128) NOT NULL, [nt_domain] [nvarchar](128) NULL, [nt_user_name] [nvarchar](128) NULL, [status] [nvarchar](30) NOT NULL, [context_info] [varbinary](128) NULL, [cpu_time] [int] NOT NULL, [memory_usage] [int] NOT NULL, [ total_scheduled_time] [int] NOT NULL, [total_elapsed_time] [int] NOT NULL, [endpoint_id] [int] NOT NULL, [last_request_start_time] [datetime] NOT NULL, [last_request_end_time] [datetime] NULL, [membaca] [bigint] NOT NULL, [menulis] [bigint] NOT NULL, [logical_reads] [bigint] NOT NULL, [is_user_process] [bit] NOT NULL, [text_size] [int] NOT NULL, [bahasa] [nvarchar](128) NULL, [date_format] [nvarchar](3) NULL, [date_first] [smallint] NOT NULL, [quoted_identifier] [bit] NOT NULL, [arithabort] [bit] NOT NULL, [ansi_null_dflt_on] [bit] NOT NULL, [ansi_defaults] [bit] NOT NULL, [ansi_warnings] [bit] NOT NULL, [ansi_padding] [bit] NOT NULL, [ansi_nulls] [bit] NOT NULL, [concat_null_yields_null] [bit] NOT NULL, [transaction_isolation_level] [smallint] NOT NULL, [lock_timeout] [int] NOT NULL, [deadlock_priority] [int] NOT NULL, [row_count] [bigint] NOT NULL , [prev_error] [int] NOT NULL, [original_security_id] [varbinary](85) NOT NULL, [original_login_name] [nvarchar](128) NOT NULL, [last_successful_logon] [datetime] NULL, [last_unsuccessful_logon] [datetime] NULL, [unsuccessful_logons] [bigint] NULL, [group_id] [int] NOT NULL, [database_id] [smallint] NOT NULL, [authenticating_database_id] [int] NULL, [open_transaction_count] [int] NOT NULL, [most_recent_session_id] [int] NULL , [waktu_koneksi] [ datetime] NULL, [net_transport] [nvarchar](40) NULL, [protocol_type] [nvarchar](40) NULL, [protocol_version] [int] NULL, [encrypt_option] [nvarchar](40) NULL, [auth_scheme] [nvarchar ](40) NULL, [node_affinity] [smallint] NULL, [num_reads] [int] NULL, [num_writes] [int] NULL, [last_read] [datetime] NULL, [last_write] [datetime] NULL, [net_packet_size] [ int] NULL, [client_net_address] [nvarchar](48) NULL, [client_tcp_port] [int] NULL, [local_net_address] [nvarchar](48) NULL, [local_tcp_port] [int] NULL, [connection_id] [uniqueidentifier] NULL [parent_connection_id] [uniqueidentifier] NULL, [most_recent_sql_handle] [varbinary](64) NULL, [LastTSQL] [nvarchar](max) NULL, [transaction_begin_time] [datetime] NOT NULL, [CountTranNotRequest] [tinyint] NOTSessionNotRequest, [CountTranNotRequest] ] [tinyint] NOT NULL, [InsertUTCDate] [datetime] NOT NULL, CONSTRAINT [PK_KillSession] PRIMARY KEY CLUSTERED ( [ID] ASC)DENGAN (PAD_INDEX =OFF, STATISTICS_NORECOMPUTE =OFF, IGNORE_DUP_LOCKS =OFF, LOCKSLOW_ OFF_ AKTIF, ALLOW_PAGE_LOCKS =AKTIF) AKTIF [PRIMARY]) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]GOALTER TABLE [srv].[KillSession] ADD CONSTRAINT [DF_KillSession_InsertUTCDate] DEFAULT (getutcdate()) FOR [InsertpreUTCDate][/expand]
Di sini, semua bidang diambil dari representasi sistem 'sys.dm_exec_sessions' dan 'sys.dm_exec_connections', dan 'InsertUTCDate' menentukan waktu UTC entri dibuat.
Kemudian, untuk menyelesaikan langkah selanjutnya, mari implementasikan prosedur tersimpan [srv].[AutoKillSessionTranBegin] sebagai berikut:
[expand title =”Kode “]
GUNAKAN [DB_NAME]GOSET ANSI_NULLS ONGOSET QUOTED_IDENTIFIER ONGOCREATE PROCEDURE [srv].[AutoKillSessionTranBegin] @minuteOld int, --umur transaksi yang dieksekusi (T min.) @countIsNotRequests int --jumlah kali transaksi tersebut ditempatkan ke dalam tabel (K)ASBEGIN SET NOCOUNT ON; SET TINGKAT ISOLASI TRANSAKSI BACA TANPA KOMITMEN; mendeklarasikan tabel @tbl ( int SessionID, bigint TransactionID, bit IsSessionNotRequest, datetime TransactionBeginTime ); --mengambil informasi (transaksi dan sesinya yang tidak memiliki permintaan, yaitu transaksi yang dimulai dan dilupakan) masukkan ke @tbl ( SessionID, TransactionID, IsSessionNotRequest, TransactionBeginTime ) pilih t.[session_id] sebagai SessionID , t.[transaction_id] sebagai TransactionID , kasus ketika ada(pilih top(1) 1 dari sys.dm_exec_requests sebagai r di mana r.[session_id]=t.[session_id]) lalu 0 lain 1 diakhiri sebagai IsSessionNotRequest , (pilih top(1) ta.[transaction_begin_time ] dari sys.dm_tran_active_transactions sebagai ta di mana ta.[transaction_id]=t.[transaction_id]) sebagai TransactionBeginTime dari sys.dm_tran_session_transactions sebagai t di mana t.[is_user_transaction]=1 dan tidak ada(pilih atas(1) 1 dari sys.dm_exec_exec_ sebagai r di mana r.[transaction_id]=t.[transaction_id]); --menyegarkan tabel yang berisi semua transaksi yang dimulai tanpa permintaan;gabungkan srv.SessionTran sebagai st menggunakan @tbl sebagai t pada st.[SessionID]=t.[SessionID] dan st.[TransactionID]=t.[TransactionID] saat dicocokkan lalu perbarui set [UpdateUTCDate] =getUTCDate() , [CountTranNotRequest] =st.[CountTranNotRequest]+1 , [CountSessionNotRequest] =case when (t.[IsSessionNotRequest]=1) lalu (st.[CountSessionNotRequest]+1) else 0 end , [TransactionBeginTime] =t.[TransactionBeginTime] bila tidak sesuai dengan target lalu masukkan nilai ( [SessionID] ,[TransactionID] ,[TransactionBeginTime] ) nilai ( t.[SessionID] ,t.[TransactionID] ,t.[TransactionBeginTime] ) jika tidak cocok dengan sumbernya, hapus; --daftar sesi yang perlu dihapus (yang berisi transaksi yang terlupakan) mendeklarasikan tabel @kills ( SessionID int ); --детальная ормация архива mendeklarasikan tabel @kills_copy ( SessionID int, TransactionID bigint, CountTranNotRequest tinyint, CountSessionNotRequest tinyint, TransactionBeginTime datetime ) --mengumpulkan sesi yang perlu kita bunuh --sesi memiliki setidaknya satu transaksi yang ditandai tidak memiliki meminta @countIsNotRequests kali --dan sesi ini ditandai sebagai tidak memiliki permintaan aktif dengan jumlah waktu yang sama dimasukkan ke dalam @kills_copy ( SessionID, TransactionID, CountTranNotRequest, CountSessionNotRequest, TransactionBeginTime ) pilih SessionID, TransactionID, CountTranNotRequest, CountSessionNotRequest, TransactionBeginTime dari srv.SessionTranv. di mana [CountTranNotRequest]>[email protected] dan [CountSessionNotRequest]>[email protected] dan [TransactionBeginTime]<=DateAdd(minute,[email protected],GetDate()); --mengarsipkan data yang perlu kita hapus (detail tentang sesi yang akan dihapus, koneksi dan transaksi) INSERT INTO [srv].[KillSession] ([session_id] ,[transaction_id] ,[login_time] ,[host_name] ,[program_name ] ,[host_process_id] ,[client_version] ,[client_interface_name] ,[security_id] ,[login_name] ,[nt_domain] ,[nt_user_name] ,[status] ,[context_info] ,[cpu_time] ,[memory_usage] ,[total_waktu] [total_elapsed_time] ,[endpoint_id] ,[last_request_start_time] ,[last_request_end_time] ,[reads] ,[writes] ,[logical_reads] ,[is_user_process] ,[text_size] ,[bahasa] ,[date_format] ,[date_first] ] ,[arithabort] ,[ansi_null_dflt_on] ,[ansi_defaults] ,[ansi_warnings] ,[ansi_padding] ,[ansi_nulls] ,[concat_null_yields_null] ,[transaction_isolation_level] ,[lock_timeout] ,[deadlock_priority] ,[row_count] ,[nama_sebelumnya] _,[nama_kesalahan] awal last_successful_logon] ,[last_unsuccessful_logon] ,[unsuccessful_logons] ,[group_id] ,[database_id] ,[authenticating_database_id] ,[open_transaction_count] ,[most_recent_session_id] ,[net_transport] ,[col_time_transport] ,[net_transport] ,[auth_scheme] ,[node_affinity] ,[num_reads] ,[num_writes] ,[last_read] ,[last_write] ,[net_packet_size] ,[client_net_address] ,[client_tcp_port] ,[local_n et_address] ,[local_tcp_port] ,[connection_id] ,[parent_connection_id] ,[most_recent_sql_handle] ,[LastTSQL] ,[transaction_begin_time] ,[CountTranNotRequest] ,[CountSessionNotRequest]) pilih ES.Transaction_id ,ksion_id [ES. [login_time] ,ES.[host_name] ,ES.[nama_program] ,ES.[host_process_id] ,ES.[client_version] ,ES.[client_interface_name] ,ES.[security_id] ,ES.[login_name] ,ES.[nt_domain ] ,ES.[nt_user_name] ,ES.[status] ,ES.[context_info] ,ES.[cpu_time] ,ES.[memory_usage] ,ES.[total_scheduled_time] ,ES.[total_elapsed_time] ,ES.[endpoint_id] , ES.[last_request_start_time] ,ES.[last_request_end_time] ,ES.[reads] ,ES.[writes] ,ES.[logical_reads] ,ES.[is_user_process ] ,ES.[text_size] ,ES.[language] ,ES.[date_format] ,ES.[date_first] ,ES.[quoted_identifier] ,ES.[arithabort] ,ES.[ansi_null_dflt_on] ,ES.[ansi_defaults] , ES.[ansi_warnings] ,ES.[ansi_padding] ,ES.[ansi_nulls] ,ES.[concat_null_yields_null] ,ES.[transaction_isolation_level] ,ES.[lock_timeout] ,ES.[deadlock_priority] ,ES.[row_count] ,ES. [prev_error] ,ES.[original_security_id] ,ES.[original_login_name] ,ES.[last_successful_logon] ,ES.[last_unsuccessful_logon] ,ES.[unsuccessful_logons] ,ES.[group_id] ,ES.[database_id] ,ES.[authenticating_database_database] ] ,ES.[open_transaction_count] ,EC.[most_recent_session_id] ,EC.[connect_time] ,EC.[net_transport] ,EC.[protocol_type] ,EC.[protocol_version ] ,EC.[encrypt_option] ,EC.[auth_scheme] ,EC.[node_affinity] ,EC.[num_reads] ,EC.[num_writes] ,EC.[last_read] ,EC.[last_write] ,EC.[net_packet_size] , EC.[client_net_address] ,EC.[client_tcp_port] ,EC.[local_net_address] ,EC.[local_tcp_port] ,EC.[connection_id] ,EC.[parent_connection_id] ,EC.[most_recent_sql_handle] ,(pilih atas(1) teks dari sys.dm_exec_sql_text(EC.[most_recent_sql_handle])) sebagai [LastTSQL] ,kc.[TransactionBeginTime] ,kc.[CountTranNotRequest] ,kc.[CountSessionNotRequest] dari @kills_copy sebagai kc inner join sys.dm_exec_sessions committed .[SessionID]=ES.[session_id] gabung dalam sys.dm_exec_connections EC dengan(readuncommitted) di EC.session_id =ES.session_id; --gathering session masukkan ke @kills ( SessionID ) pilih [SessionID] dari grup @kills_copy oleh [SessionID]; mendeklarasikan @SessionID int; --menghapus sesi while(exists(select top(1) 1 from @kills)) start pilih top(1) @SessionID=[SessionID] from @kills; MULAI COBA EXEC sp_executesql N'kill @SessionID', N'@SessionID INT', @SessionID; AKHIR COBA MULAI TANGKAP AKHIR TANGKAP hapus dari @kills di mana [SessionID][email protected]; akhir pilih st.[SessionID] ,st.[TransactionID] menjadi #tbl dari srv.SessionTran sebagai st di mana st.[CountTranNotRequest]>=250 atau st.[CountSessionNotRequest]>=250 atau ada(pilih atas(1) 1 dari @kills_copy kc di mana kc.[SessionID]=st.[SessionID]); --Menghapus entri yang diproses bersama dengan entri yang tidak dapat dihapus dan telah berada di tabel terlalu lama, hapus dari st dari #tbl sebagai t bagian dalam join srv.SessionTran sebagai st pada t.[SessionID] =st.[SessionID] dan t.[IDTransaksi]=st.[IDTransaksi]; letakkan tabel #tbl;ENDGO[/expand]
Langkah 7 dari algoritme diimplementasikan melalui salah satu dari dua penghitung ini – CountTranNotRequest atau CountSessionNotRequest – mencapai nilai 250.
Hasilnya
Dalam artikel ini, kita telah melihat implementasi proses yang secara otomatis menghapus transaksi yang terlupakan.
Metode ini memungkinkan kita untuk mengotomatisasi proses penghapusan transaksi yang terlupakan. Hal ini mengakibatkan penurunan atau penghentian pertumbuhan fluktuasi dalam pemblokiran yang dihasilkan oleh transaksi tersebut. Jadi, kinerja DBMS terlindungi dari tindakan yang dapat mengakibatkan transaksi yang terlupakan.
Sumber:
» sys.dm_exec_requests
» sys.dm_tran_active_transactions
» sys.dm_tran_session_transactions
» sys.dm_exec_sql_text
» sys.dm_exec_sessions
» sys.dm_exec_sessions
»