এসকিউএল সার্ভারে এলওবি ডেটার জন্য কর্মক্ষমতা মুছুন


16

এই প্রশ্নটি এই ফোরামের থ্রেডের সাথে সম্পর্কিত ।

আমার ওয়ার্কস্টেশনে এসকিউএল সার্ভার ২০০৮ বিকাশকারী সংস্করণ এবং একটি এন্টারপ্রাইজ সংস্করণ দ্বি-নোড ভার্চুয়াল মেশিন ক্লাস্টারে যেখানে আমি "আলফা ক্লাস্টার" উল্লেখ করেছি Run

ভের্বাইনারি (সর্বাধিক) কলাম সহ সারিগুলি মুছতে সময় লাগে time কলামের ডেটার দৈর্ঘ্যের সাথে সরাসরি সম্পর্কিত। এটি প্রথমে স্বজ্ঞাত মনে হতে পারে তবে তদন্তের পরে এসকিউএল সার্ভারটি কীভাবে সাধারণভাবে সারিগুলি মুছে ফেলবে এবং এই জাতীয় ডেটা নিয়ে ডিল করে তা বোঝার সাথে আমার সংঘাত হয়।

সমস্যাটি একটি মুছে ফেলা টাইমআউট (> 30 সেকেন্ড) সমস্যা থেকে উদ্ভূত হয়েছে যা আমরা আমাদের। নেট ওয়েব অ্যাপ্লিকেশনটিতে দেখছি, তবে আমি এই আলোচনার জন্য এটি সহজ করে তুলেছি।

যখন একটি রেকর্ড মুছে ফেলা হয়, এসকিউএল সার্ভার এটিকে লভেন্তি সম্পাদনের পরে পরবর্তী সময়ে ঘোস্ট ক্লিনআপ টাস্ক দ্বারা পরিষ্কার করা ভূত হিসাবে চিহ্নিত করে ( পল রান্ডালের ব্লগ দেখুন ) see যথাক্রমে 16 কেবি, 4 এমবি এবং 50 এমবি ডেটা সহ একটি বর্ণের (সর্বাধিক) কলামে তিনটি সারি মুছে ফেলা একটি পরীক্ষায়, আমি এই পৃষ্ঠায় ডেটা-সারি অংশের পাশাপাশি লেনদেনে দেখছি লগ ইন করুন।

আমার কাছে যেটি অদ্ভুত বলে মনে হচ্ছে তা হ'ল মুছে ফেলার সময় সমস্ত লওবি ডেটা পৃষ্ঠায় এক্স লক স্থাপন করা হয় এবং পৃষ্ঠাগুলি পিএফএসে বিচ্ছিন্ন হয়। আমি এটি লেনদেনের লগের পাশাপাশি ডিএমভি ( ) sp_lockএর ফলাফলগুলিতে দেখতে পাচ্ছি । dm_db_index_operational_statspage_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 আকার নির্বিশেষে স্থির সময় ছিল।

সুতরাং, প্রথম আমার একাডেমিক প্রশ্ন:

  1. এক্স-লক করার জন্য এসকিউএল সার্ভারকে সমস্ত LOB ডেটা পৃষ্ঠাগুলি অনুসন্ধান করার দরকার নেই কেন? লকগুলি কীভাবে স্মৃতিতে উপস্থাপিত হয় (কোনওভাবে পৃষ্ঠায় সঞ্চিত) তার একটি বিবরণ কি এটি? এটি সম্পূর্ণরূপে ক্যাশেড না থাকলে আই / ও প্রভাব ডেটা আকারের উপর দৃ strongly়ভাবে নির্ভর করে।
  2. এক্স কেন এগুলি লক করে, কেবল তাদের হ্রাস করতে? ডিলোকেশনটির নিজেরাই পৃষ্ঠাগুলি সংশোধন করার প্রয়োজন নেই বলেই কেবল ইন-সারি অংশের সাথে সূচক পাতার তালাবদ্ধ করা কি যথেষ্ট নয়? লকটি সুরক্ষা দেয় এমন এলওবি ডেটা পাওয়ার কী অন্য কোনও উপায় আছে?
  3. এই ধরণের কাজের জন্য ইতিমধ্যে একটি ব্যাকগ্রাউন্ড টাস্ক নিবেদিত রয়েছে কেন, কেন পৃষ্ঠাগুলি একেবারে আপ্লুত করবেন?

এবং সম্ভবত আরও গুরুত্বপূর্ণ, আমার ব্যবহারিক প্রশ্ন:

  • মুছে ফেলা আলাদাভাবে কাজ করার কোনও উপায় আছে কি? আমার লক্ষ্য হ'ল ফাইল স্ট্রিমের মতো আকারের নির্বিশেষে ধ্রুবক সময় মুছে ফেলা হয়, যেখানে সত্যতার পরে পটভূমিতে কোনও ক্লিনআপ ঘটে। এটা কি কনফিগারেশন জিনিস? আমি কি অদ্ভুতভাবে জিনিসগুলি সঞ্চয় করছি?

