মুখবন্ধ
আমাদের অ্যাপ্লিকেশনটি বেশ কয়েকটি থ্রেড চালায় যা DELETE
সমান্তরালভাবে প্রশ্নগুলি চালায় । প্রশ্নগুলি বিচ্ছিন্ন ডেটাগুলিকে প্রভাবিত করে, অর্থাত DELETE
পৃথক থ্রেড থেকে একই সারিগুলিতে সমবর্তী হওয়ার সম্ভাবনা নেই । যাইহোক, প্রতি ডকুমেন্টেশন মাইএসকিউএল DELETE
বিবৃতিগুলির জন্য তথাকথিত 'নেক্সট-কী' লক ব্যবহার করে , যা মিলের কী এবং কিছু ফাঁক উভয়কেই লক করে। এই জিনিসটি মৃত-লকগুলিতে নিয়ে যায় এবং একমাত্র সমাধান যা আমরা পেয়েছি তা হল READ COMMITTED
বিচ্ছিন্নতা স্তর ব্যবহার করা ।
সমস্যাটি
বিশাল টেবিলগুলির DELETE
সাথে জটিল বিবৃতি কার্যকর করার সময় সমস্যা দেখা দেয় JOIN
। একটি বিশেষ ক্ষেত্রে আমাদের কাছে একটি সতর্কতা সহ একটি টেবিল রয়েছে যাতে মাত্র দুটি সারি রয়েছে, তবে ক্যোয়ারিতে দুটি পৃথক INNER JOIN
এড টেবিল থেকে কিছু নির্দিষ্ট সত্তার সাথে সম্পর্কিত সমস্ত সতর্কতাগুলি ফেলে দেওয়া দরকার । কোয়েরিটি নিম্নরূপ:
DELETE pw
FROM proc_warnings pw
INNER JOIN day_position dp
ON dp.transaction_id = pw.transaction_id
INNER JOIN ivehicle_days vd
ON vd.id = dp.ivehicle_day_id
WHERE vd.ivehicle_id=? AND dp.dirty_data=1
যখন দিন_ অবস্থানের টেবিলটি যথেষ্ট বড় হয় (আমার পরীক্ষার ক্ষেত্রে 1448 সারি রয়েছে) তবে READ COMMITTED
বিচ্ছিন্নতা মোডের সাথে কোনও লেনদেন পুরো proc_warnings
টেবিলটিকে অবরুদ্ধ করে ।
এই নমুনা ডেটাতে ইস্যুটি সর্বদা পুনরুত্পাদন করা হয় - http://yadi.sk/d/QDuwBtpW1BxB9 উভয়ই মাইএসকিউএল 5.1 (5.1.59-এ চেক করা হয়েছে) এবং মাইএসকিউএল 5.5 (মাইএসকিউএল 5.5.24 এ পরীক্ষিত)।
সম্পাদনা: লিঙ্কযুক্ত নমুনা ডেটাতে কোয়েরি সারণীর জন্য স্কিমা এবং সূচি রয়েছে, সুবিধার্থে এখানে পুনরুত্পাদন করা:
CREATE TABLE `proc_warnings` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`transaction_id` int(10) unsigned NOT NULL,
`warning` varchar(2048) NOT NULL,
PRIMARY KEY (`id`),
KEY `proc_warnings__transaction` (`transaction_id`)
);
CREATE TABLE `day_position` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`transaction_id` int(10) unsigned DEFAULT NULL,
`sort_index` int(11) DEFAULT NULL,
`ivehicle_day_id` int(10) unsigned DEFAULT NULL,
`dirty_data` tinyint(4) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `day_position__trans` (`transaction_id`),
KEY `day_position__is` (`ivehicle_day_id`,`sort_index`),
KEY `day_position__id` (`ivehicle_day_id`,`dirty_data`)
) ;
CREATE TABLE `ivehicle_days` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`d` date DEFAULT NULL,
`sort_index` int(11) DEFAULT NULL,
`ivehicle_id` int(10) unsigned DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `ivehicle_days__is` (`ivehicle_id`,`sort_index`),
KEY `ivehicle_days__d` (`d`)
);
লেনদেনের জন্য প্রশ্নগুলি নিম্নরূপ:
লেনদেন ঘ
set transaction isolation level read committed; set autocommit=0; begin; DELETE pw FROM proc_warnings pw INNER JOIN day_position dp ON dp.transaction_id = pw.transaction_id INNER JOIN ivehicle_days vd ON vd.id = dp.ivehicle_day_id WHERE vd.ivehicle_id=2 AND dp.dirty_data=1;
লেনদেন 2
set transaction isolation level read committed; set autocommit=0; begin; DELETE pw FROM proc_warnings pw INNER JOIN day_position dp ON dp.transaction_id = pw.transaction_id INNER JOIN ivehicle_days vd ON vd.id = dp.ivehicle_day_id WHERE vd.ivehicle_id=13 AND dp.dirty_data=1;
এর মধ্যে একটি সর্বদা 'লক ওয়েট টাইমআউট অতিক্রম করে ...' ত্রুটি দিয়ে ব্যর্থ হয়। information_schema.innodb_trx
নিম্নলিখিত সারি রয়েছে:
| trx_id | trx_state | trx_started | trx_requested_lock_id | trx_wait_started | trx_wait | trx_mysql_thread_id | trx_query |
| '1A2973A4' | 'LOCK WAIT' | '2012-12-12 20:03:25' | '1A2973A4:0:3172298:2' | '2012-12-12 20:03:25' | '2' | '3089' | 'DELETE pw FROM proc_warnings pw INNER JOIN day_position dp ON dp.transaction_id = pw.transaction_id INNER JOIN ivehicle_days vd ON vd.id = dp.ivehicle_day_id WHERE vd.ivehicle_id=13 AND dp.dirty_data=1' |
| '1A296F67' | 'RUNNING' | '2012-12-12 19:58:02' | NULL | NULL | '7' | '3087' | NULL |
information_schema.innodb_locks
| lock_id | lock_trx_id | lock_mode | lock_type | lock_table | lock_index | lock_space | lock_page | lock_rec | lock_data |
| '1A2973A4:0:3172298:2' | '1A2973A4' | 'X' | 'RECORD' | '`deadlock_test`.`proc_warnings`' | '`PRIMARY`' | '0' | '3172298' | '2' | '53' |
| '1A296F67:0:3172298:2' | '1A296F67' | 'X' | 'RECORD' | '`deadlock_test`.`proc_warnings`' | '`PRIMARY`' | '0' | '3172298' | '2' | '53' |
যেহেতু আমি দেখতে পাচ্ছি উভয় X
প্রশ্নই প্রাথমিক কী = 53 দিয়ে একটি সারিতে একচেটিয়া লক চায় However তবে, তাদের উভয়েরই অবশ্যই proc_warnings
টেবিল থেকে সারিগুলি মুছতে হবে না । আমি শুধু বুঝতে পারি না কেন সূচকটি লক করা আছে। তদুপরি, proc_warnings
সারণিটি ফাঁকা থাকলে সূচীটি লক করা হয় না বা day_position
সারণীতে কম সংখ্যক সারি থাকে (যেমন একশত সারি)।
আরও তদন্ত EXPLAIN
একই ধরণের SELECT
জিজ্ঞাসা চালানো ছিল । এটি দেখায় যে ক্যোয়ারী অপ্টিমাইজার proc_warnings
সারণী সন্ধানের জন্য সূচক ব্যবহার করে না এবং এটি কেবল প্রাথমিক কারণ কী সূচকটিকে কেন অবরুদ্ধ করে তা আমি কল্পনা করতে পারি।
সরলীকৃত মামলা
দু'টি রেকর্ডের সাথে কেবল দুটি টেবিল থাকলেই ইস্যুটিকে সরল ক্ষেত্রেও পুনরুত্পাদন করা যেতে পারে, তবে সন্তানের টেবিলটির মূল টেবিলে রেফ কলামে কোনও সূচক থাকে না।
parent
টেবিল তৈরি করুন
CREATE TABLE `parent` (
`id` int(10) unsigned NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB
child
টেবিল তৈরি করুন
CREATE TABLE `child` (
`id` int(10) unsigned NOT NULL,
`parent_id` int(10) unsigned DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB
টেবিলগুলি পূরণ করুন
INSERT INTO `parent` (id) VALUES (1), (2);
INSERT INTO `child` (id, parent_id) VALUES (1, NULL), (2, NULL);
দুটি সমান্তরাল লেনদেনে পরীক্ষা:
লেনদেন ঘ
SET TRANSACTION ISOLATION LEVEL READ COMMITTED; SET AUTOCOMMIT=0; BEGIN; DELETE c FROM child c INNER JOIN parent p ON p.id = c.parent_id WHERE p.id = 1;
লেনদেন 2
SET TRANSACTION ISOLATION LEVEL READ COMMITTED; SET AUTOCOMMIT=0; BEGIN; DELETE c FROM child c INNER JOIN parent p ON p.id = c.parent_id WHERE p.id = 2;
উভয় ক্ষেত্রেই সাধারণ অংশটি হ'ল মাইএসকিউএল সূচকগুলি ব্যবহার করে না। আমি বিশ্বাস করি এটি পুরো টেবিলটি লক করার কারণ।
আমাদের সমাধান
একমাত্র সমাধান যা আমরা এখন দেখতে পাচ্ছি তা থ্রেড পরিষ্কার শেষ হতে দিতে 50 ডিফল্ট থেকে 500 সেকেন্ডে ডিফল্ট লক ওয়েটআউট আউট করা। তারপরে আঙ্গুলগুলি অতিক্রম করতে হবে।
কোন সাহায্য প্রশংসা।
day_position
সারণীতে সাধারণত কতগুলি সারি থাকে, যখন এটি এত ধীরে চলতে শুরু করে যে আপনাকে টাইম আউট সীমাটি 500 সেকেন্ডে গতিতে হবে? 2) আপনার কাছে কেবলমাত্র নমুনা ডেটা থাকলে চালানো কতক্ষণ সময় নেয়?