এই প্রশ্নটি এই ফোরামের থ্রেডের সাথে সম্পর্কিত ।
আমার ওয়ার্কস্টেশনে এসকিউএল সার্ভার ২০০৮ বিকাশকারী সংস্করণ এবং একটি এন্টারপ্রাইজ সংস্করণ দ্বি-নোড ভার্চুয়াল মেশিন ক্লাস্টারে যেখানে আমি "আলফা ক্লাস্টার" উল্লেখ করেছি Run
ভের্বাইনারি (সর্বাধিক) কলাম সহ সারিগুলি মুছতে সময় লাগে time কলামের ডেটার দৈর্ঘ্যের সাথে সরাসরি সম্পর্কিত। এটি প্রথমে স্বজ্ঞাত মনে হতে পারে তবে তদন্তের পরে এসকিউএল সার্ভারটি কীভাবে সাধারণভাবে সারিগুলি মুছে ফেলবে এবং এই জাতীয় ডেটা নিয়ে ডিল করে তা বোঝার সাথে আমার সংঘাত হয়।
সমস্যাটি একটি মুছে ফেলা টাইমআউট (> 30 সেকেন্ড) সমস্যা থেকে উদ্ভূত হয়েছে যা আমরা আমাদের। নেট ওয়েব অ্যাপ্লিকেশনটিতে দেখছি, তবে আমি এই আলোচনার জন্য এটি সহজ করে তুলেছি।
যখন একটি রেকর্ড মুছে ফেলা হয়, এসকিউএল সার্ভার এটিকে লভেন্তি সম্পাদনের পরে পরবর্তী সময়ে ঘোস্ট ক্লিনআপ টাস্ক দ্বারা পরিষ্কার করা ভূত হিসাবে চিহ্নিত করে ( পল রান্ডালের ব্লগ দেখুন ) see যথাক্রমে 16 কেবি, 4 এমবি এবং 50 এমবি ডেটা সহ একটি বর্ণের (সর্বাধিক) কলামে তিনটি সারি মুছে ফেলা একটি পরীক্ষায়, আমি এই পৃষ্ঠায় ডেটা-সারি অংশের পাশাপাশি লেনদেনে দেখছি লগ ইন করুন।
আমার কাছে যেটি অদ্ভুত বলে মনে হচ্ছে তা হ'ল মুছে ফেলার সময় সমস্ত লওবি ডেটা পৃষ্ঠায় এক্স লক স্থাপন করা হয় এবং পৃষ্ঠাগুলি পিএফএসে বিচ্ছিন্ন হয়। আমি এটি লেনদেনের লগের পাশাপাশি ডিএমভি ( ) sp_lock
এর ফলাফলগুলিতে দেখতে পাচ্ছি । dm_db_index_operational_stats
page_lock_count
যদি সেই পৃষ্ঠাগুলি ইতিমধ্যে বাফার ক্যাশে না থাকে তবে এটি আমার ওয়ার্কস্টেশন এবং আমাদের আলফা ক্লাস্টারে একটি I / O বাধা সৃষ্টি করে। প্রকৃতপক্ষে, page_io_latch_wait_in_ms
একই ডিএমভি থেকে প্রাপ্তগুলি কার্যত মুছার পুরো সময়কাল, এবং page_io_latch_wait_count
লক করা পৃষ্ঠাগুলির সংখ্যার সাথে সঙ্গতিপূর্ণ। আমার ওয়ার্কস্টেশনে 50 এমবি ফাইলের জন্য, এটি খালি বাফার ক্যাশে ( checkpoint
/ dbcc dropcleanbuffers
) দিয়ে শুরু করার সময় 3 সেকেন্ডেরও বেশি অনুবাদ হয় এবং আমার কোনও সন্দেহ নেই যে এটি ভারী খণ্ডন ও লোডের জন্য আরও দীর্ঘতর হবে।
আমি নিশ্চিত করার চেষ্টা করেছি যে এটি কেবল সময় নেওয়ার সময় ক্যাশে স্থান বরাদ্দ ছিল না। আমি checkpoint
এসকিউএল সার্ভার প্রক্রিয়াতে বরাদ্দকৃত পদ্ধতির পরিবর্তে মুছে ফেলা চালানোর আগে অন্যান্য সারি থেকে 2 জিবি ডেটা পড়েছি । এটি বৈধ পরীক্ষা কিনা তা নিশ্চিত নন, যেহেতু আমি জানি না যে এসকিউএল সার্ভার কীভাবে ডেটাটি চারপাশে পরিবর্তন করে। আমি ধরে নিয়েছিলাম এটি সর্বদা নতুনটির পক্ষে পুরানোদের সরিয়ে দেবে।
আরও, এটি পৃষ্ঠাগুলিও পরিবর্তন করে না। এটি আমি দেখতে পাচ্ছি dm_os_buffer_descriptors
। পৃষ্ঠাগুলি মুছে ফেলার পরে পরিষ্কার হয়, পরিবর্তিত পৃষ্ঠাগুলির সংখ্যা তিনটি ছোট, মাঝারি এবং বড় মুছে ফেলার জন্য 20 এর চেয়ে কম। আমি DBCC PAGE
পৃষ্ঠাগুলির স্যাম্পলিংয়ের জন্য আউটপুটটিও তুলনা করেছি এবং কোনও পরিবর্তন হয়নি (কেবলমাত্র ALLOCATED
পিটিএস থেকে বিটটি সরানো হয়েছিল)। এটি কেবল তাদের deallocates।
পৃষ্ঠার অনুসন্ধান / deallocations সমস্যাটি সৃষ্টি করছে তা আরও প্রমাণ করার জন্য, আমি ভ্যানিলা ভের্বিনারি (সর্বাধিক) এর পরিবর্তে ফাইল স্ট্রিম কলাম ব্যবহার করে একই পরীক্ষার চেষ্টা করেছি। মুছে ফেলাগুলি LOB আকার নির্বিশেষে স্থির সময় ছিল।
সুতরাং, প্রথম আমার একাডেমিক প্রশ্ন:
- এক্স-লক করার জন্য এসকিউএল সার্ভারকে সমস্ত LOB ডেটা পৃষ্ঠাগুলি অনুসন্ধান করার দরকার নেই কেন? লকগুলি কীভাবে স্মৃতিতে উপস্থাপিত হয় (কোনওভাবে পৃষ্ঠায় সঞ্চিত) তার একটি বিবরণ কি এটি? এটি সম্পূর্ণরূপে ক্যাশেড না থাকলে আই / ও প্রভাব ডেটা আকারের উপর দৃ strongly়ভাবে নির্ভর করে।
- এক্স কেন এগুলি লক করে, কেবল তাদের হ্রাস করতে? ডিলোকেশনটির নিজেরাই পৃষ্ঠাগুলি সংশোধন করার প্রয়োজন নেই বলেই কেবল ইন-সারি অংশের সাথে সূচক পাতার তালাবদ্ধ করা কি যথেষ্ট নয়? লকটি সুরক্ষা দেয় এমন এলওবি ডেটা পাওয়ার কী অন্য কোনও উপায় আছে?
- এই ধরণের কাজের জন্য ইতিমধ্যে একটি ব্যাকগ্রাউন্ড টাস্ক নিবেদিত রয়েছে কেন, কেন পৃষ্ঠাগুলি একেবারে আপ্লুত করবেন?
এবং সম্ভবত আরও গুরুত্বপূর্ণ, আমার ব্যবহারিক প্রশ্ন:
- মুছে ফেলা আলাদাভাবে কাজ করার কোনও উপায় আছে কি? আমার লক্ষ্য হ'ল ফাইল স্ট্রিমের মতো আকারের নির্বিশেষে ধ্রুবক সময় মুছে ফেলা হয়, যেখানে সত্যতার পরে পটভূমিতে কোনও ক্লিনআপ ঘটে। এটা কি কনফিগারেশন জিনিস? আমি কি অদ্ভুতভাবে জিনিসগুলি সঞ্চয় করছি?
বর্ণিত পরীক্ষাটি পুনরুত্পাদন করার পদ্ধতি এখানে (এসএসএমএস ক্যোয়ারী উইন্ডোর মাধ্যমে সম্পাদিত):
CREATE TABLE [T] (
[ID] [uniqueidentifier] NOT NULL PRIMARY KEY,
[Data] [varbinary](max) NULL
)
DECLARE @SmallID uniqueidentifier
DECLARE @MediumID uniqueidentifier
DECLARE @LargeID uniqueidentifier
SELECT @SmallID = NEWID(), @MediumID = NEWID(), @LargeID = NEWID()
-- May want to keep these IDs somewhere so you can use them in the deletes without var declaration
INSERT INTO [T] VALUES (@SmallID, CAST(REPLICATE(CAST('a' AS varchar(max)), 16 * 1024) AS varbinary(max)))
INSERT INTO [T] VALUES (@MediumID, CAST(REPLICATE(CAST('a' AS varchar(max)), 4 * 1024 * 1024) AS varbinary(max)))
INSERT INTO [T] VALUES (@LargeID, CAST(REPLICATE(CAST('a' AS varchar(max)), 50 * 1024 * 1024) AS varbinary(max)))
-- Do this before test
CHECKPOINT
DBCC DROPCLEANBUFFERS
BEGIN TRAN
-- Do one of these deletes to measure results or profile
DELETE FROM [T] WHERE ID = @SmallID
DELETE FROM [T] WHERE ID = @MediumID
DELETE FROM [T] WHERE ID = @LargeID
-- Do this after test
ROLLBACK
আমার ওয়ার্কস্টেশনে মুছে ফেলা প্রোফাইলগুলি থেকে এখানে কিছু ফলাফল:
| কলামের প্রকার | মাপ মুছুন | সময়কাল (এমএস) | পড়া | লিখেছেন | সিপিইউ | -------------------------------------------------- ------------------ | ভারবাইনারি | 16 কেবি | 40 | 13 | 2 | 0 | | ভারবাইনারি | 4 এমবি | 952 | 2318 | 2 | 0 | | ভারবাইনারি | 50 এমবি | 2976 | 28594 | 1 | 62 | -------------------------------------------------- ------------------ | ফাইলস্ট্রিম | 16 কেবি | 1 | 12 | 1 | 0 | | ফাইলস্ট্রিম | 4 এমবি | 0 | 9 | 0 | 0 | | ফাইলস্ট্রিম | 50 এমবি | 1 | 9 | 0 | 0 |
এর পরিবর্তে আমরা কেবল ফাইল স্ট্রিম ব্যবহার করতে পারি না কারণ:
- আমাদের ডেটা আকারের বিতরণ এটির ওয়ারেন্ট দেয় না।
- অনুশীলনে, আমরা অনেক অংশে ডেটা যুক্ত করি এবং ফাইল স্ট্রিম আংশিক আপডেটগুলি সমর্থন করে না। আমাদের এটি প্রায় নকশা করা প্রয়োজন।
আপডেট 1
একটি তত্ত্ব পরীক্ষা করেছেন যে মুছার অংশ হিসাবে লেনদেনের লগতে ডেটা লেখা হচ্ছে এবং এটি মনে হয় না। আমি কি এটির জন্য ভুল পরীক্ষা করছি? নিচে দেখ.
SELECT MAX([Current LSN]) FROM fn_dblog(NULL, NULL)
--0000002f:000001d9:0001
BEGIN TRAN
DELETE FROM [T] WHERE ID = @ID
SELECT
SUM(
DATALENGTH([RowLog Contents 0]) +
DATALENGTH([RowLog Contents 1]) +
DATALENGTH([RowLog Contents 3]) +
DATALENGTH([RowLog Contents 4])
) [RowLog Contents Total],
SUM(
DATALENGTH([Log Record])
) [Log Record Total]
FROM fn_dblog(NULL, NULL)
WHERE [Current LSN] > '0000002f:000001d9:0001'
5 এমবি আকারের ফাইলের জন্য, এটি ফিরে আসল 1651 | 171860
।
তদ্ব্যতীত, আমি প্রত্যাশা করব যে লগগুলিতে ডেটা লিখিত থাকলে পৃষ্ঠাগুলি নিজেই নোংরা হবে। কেবল ডিলোকেশনগুলি লগ করা হয়েছে বলে মনে হয়, যা মুছার পরে কী নোংরা তা মেলে।
আপডেট 2
আমি পল র্যান্ডাল থেকে একটি প্রতিক্রিয়া পেয়েছিলাম। তিনি এ সত্যটি নিশ্চিত করে বলেছেন যে গাছটি পেরোনোর জন্য এবং কোন পৃষ্ঠাগুলিকে হ্রাস করতে হবে তা খুঁজে পেতে এটি সমস্ত পৃষ্ঠা পড়তে হবে এবং বলেছিল যে কোন পৃষ্ঠাগুলি সন্ধানের অন্য কোনও উপায় নেই। এটি 1 এবং 2 এর অর্ধেক উত্তর (যদিও সারি-সারি ডেটাতে লকগুলির প্রয়োজনীয়তার ব্যাখ্যা দেয় না, তবে এটি ছোট আলু।
প্রশ্ন 3 এখনও উন্মুক্ত: যদি মুছে ফেলার জন্য ক্লিনআপ করার জন্য ইতিমধ্যে কোনও পটভূমি কাজ থাকে তবে কেন পৃষ্ঠাগুলি সামনে সরিয়ে ফেলুন?
এবং অবশ্যই, সমস্ত গুরুত্বপূর্ণ প্রশ্ন: এই আকার-নির্ভরশীল মুছে ফেলা আচরণকে সরাসরি প্রশমিত করার (অর্থাত্ কাজ করে না) কী উপায় আছে? আমি মনে করি এটি আরও সাধারণ সমস্যা হবে, যদি না আমরা সত্যই এসকিউএল সার্ভারে 50 এমবি সারি সংরক্ষণ এবং মুছে ফেলি? এখানকার অন্য প্রত্যেকেই কি কোনও কিছু আবর্জনা সংগ্রহের কাজের সাথে কাজ করে?