চেকডিবির কেন একটি মেমোরি অপ্টিমাইজড টেবিল সহ একটি ডাটাবেসে লেনদেনের লগ ফাইলটি পড়ছে?


16

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 একটি অভ্যন্তরীণ স্ন্যাপশট ব্যবহার করছে।

আমি পড়েছি যে অনির্বাচিত লেনদেন পূর্বাবস্থায় ফেলার জন্য স্ন্যাপশট পুনরুদ্ধার করে :

আন-কমমিটড লেনদেনগুলি নতুনভাবে তৈরি করা ডাটাবেস স্ন্যাপশটে ফিরে আসে কারণ স্ন্যাপশট তৈরি হওয়ার পরে ডেটাবেস ইঞ্জিন পুনরুদ্ধার চালায় (ডাটাবেসে লেনদেন প্রভাবিত হয় না)।

তবে এটি এখনও ব্যাখ্যা করে না যে লগ ফাইলের একটি বড় অংশটি প্রায়শই আমার উত্পাদনের দৃশ্যে (এবং মাঝে মাঝে এখানে প্রদত্ত তিরস্কারে) পড়া হয়। আমি মনে করি না যে আমার অ্যাপটিতে একটি নির্দিষ্ট সময়ে আমার সাথে অনেকগুলি ফ্লাইটের লেনদেন রয়েছে, এবং অবশ্যই এখানে তিরস্কারের কোনও কিছুই নেই।

উত্তর:


10

যদিও এসকিউএল সার্ভার ডকুমেন্টেশনে বলা হয়েছে যে "ইন-মেমোরি" DBCC CHECKDBসারণীযুক্ত ডেটাবেসগুলি স্ন্যাপশটগুলিকে সমর্থন করে না, চেকডবি অপারেশনটি মেমোরি টেবিলগুলিতে স্পর্শ না করে এবং এর জন্য কেবল "অভ্যন্তরীণ" স্ন্যাপশট তৈরি করা যায় এবং স্ন্যাপশটটি কেবল পরিবর্তনগুলি ক্যাপচার করে অন ​​ডিস্ক টেবিল।

সম্ভবত, মাইক্রোসফ্ট ইন-মেমোরি টেবিলগুলির সাথে ডাটাবেসে ব্যবহারকারী-নির্মিত স্ন্যাপশটগুলি প্রতিরোধ করতে বেছে নিয়েছে কারণ স্ন্যাপশটটি স্বাভাবিক, ব্যবহারকারীকেন্দ্রিক, জ্ঞান থেকে সত্যিকার অর্থে একটি সম্পূর্ণ স্ন্যাপশট হওয়ার জন্য তাদের মেমরির কাঠামোগুলি নকল করতে হবে। একটি স্ন্যাপশট জন্য ইন-মেমোরি টেবিল অনুরূপ সহজে সার্ভার মেমরি রান আউট, যা বানাতে পারে না একটি ভাল জিনিস ™

আপনি নিজের জন্য প্রমাণ করতে পারেন যে প্রারম্ভিক ডাটাবেস ডেটা ফাইল চলাকালীন যেখানে থাকে সেখানে ডেটা ফোল্ডারটি দেখে একটি অভ্যন্তরীণ ডিবিসিসি স্ন্যাপশট তৈরি করা হচ্ছে DBCC CHECKDB। যদি কোনও অভ্যন্তরীণ স্ন্যাপশট তৈরি করা হয়, আপনি নামের একটি ফাইল দেখতে পাবেন LogFileRead_Test.mdf_MSSQL_DBCC7(এটি 7ভিন্ন হতে পারে - এটি আপনার ডাটাবেসের জন্য ডাটাবেস আইডি উপস্থাপন করে)।

একবার স্ন্যাপশট ফাইলটি তৈরি হয়ে গেলে, এসবিএল সার্ভারের এটি একটি সামঞ্জস্যপূর্ণ অবস্থায় আনার জন্য ডাটাবেসটিতে পুনরুদ্ধার চালানো প্রয়োজন যা ডিবিসিসি চেকডিডিবি চালানোর জন্য প্রয়োজনীয়। আপনি যে কোনও লগ-রিডিং ক্রিয়াকলাপটি দেখছেন সম্ভবত সেই পুনরুদ্ধারের প্রক্রিয়াটির ফলস্বরূপ। আমি একাধিক DBCC CHECKDBক্রিয়াকলাপের আউটপুট যাচাই করার জন্য একটি দ্রুত কড়া তৈরি করেছি, যা প্রমাণ করে যে যদি চেকডবসের মধ্যে কোনও লেনদেন না হয় তবে লগ-ফাইল রিড নেই।

USE master;
SET IMPLICIT_TRANSACTIONS OFF;
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

CREATE DATABASE [LogFileRead_Test]
ALTER DATABASE [LogFileRead_Test]
MODIFY FILE
(
    NAME = LogFileRead_Test_log,
    SIZE = 128MB
);

ALTER DATABASE [LogFileRead_Test]
ADD FILEGROUP [LatencyTestInMemoryFileGroup] CONTAINS MEMORY_OPTIMIZED_DATA;
ALTER DATABASE [LogFileRead_Test]
ADD FILE 
(
    NAME = [LatencyTestInMemoryFile], 
    FILENAME = 'C:\temp\LogFileRead_Test_SessionStateInMemoryFile'
) TO FILEGROUP [LatencyTestInMemoryFileGroup];
GO

