tl; dr : মেমরি অপ্টিমাইজড টেবিল সহ কোনও ব্যবহারকারী ডাটাবেসের জন্য লেনদেনের লগ কেন চেকডিবিবি পড়ছে?
এটি প্রদর্শিত হয় যে CHECKDB ব্যবহারকারী ডাটাবেসের লেনদেনের লগ ফাইলটি পড়ছে যখন এটি আমার একটি ডাটাবেস-বিশেষত, এমন একটি ডাটাবেস যা মেমরির ওয়ালটিপি টেবিল ব্যবহার করে তা পরীক্ষা করে।
এই ডাটাবেসের জন্য CHECKDB এখনও যুক্তিসঙ্গত পরিমাণে শেষ হয়, তাই আমি বেশিরভাগভাবে আচরণ সম্পর্কে আগ্রহী; তবে অবশ্যই এই উদাহরণস্বরূপ সমস্ত ডাটাবেসের CHECKDB এর জন্য দীর্ঘতম সময়কাল।
পল Randal এর মহাকাব্যিক ধরে খুঁজছি ইন " যে কোনো দৃষ্টিকোণ থেকে CHECKDB: সব CHECKDB পর্যায়ে সম্পূর্ণ বিবরণ, " আমি দেখতে যে প্রাক এসকিউএল 2005 CHECKDB করতে ব্যবহৃত অর্ডার ডেটাবেসের একটি সামঞ্জস্যপূর্ণ ভিউ করতে লগ ইন করুন পড়ুন। তবে এটি যেহেতু 2016, এটি অভ্যন্তরীণ ডাটাবেস স্ন্যাপশট ব্যবহার করে।
তবে স্ন্যাপশটের জন্য পূর্বশর্তগুলির মধ্যে একটি হ'ল:
উত্স ডাটাবেসে অবশ্যই একটি MEMORY_OPTIMIZED_DATA ফাইলগোষ্ঠী থাকা উচিত
আমার ব্যবহারকারী ডাটাবেসের মধ্যে এই ফাইলগ্রুপগুলির মধ্যে একটি রয়েছে, সুতরাং দেখে মনে হচ্ছে স্ন্যাপশটগুলি টেবিলের বাইরে রয়েছে।
CHECKDB ডক্স অনুসারে :
যদি একটি স্ন্যাপশট তৈরি করা যায় না, বা ট্যাবলক নির্দিষ্ট করা থাকে, ডিবিসিসি CHECKDB প্রয়োজনীয় ধারাবাহিকতা পেতে লকগুলি অর্জন করে। এই ক্ষেত্রে, বরাদ্দ চেকগুলি সম্পাদনের জন্য একটি একচেটিয়া ডাটাবেস লক প্রয়োজন, এবং টেবিল চেকগুলি সম্পাদন করতে ভাগ করা টেবিল লকগুলি প্রয়োজন।
ঠিক আছে, সুতরাং আমরা স্ন্যাপশটের পরিবর্তে ডাটাবেস এবং টেবিল লক করছি। তবে কেন এটি লেনদেনের লগটি পড়তে হয় তা এখনও ব্যাখ্যা করে না। তাহলে কি দেয়?
আমি দৃশ্যের পুনরুত্পাদন করতে নীচে একটি স্ক্রিপ্ট সরবরাহ করেছি। এটি sys.dm_io_virtual_file_stats
লগ ফাইলের পঠন সনাক্ত করতে ব্যবহার করে।
নোট করুন যে বেশিরভাগ সময় এটি লগের একটি ছোট অংশ (480 কেবি) পড়ে, তবে এটি মাঝে মাঝে আরও বেশি পরিমাণে পড়ে (48.2 এমবি)। আমার উত্পাদনের দৃশ্যে, আমরা যখন CHECKDB চালাই তখন প্রতি রাতে মধ্যরাতে এটি বেশিরভাগ লগ ফাইল (2 জিবি ফাইলের মধ্যে 1.3 গিগাবাইট) পড়ে reads
স্ক্রিপ্টটি দিয়ে আমি এ পর্যন্ত যে ফলাফলগুলি পেয়েছি তার উদাহরণ এখানে:
collection_time num_of_reads num_of_bytes_read
2018-04-04 15:12:29.203 106 50545664
অথবা এটা:
collection_time num_of_reads num_of_bytes_read
2018-04-04 15:25:14.227 1 491520
আমি যদি নিয়মিত টেবিলের সাহায্যে মেমরি অপটিমাইজড অবজেক্টগুলিকে প্রতিস্থাপন করি তবে আউটপুটটি এমন দেখাচ্ছে:
collection_time num_of_reads num_of_bytes_read
2018-04-04 15:21:03.207 0 0
CHECKDB লগ ফাইলটি পড়ছে কেন? এবং বিশেষত, কেন এটি মাঝেমধ্যে লগ ফাইলের অনেক বড় অংশ পড়ে?
আসল লিপিটি এখানে:
-- let's have a fresh DB
USE [master];
IF (DB_ID(N'LogFileRead_Test') IS NOT NULL)
BEGIN
ALTER DATABASE [LogFileRead_Test]
SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
DROP DATABASE [LogFileRead_Test];
END
GO
CREATE DATABASE [LogFileRead_Test]
GO
ALTER DATABASE [LogFileRead_Test]
MODIFY FILE
(
NAME = LogFileRead_Test_log,
SIZE = 128MB
);
-- Hekaton-yeah, I want memory optimized data
GO
ALTER DATABASE [LogFileRead_Test]
ADD FILEGROUP [LatencyTestInMemoryFileGroup] CONTAINS MEMORY_OPTIMIZED_DATA;
GO
ALTER DATABASE [LogFileRead_Test]
ADD FILE
(
NAME = [LatencyTestInMemoryFile],
FILENAME = 'C:\Program Files\Microsoft SQL Server\MSSQL13.SQL2016\MSSQL\DATA\LogFileRead_Test_SessionStateInMemoryFile'
) TO FILEGROUP [LatencyTestInMemoryFileGroup];
GO
USE [LogFileRead_Test]
GO
CREATE TYPE [dbo].[InMemoryIdTable] AS TABLE (
[InMemoryId] NVARCHAR (88) COLLATE Latin1_General_100_BIN2 NOT NULL,
PRIMARY KEY NONCLUSTERED HASH ([InMemoryId]) WITH (BUCKET_COUNT = 240))
WITH (MEMORY_OPTIMIZED = ON);
GO
CREATE TABLE [dbo].[InMemoryStuff] (
[InMemoryId] NVARCHAR (88) COLLATE Latin1_General_100_BIN2 NOT NULL,
[Created] DATETIME2 (7) NOT NULL,
CONSTRAINT [PK_InMemoryStuff_InMemoryId] PRIMARY KEY NONCLUSTERED HASH ([InMemoryId]) WITH (BUCKET_COUNT = 240)
)
WITH (MEMORY_OPTIMIZED = ON);
GO
-- RBAR is the new black (we need some logs to read)
declare @j int = 0;
while @j < 100000
begin
INSERT INTO [dbo].[InMemoryStuff](InMemoryId, Created) VALUES ('Description' + CAST(@j as varchar), GETDATE());
set @j = @j + 1;
end
-- grab a baseline of virtual file stats to be diff'd later
select f.num_of_reads, f.num_of_bytes_read
into #dm_io_virtual_file_stats
from sys.dm_io_virtual_file_stats(default, default) f
where database_id = db_id('LogFileRead_Test') and file_id = FILE_IDEX('LogFileRead_Test_log');
-- hands off my log file, CHECKDB!
GO
DBCC CHECKDB ([LogFileRead_Test]) WITH NO_INFOMSGS, ALL_ERRORMSGS, DATA_PURITY;
-- grab the latest virtual file stats, and compare with the previous capture
GO
select f.num_of_reads, f.num_of_bytes_read
into #checkdb_stats
from sys.dm_io_virtual_file_stats(default, default) f
where database_id = db_id('LogFileRead_Test') and file_id = FILE_IDEX('LogFileRead_Test_log');
select
collection_time = GETDATE()
, num_of_reads = - f.num_of_reads + t.num_of_reads
, num_of_bytes_read = - f.num_of_bytes_read + t.num_of_bytes_read
into #dm_io_virtual_file_stats_diff
from #dm_io_virtual_file_stats f, #checkdb_stats t;
drop table #checkdb_stats;
drop table #dm_io_virtual_file_stats;
-- CHECKDB ignored my comment
select collection_time, num_of_reads, num_of_bytes_read
from #dm_io_virtual_file_stats_diff d
order by d.collection_time;
drop table #dm_io_virtual_file_stats_diff;
-- I was *not* raised in a barn
USE [master];
ALTER DATABASE [LogFileRead_Test]
SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
DROP DATABASE [LogFileRead_Test];
যেহেতু এই রেপ্রোটি সাধারণত 1 বা 106 লগ ফাইল পাঠ করে, তাই আমি ভেবেছিলাম যে আমি 1-এ একটি ফাইল_রেড এবং ফাইল_রেড_প্রাপ্ত বর্ধিত ইভেন্ট সেশন দিয়ে খনন করব।
name timestamp mode offset database_id file_id size duration
file_read 2018-04-06 10:51:11.1098141 Contiguous 72704 9 2 0 NULL
file_read_completed 2018-04-06 10:51:11.1113345 Contiguous 72704 9 2 491520 1
এবং DBCC LOGINFO()
সেই অফসেটগুলিতে এবং এরকম প্রসঙ্গের জন্য এখানে ভিএলএফ বিশদ ( ) রয়েছে:
RecoveryUnitId FileId FileSize StartOffset FSeqNo Status Parity CreateLSN
0 2 2031616 8192 34 2 64 0
0 2 2031616 2039808 35 2 64 0
0 2 2031616 4071424 36 2 64 0
0 2 2285568 6103040 37 2 64 0
0 2 15728640 8388608 38 2 64 34000000005200001
0 2 15728640 24117248 39 2 64 34000000005200001
0 2 15728640 39845888 40 2 64 34000000005200001
0 2 15728640 55574528 0 0 0 34000000005200001
0 2 15728640 71303168 0 0 0 34000000005200001
0 2 15728640 87031808 0 0 0 34000000005200001
0 2 15728640 102760448 0 0 0 34000000005200001
0 2 15728640 118489088 0 0 0 34000000005200001
সুতরাং, CHECKDB অপারেশন:
- প্রথম ভিএলএফ-তে 63 কেবি (64,512 বাইট) পড়া শুরু করে,
- 480 কেবি (491,520 বাইট) পড়ুন এবং
- হয়নি না পড়া VLF শেষ 1441 কিলোবাইট (1,475,584 বাইটস)
আমি কলস্ট্যাকগুলি ক্যাপচার করেছি, যদি তারা সহায়ক হয়।
ফাইল_ড্রেড কলস্ট্যাক:
(00007ffd`999a0860) sqlmin!XeSqlPkg::file_read::Publish+0x1dc | (00007ffd`999a0b40) sqlmin!XeSqlPkg::file_read_enqueued::Publish
(00007ffd`9a825e30) sqlmin!FireReadEvent+0x118 | (00007ffd`9a825f60) sqlmin!FireReadEnqueuedEvent
(00007ffd`9980b500) sqlmin!FCB::AsyncRead+0x74d | (00007ffd`9980b800) sqlmin!FCB::AsyncReadInternal
(00007ffd`9970e9d0) sqlmin!SQLServerLogMgr::LogBlockReadAheadAsync+0x6a6 | (00007ffd`9970ec00) sqlmin!LBH::Destuff
(00007ffd`9970a6d0) sqlmin!LogConsumer::GetNextLogBlock+0x1591 | (00007ffd`9970ab70) sqlmin!LogPoolPrivateCacheBufferMgr::Lookup
(00007ffd`9a9fcbd0) sqlmin!SQLServerLogIterForward::GetNext+0x258 | (00007ffd`9a9fd2d0) sqlmin!SQLServerLogIterForward::GetNextBlock
(00007ffd`9aa417f0) sqlmin!SQLServerCOWLogIterForward::GetNext+0x2b | (00007ffd`9aa418c0) sqlmin!SQLServerCOWLogIterForward::StartScan
(00007ffd`9aa64210) sqlmin!RecoveryMgr::AnalysisPass+0x83b | (00007ffd`9aa65100) sqlmin!RecoveryMgr::AnalyzeLogRecord
(00007ffd`9aa5ed50) sqlmin!RecoveryMgr::PhysicalRedo+0x233 | (00007ffd`9aa5f790) sqlmin!RecoveryMgr::PhysicalCompletion
(00007ffd`9aa7fd90) sqlmin!RecoveryUnit::PhysicalRecovery+0x358 | (00007ffd`9aa802c0) sqlmin!RecoveryUnit::CompletePhysical
(00007ffd`9a538b90) sqlmin!StartupCoordinator::NotifyPhaseStart+0x3a | (00007ffd`9a538bf0) sqlmin!StartupCoordinator::NotifyPhaseEnd
(00007ffd`9a80c430) sqlmin!DBTABLE::ReplicaCreateStartup+0x2f4 | (00007ffd`9a80c820) sqlmin!DBTABLE::RefreshPostRecovery
(00007ffd`9a7ed0b0) sqlmin!DBMgr::SyncAndLinkReplicaRecoveryPhase+0x890 | (00007ffd`9a7edff0) sqlmin!DBMgr::DetachDB
(00007ffd`9a7f2cd0) sqlmin!DBMgr::CreatePhasedTransientReplica+0x869 | (00007ffd`9a7f3630) sqlmin!DBMgr::StrandTransientReplica
(00007ffd`9a7f2ae0) sqlmin!DBMgr::CreateTransientReplica+0x118 | (00007ffd`9a7f2cd0) sqlmin!DBMgr::CreatePhasedTransientReplica
(00007ffd`99ec6d30) sqlmin!DBDDLAgent::CreateReplica+0x1b5 | (00007ffd`99ec6f90) sqlmin!FSystemDatabase
(00007ffd`9abaaeb0) sqlmin!UtilDbccCreateReplica+0x82 | (00007ffd`9abab000) sqlmin!UtilDbccDestroyReplica
(00007ffd`9ab0d7e0) sqlmin!UtilDbccCheckDatabase+0x994 | (00007ffd`9ab0ffd0) sqlmin!UtilDbccRetainReplica
(00007ffd`9ab0cfc0) sqlmin!DbccCheckDB+0x22d | (00007ffd`9ab0d380) sqlmin!DbccCheckFilegroup
(00007ffd`777379c0) sqllang!DbccCommand::Execute+0x193 | (00007ffd`77737d70) sqllang!DbccHelp
(00007ffd`777e58d0) sqllang!CStmtDbcc::XretExecute+0x889 | (00007ffd`777e6250) sqllang!UtilDbccSetPermissionFailure
(00007ffd`76b02eb0) sqllang!CMsqlExecContext::ExecuteStmts<1,1>+0x40d | (00007ffd`76b03410) sqllang!CSQLSource::CleanupCompileXactState
(00007ffd`76b03a60) sqllang!CMsqlExecContext::FExecute+0xa9e | (00007ffd`76b043d0) sqllang!CCacheObject::Release
(00007ffd`76b03430) sqllang!CSQLSource::Execute+0x981 | (00007ffd`76b039b0) sqllang!CSQLLock::Cleanup
ফাইল_ড্রেড_কম্পটেড কলস্ট্যাক:
(00007ffd`99995cc0) sqlmin!XeSqlPkg::file_read_completed::Publish+0x1fc | (00007ffd`99995fe0) sqlmin!XeSqlPkg::file_write_completed::Publish
(00007ffd`9a826630) sqlmin!FireIoCompletionEventLong+0x227 | (00007ffd`9a8269c0) sqlmin!IoRequestDispenser::Dump
(00007ffd`9969bee0) sqlmin!FCB::IoCompletion+0x8e | (00007ffd`9969c180) sqlmin!IoRequestDispenser::Put
(00007ffd`beaa11e0) sqldk!IOQueue::CheckForIOCompletion+0x426 | (00007ffd`beaa1240) sqldk!SystemThread::GetCurrentId
(00007ffd`beaa15b0) sqldk!SOS_Scheduler::SwitchContext+0x173 | (00007ffd`beaa18a0) sqldk!SOS_Scheduler::Switch
(00007ffd`beaa1d00) sqldk!SOS_Scheduler::SuspendNonPreemptive+0xd3 | (00007ffd`beaa1db0) sqldk!SOS_Scheduler::ResumeNoCuzz
(00007ffd`99641720) sqlmin!EventInternal<SuspendQueueSLock>::Wait+0x1e7 | (00007ffd`99641ae0) sqlmin!SOS_DispatcherPool<DispatcherWorkItem,DispatcherWorkItem,SOS_DispatcherQueue<DispatcherWorkItem,0,DispatcherWorkItem>,DispatcherPoolConfig,void * __ptr64>::GetDispatchers
(00007ffd`9aa437c0) sqlmin!SQLServerLogMgr::CheckLogBlockReadComplete+0x1e6 | (00007ffd`9aa44670) sqlmin!SQLServerLogMgr::ValidateBlock
(00007ffd`9970a6d0) sqlmin!LogConsumer::GetNextLogBlock+0x1b37 | (00007ffd`9970ab70) sqlmin!LogPoolPrivateCacheBufferMgr::Lookup
(00007ffd`9a9fcbd0) sqlmin!SQLServerLogIterForward::GetNext+0x258 | (00007ffd`9a9fd2d0) sqlmin!SQLServerLogIterForward::GetNextBlock
(00007ffd`9aa417f0) sqlmin!SQLServerCOWLogIterForward::GetNext+0x2b | (00007ffd`9aa418c0) sqlmin!SQLServerCOWLogIterForward::StartScan
(00007ffd`9aa64210) sqlmin!RecoveryMgr::AnalysisPass+0x83b | (00007ffd`9aa65100) sqlmin!RecoveryMgr::AnalyzeLogRecord
(00007ffd`9aa5ed50) sqlmin!RecoveryMgr::PhysicalRedo+0x233 | (00007ffd`9aa5f790) sqlmin!RecoveryMgr::PhysicalCompletion
(00007ffd`9aa7fd90) sqlmin!RecoveryUnit::PhysicalRecovery+0x358 | (00007ffd`9aa802c0) sqlmin!RecoveryUnit::CompletePhysical
(00007ffd`9a538b90) sqlmin!StartupCoordinator::NotifyPhaseStart+0x3a | (00007ffd`9a538bf0) sqlmin!StartupCoordinator::NotifyPhaseEnd
(00007ffd`9a80c430) sqlmin!DBTABLE::ReplicaCreateStartup+0x2f4 | (00007ffd`9a80c820) sqlmin!DBTABLE::RefreshPostRecovery
(00007ffd`9a7ed0b0) sqlmin!DBMgr::SyncAndLinkReplicaRecoveryPhase+0x890 | (00007ffd`9a7edff0) sqlmin!DBMgr::DetachDB
(00007ffd`9a7f2cd0) sqlmin!DBMgr::CreatePhasedTransientReplica+0x869 | (00007ffd`9a7f3630) sqlmin!DBMgr::StrandTransientReplica
(00007ffd`9a7f2ae0) sqlmin!DBMgr::CreateTransientReplica+0x118 | (00007ffd`9a7f2cd0) sqlmin!DBMgr::CreatePhasedTransientReplica
(00007ffd`99ec6d30) sqlmin!DBDDLAgent::CreateReplica+0x1b5 | (00007ffd`99ec6f90) sqlmin!FSystemDatabase
(00007ffd`9abaaeb0) sqlmin!UtilDbccCreateReplica+0x82 | (00007ffd`9abab000) sqlmin!UtilDbccDestroyReplica
(00007ffd`9ab0d7e0) sqlmin!UtilDbccCheckDatabase+0x994 | (00007ffd`9ab0ffd0) sqlmin!UtilDbccRetainReplica
(00007ffd`9ab0cfc0) sqlmin!DbccCheckDB+0x22d | (00007ffd`9ab0d380) sqlmin!DbccCheckFilegroup
(00007ffd`777379c0) sqllang!DbccCommand::Execute+0x193 | (00007ffd`77737d70) sqllang!DbccHelp
এই স্ট্যাকট্রেসগুলি ম্যাক্সের উত্তরের সাথে সম্পর্কিত যা ইঙ্গিত করে যে হেকাটন টেবিলগুলির উপস্থিতি সত্ত্বেও CHECKDB একটি অভ্যন্তরীণ স্ন্যাপশট ব্যবহার করছে।
আমি পড়েছি যে অনির্বাচিত লেনদেন পূর্বাবস্থায় ফেলার জন্য স্ন্যাপশট পুনরুদ্ধার করে :
আন-কমমিটড লেনদেনগুলি নতুনভাবে তৈরি করা ডাটাবেস স্ন্যাপশটে ফিরে আসে কারণ স্ন্যাপশট তৈরি হওয়ার পরে ডেটাবেস ইঞ্জিন পুনরুদ্ধার চালায় (ডাটাবেসে লেনদেন প্রভাবিত হয় না)।
তবে এটি এখনও ব্যাখ্যা করে না যে লগ ফাইলের একটি বড় অংশটি প্রায়শই আমার উত্পাদনের দৃশ্যে (এবং মাঝে মাঝে এখানে প্রদত্ত তিরস্কারে) পড়া হয়। আমি মনে করি না যে আমার অ্যাপটিতে একটি নির্দিষ্ট সময়ে আমার সাথে অনেকগুলি ফ্লাইটের লেনদেন রয়েছে, এবং অবশ্যই এখানে তিরস্কারের কোনও কিছুই নেই।