বর্ণিত পরীক্ষাটি পুনরুত্পাদন করার পদ্ধতি এখানে (এসএসএমএস ক্যোয়ারী উইন্ডোর মাধ্যমে সম্পাদিত):

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. আমাদের ডেটা আকারের বিতরণ এটির ওয়ারেন্ট দেয় না।
  2. অনুশীলনে, আমরা অনেক অংশে ডেটা যুক্ত করি এবং ফাইল স্ট্রিম আংশিক আপডেটগুলি সমর্থন করে না। আমাদের এটি প্রায় নকশা করা প্রয়োজন।

আপডেট 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 এমবি সারি সংরক্ষণ এবং মুছে ফেলি? এখানকার অন্য প্রত্যেকেই কি কোনও কিছু আবর্জনা সংগ্রহের কাজের সাথে কাজ করে?


আমি আশা করি এর থেকে আরও ভাল সমাধান থাকলেও খুঁজে পেল না। আমার কাছে 1MB + অবধি আকারের বিভিন্ন আকারের সারিগুলির বৃহত পরিমাণে লগ করার পরিস্থিতি রয়েছে এবং পুরানো রেকর্ডগুলি মুছতে আমার একটি "শুদ্ধি" প্রক্রিয়া রয়েছে। মুছে ফেলা এত ধীর ছিল তাই আমাকে এটিকে দুটি ধাপে বিভক্ত করতে হয়েছিল - প্রথমে সারণির (যা খুব দ্রুত) এর মধ্যে উল্লেখগুলি সরিয়ে ফেলুন, তারপরে অনাথ সারিগুলি মুছুন। মুছে ফেলার কাজটি ডেটা মুছতে গড় গড় ~ 2.2 সেকেন্ড / এমবি। অবশ্যই অবশ্যই আমার বিতর্ক হ্রাস করতে হয়েছিল, সুতরাং আমার কোনও লুপের মধ্যে "ডিলিট টপ (250)" সঞ্চিত প্রক্রিয়া রয়েছে যতক্ষণ না কোনও সারি আর মোছা না যায়।
অ্যাবাকাস

উত্তর:


5

ফাইল স্ট্রিমের তুলনায় ভার্বিনারি (ম্যাক্স) মুছে ফেলার জন্য কেন এত বেশি অদক্ষ হবে তা আমি বলতে পারি না তবে এই লবগুলি মোছার সময় আপনি যদি কেবল নিজের ওয়েব অ্যাপ্লিকেশন থেকে সময় নিরস্ত করার চেষ্টা করছেন তবে আপনি বিবেচনা করতে পারেন। আপনি ভারবাইনারি (ম্যাক্স) মানগুলি একটি পৃথক টেবিলের মধ্যে সংরক্ষণ করতে পারেন (আসুন একে কল করুন tblLOB) যা মূল টেবিল দ্বারা রেফারেন্স করা হয় (আসুন এই টিবিএলপ্যারেন্টকে কল করুন)।

এখান থেকে আপনি যখন কোনও রেকর্ড মুছবেন তখন আপনি এটি কেবল প্যারেন্ট রেকর্ড থেকে মুছতে পারেন এবং তারপরে LOB টেবিলের রেকর্ডগুলি পরিষ্কার করতে মাঝে মাঝে মাঝে আবর্জনা সংগ্রহের প্রক্রিয়া করতে পারেন। এই আবর্জনা সংগ্রহের প্রক্রিয়া চলাকালীন অতিরিক্ত হার্ড ড্রাইভের ক্রিয়াকলাপ থাকতে পারে তবে এটি কমপক্ষে সামনের ওয়েবের থেকে পৃথক হবে এবং অ-পিক সময়ে সম্পাদন করা যেতে পারে।


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

1
এটি মুছে ফেলা হয়েছে তা নির্দেশ করার জন্য আমি কেবলমাত্র একটি সময়ের স্ট্যাম্পের বিষয়ে সতর্ক থাকব। এটি কাজ করবে তবে তারপরে আপনার অবশেষে সক্রিয় সারিগুলিতে প্রচুর ব্যবহৃত স্থান দখল থাকবে। কতটা মুছে ফেলা হবে তার উপর নির্ভর করে আপনার এক পর্যায়ে কিছু প্রকারের জিসি প্রক্রিয়া থাকা দরকার এবং নিয়মিত ভিত্তিতে কম মুছে ফেলার পরিবর্তে এটি মাঝে মাঝে খুব কম প্রভাব ফেলবে।
ইয়ান চেম্বারল্যান্ড
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.