USE LogFileRead_Test;

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);

;WITH src AS (
    SELECT n.Num
    FROM (VALUES (0), (1), (2), (3), (4), (5), (6), (7), (8), (9))n(Num)
)
INSERT INTO [dbo].[InMemoryStuff] (InMemoryId, Created) 
SELECT 'Description' + CONVERT(varchar(30)
        , ((s1.Num * 10000) 
         + (s2.Num * 1000) 
         + (s3.Num * 100) 
         + (s4.Num * 10) 
         + (s5.Num)))
    , GETDATE()
FROM src s1
    CROSS JOIN src s2
    CROSS JOIN src s3
    CROSS JOIN src s4
    CROSS JOIN src s5;
USE master;

DECLARE @cmd nvarchar(max);
DECLARE @msg nvarchar(1000);
DECLARE @l int;
DECLARE @m int;
SET @m = 10;
SET @l = 1;
IF OBJECT_ID(N'tempdb..#vfs', N'U') IS NOT NULL DROP TABLE #vfs;
CREATE TABLE #vfs (
    vfs_run int NOT NULL IDENTITY(1,1) PRIMARY KEY CLUSTERED
    , collection_time datetime2(7)
    , num_of_reads bigint
    , num_of_bytes_read bigint
);

WHILE @l <= @m 
BEGIN
SET @msg = N'loop ' + CONVERT(nvarchar(10), @l);
RAISERROR (@msg, 0, 1) WITH NOWAIT;

SET @cmd = 'USE [LogFileRead_Test];
-- 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'');

DBCC CHECKDB ([LogFileRead_Test]) WITH NO_INFOMSGS, ALL_ERRORMSGS, DATA_PURITY;

-- grab the latest virtual file stats, and compare with the previous capture
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;
';
INSERT INTO #vfs (collection_time, num_of_reads, num_of_bytes_read)
EXEC sys.sp_executesql @cmd;

SET @l += 1;
END

USE master;
SET @cmd = 'USE [master];
ALTER DATABASE [LogFileRead_Test]
SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
DROP DATABASE [LogFileRead_Test];
';
EXEC sys.sp_executesql @cmd;

SELECT *
FROM #vfs
ORDER BY vfs_run;

ফলাফলগুলো:

╔═════════╦═════════════════════════════╦═════════ ═════╦═══════════════════╗
║ vfs_run ║ সংগ্রহ_কাল time num_of_reads ║ num_of_bytes_read
╠═════════╬═════════════════════════════╬═════════ ═════╬═══════════════════╣
║ 1 ║ 2018-04-06 15: 53: 37.6566667 ║ 1 ║ 491520 ║
║ 2 ║ 2018-04-06 15: 53: 37.8300000 ║ 0 ║ 0 ║
║ 3 ║ 2018-04-06 15: 53: 38.0166667 ║ 0 ║ 0 ║
║ 4 ║ 2018-04-06 15: 53: 38.1866667 ║ 0 ║ 0 ║
║ 5 ║ 2018-04-06 15: 53: 38.3766667 ║ 0 ║ 0 ║
║ 6 ║ 2018-04-06 15: 53: 38.5633333 ║ 0 ║ 0 ║
║ 7 ║ 2018-04-06 15: 53: 38.7333333 ║ 0 ║ 0 ║
║ 8 ║ 2018-04-06 15: 53: 38.9066667 ║ 0 ║ 0 ║
║ 9 ║ 2018-04-06 15: 53: 39.0933333 ║ 0 ║ 0 ║
║ 10 ║ 2018-04-06 15: 53: 39.2800000 ║ 0 ║ 0 ║
╚═════════╩═════════════════════════════╩═════════ ═════╩═══════════════════╝

এছাড়াও, পরীক্ষার টেবিলে ডেটা inোকানোর জন্য কোনও আরবিআর পদ্ধতির পরিবর্তে আপনি নীচের মত একটি সাধারণ সেট-ভিত্তিক পদ্ধতির ব্যবহার করতে চাইতে পারেন:

;WITH src AS (
    SELECT n.Num
    FROM (VALUES (0), (1), (2), (3), (4), (5), (6), (7), (8), (9))n(Num)
)
INSERT INTO [dbo].[InMemoryStuff] (InMemoryId, Created) 
SELECT 'Description' + CONVERT(varchar(30)
     , ((s1.Num * 10000) 
      + (s2.Num * 1000) 
      + (s3.Num * 100) 
      + (s4.Num * 10) 
      + (s5.Num)))
    , GETDATE()
FROM src s1
    CROSS JOIN src s2
    CROSS JOIN src s3
    CROSS JOIN src s4
    CROSS JOIN src s5;

আমার পরীক্ষায়, এটি 3 সেকেন্ডের নীচে টেবিলটি পূরণ করে, যেখানে আরবিআর পদ্ধতির ক্ষেত্রে অনেক বেশি সময় লাগে । এছাড়াও, আপনার কোডে দুর্দান্ত মন্তব্যগুলি আমাকে লোল করেছে।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.