InnoDB সারি লকিং - কীভাবে প্রয়োগ করা যায়


13

আমি এখন প্রায় ঘুরে দেখছিলাম, মাইএসকিএল সাইটটি পড়েছি এবং এখনও এটি ঠিক কীভাবে কাজ করে তা দেখতে পাচ্ছি না।

আমি ফলাফলটি লিখতে এবং সারি লক করতে চাই, পরিবর্তনটি লিখতে এবং লকটি প্রকাশ করতে চাই। অডিওকমিট চালু আছে।

পরিকল্পনা

id (int)
name (varchar50)
status (enum 'pending', 'working', 'complete')
created (datetime)
updated (datetime) 

মুলতুবি থাকা অবস্থায় একটি আইটেম নির্বাচন করুন, এবং এটি কাজ করে আপডেট করুন। একই আইটেমটি দু'বার বাছাই করা হয়নি তা নিশ্চিত করার জন্য একটি এক্সক্লুসিভ রাইটিং ব্যবহার করুন।

তাই;

"SELECT id FROM `items` WHERE `status`='pending' LIMIT 1 FOR WRITE"

ফলাফল থেকে আইডি পেতে

"UPDATE `items` SET `status`='working', `updated`=NOW() WHERE `id`=<selected id>

লকটি ছেড়ে দেওয়ার জন্য আমার কি কিছু করার দরকার আছে এবং এটি কি আমি উপরের মতো করে কাজ করেছি?

উত্তর:


26

আপনি যা চান তা হ'ল একটি লেনদেনের প্রসঙ্গের মধ্যে থেকে আপডেটের জন্য ... নির্বাচন করুন । নির্বাচন করুন আপডেটের জন্য নির্বাচিত সারিগুলিতে একচেটিয়া লক রাখে ঠিক যেমন আপনি আপডেট আপডেট করছেন। বিচ্ছিন্নতা স্তরটি সুস্পষ্টভাবে সেট করা আছে তা নির্বিশেষে এটি স্পষ্টভাবে READ COMMITTED বিচ্ছিন্নতা স্তরে চলে। কেবল সচেতন থাকুন যে নির্বাচন করুন ... ফরেক্সের জন্য সামঞ্জস্যের জন্য খুব খারাপ এবং এটি যখন একেবারে প্রয়োজন তখনই ব্যবহার করা উচিত। লোকেদের কেটে পেস্ট করার সাথে সাথে কোডবেজে গুন করার প্রবণতাও রয়েছে।

এখানে সাকিলা ডাটাবেস থেকে একটি উদাহরণস্বরূপ অধিবেশন যা ফর আপডেট সম্পর্কিত প্রশ্নের কিছু আচরণ দেখায়।

প্রথমত, কেবলমাত্র আমরা স্ফটিক পরিষ্কার, লেনদেনের বিচ্ছিন্নতা স্তরটিকে পুনরাবৃত্তিযোগ্য পড়ুন set এটি সাধারণত অপ্রয়োজনীয়, কারণ এটি InnoDB এর জন্য ডিফল্ট বিচ্ছিন্নতা স্তর:

session1> SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
session1> BEGIN;
session1> SELECT first_name, last_name FROM customer WHERE customer_id = 3;
+------------+-----------+
| first_name | last_name |
+------------+-----------+
| LINDA      | WILLIAMS  |
+------------+-----------+
1 row in set (0.00 sec)    

অন্য সেশনে, এই সারিটি আপডেট করুন। লিন্ডার বিয়ে হয়েছিল এবং তার নাম পরিবর্তন হয়েছে:

session2> UPDATE customer SET last_name = 'BROWN' WHERE customer_id = 3;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

সেশন 1 এ ফিরে আসুন, কারণ আমরা রিপিটেবল রিডে ছিলাম, লিন্ডা এখনও লিন্ডা উইলিয়ামস:

session1> SELECT first_name, last_name FROM customer WHERE customer_id = 3;
+------------+-----------+
| first_name | last_name |
+------------+-----------+
| LINDA      | WILLIAMS  |
+------------+-----------+
1 row in set (0.00 sec)

তবে এখন, আমরা এই সারিতে একচেটিয়া অ্যাক্সেস চাই, তাই আমরা সারিটিতে আপডেটের জন্য কল করি। লক্ষ্য করুন যে আমরা এখন সারির সাম্প্রতিকতম সংস্করণটি ফিরে পেয়েছি, যা এই লেনদেনের বাইরে সেশন 2-এ আপডেট হয়েছিল। এটি পুনরাবৃত্তিযোগ্য রিড নয়, এটি পড়ুন কমিট

session1> SELECT first_name, last_name FROM customer WHERE customer_id = 3 FOR UPDATE;
+------------+-----------+
| first_name | last_name |
+------------+-----------+
| LINDA      | BROWN     |
+------------+-----------+
1 row in set (0.00 sec)

আসুন 1 সেশনে লক সেটটি পরীক্ষা করে দেখি। নোট করুন যে সেশন 2 সারিটি আপডেট করতে পারে না।

session2> UPDATE customer SET last_name = 'SMITH' WHERE customer_id = 3;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

তবে আমরা এটি থেকে এখনও নির্বাচন করতে পারি

session2> SELECT c.customer_id, c.first_name, c.last_name, a.address_id, a.address FROM customer c JOIN address a USING (address_id) WHERE c.customer_id = 3;
+-------------+------------+-----------+------------+-------------------+
| customer_id | first_name | last_name | address_id | address           |
+-------------+------------+-----------+------------+-------------------+
|           3 | LINDA      | BROWN     |          7 | 692 Joliet Street |
+-------------+------------+-----------+------------+-------------------+
1 row in set (0.00 sec)

এবং আমরা এখনও একটি বিদেশী কী সম্পর্কের সাথে চাইল্ড টেবিল আপডেট করতে পারি

session2> UPDATE address SET address = '5 Main Street' WHERE address_id = 7;
Query OK, 1 row affected (0.05 sec)
Rows matched: 1  Changed: 1  Warnings: 0

session1> COMMIT;

আরেকটি পার্শ্ব প্রতিক্রিয়া হ'ল আপনি অচলাবস্থার সম্ভাবনা বাড়িয়ে তোলেন।

আপনার নির্দিষ্ট ক্ষেত্রে, আপনি সম্ভবত চান:

BEGIN;
SELECT id FROM `items` WHERE `status`='pending' LIMIT 1 FOR UPDATE;
-- do some other stuff
UPDATE `items` SET `status`='working', `updated`=NOW() WHERE `id`=<selected id>;
COMMIT;

যদি "কিছু অন্যান্য জিনিস করুন" টুকরো অপ্রয়োজনীয় হয় এবং আপনার চারপাশে সারি সম্পর্কে তথ্য রাখার দরকার নেই, তবে নির্বাচন করুন আপডেটের জন্য অপ্রয়োজনীয় এবং অপব্যয় এবং পরিবর্তে আপনি কেবল একটি আপডেট চালাতে পারেন:

UPDATE `items` SET `status`='working', `updated`=NOW() WHERE `status`='pending' LIMIT 1;

আশা করি এটি কিছুটা বোধগম্য হবে।


3
ধন্যবাদ। আমার সমস্যার সমাধান হবে বলে মনে হচ্ছে না, যখন "থ্রেড আইডি থেকে itemsযেখানে নির্বাচন করুন status= 'অপেক্ষার জন্য' সীমাবদ্ধ 1 'রয়েছে; এবং তারা উভয়ই একই সারিটি দেখতে পাবে, তারপরে একটি অন্যটিকে লক করবে। আমি আশা করছিলাম যে কোনওরকমভাবে এটি লক করা সারিটি পাশ কাটিয়ে উঠতে সক্ষম হবে এবং পরবর্তী আইটেমটি মুলতুবি ছিল তা ..
উইজার্ড

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

হারুন; হ্যাঁ আমি সেটাই করার চেষ্টা করছি। আমি গিয়ারম্যান এর মতো কিছু ব্যবহার করার দিকে নজর রেখেছি - তবে এটি ছিল একটি আবক্ষতা। তোমার মনে অন্য কিছু আছে?
উইজার্ড

আমি মনে করি আপনার এটি পড়তে হবে: ইঞ্জিনিয়ারড.com / blog / 2011/… - বার্তার সারিগুলির জন্য, আপনার পছন্দের ক্লায়েন্টের ভাষার উপর নির্ভর করে সেখানে অনেকগুলি রয়েছে। অ্যাক্টিভ এমকিউ, রেসকিউ (রুবি + রেডিস), জিরো কিউ, রাবিট এমকিউ, ইত্যাদি
অ্যারন ব্রাউন

আমি কীভাবে এটি তৈরি করব যাতে সেশন 1-এ আপডেট না হওয়া পর্যন্ত সেশন 2 টি পড়া বন্ধ করে দেয়?
সিএমসিডিগ্রাগনকাই

2

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

বিভিন্ন ক্লায়েন্ট এক সাথে একই সারি পড়তে পারে।

বিভিন্ন ক্লায়েন্ট একই সাথে বিভিন্ন সারি পরিবর্তন করতে পারে।

বিভিন্ন ক্লায়েন্ট একই সময়ে একই সারিতে সংশোধন করতে পারে না। যদি কোনও লেনদেন একটি সারি পরিবর্তন করে, প্রথম লেনদেন শেষ না হওয়া অবধি অন্য লেনদেনগুলি একই সারিতে সংশোধন করতে পারে না। অন্যান্য লেনদেনগুলি সংশোধিত সারিটি পড়তে পারে না, যদি না তারা পড়াশুনা বিচ্ছিন্ন বিচ্ছিন্নতা স্তরটি ব্যবহার করে। এটি হ'ল তারা আসল অযৌক্তিক সারিটি দেখতে পাবে।

মূলত, আপনাকে স্পষ্টত লকিং নির্দিষ্ট করতে হবে না ইনোডিবি এটি পরিচালনা করে যদিও কিছু পরিস্থিতিতে আপনাকে স্পষ্টত লক সম্পর্কিত বিবরণ নীচে দেওয়া যেতে পারে:

নিম্নলিখিত তালিকায় উপলভ্য লকের ধরণ এবং তাদের প্রভাবগুলি বর্ণনা করা হয়েছে:

পড়ুন

পড়ার জন্য একটি টেবিল লক করে। একটি READ লক পাঠ্য প্রশ্নের জন্য যেমন একটি সারণী লক করে যেমন সারণি থেকে তথ্য পুনরুদ্ধার করে LECT এটি সারণি মোছার মতো INSERT, মোছা বা আপডেটের মতো লেখার ক্রিয়াকলাপের অনুমতি দেয় না এমনকি লকটি ধারণ করে এমন ক্লায়েন্ট দ্বারাও। যখন কোনও টেবিলটি পড়ার জন্য লক করা থাকে, অন্য ক্লায়েন্টরা একই সময়ে টেবিল থেকে পড়তে পারে তবে কোনও ক্লায়েন্ট এটিতে লিখতে পারে না। যে ক্লায়েন্টটি পাঠ্য-লক হওয়া কোনও টেবিলে লিখতে চায় তার জন্য বর্তমানে এটি পড়তে থাকা সমস্ত ক্লায়েন্ট তাদের লক শেষ না করে এবং অবধি প্রকাশ না হওয়া পর্যন্ত অপেক্ষা করতে হবে।

লিখুন

লেখার জন্য একটি টেবিল লক করে। একটি WRITE লক হল একচেটিয়া লক। এটি কেবল তখনই অধিগ্রহণ করা যাবে যখন কোনও টেবিল ব্যবহার করা হচ্ছে না। একবার অধিগ্রহণ করার পরে, কেবল লেখার লক ধারণকারী ক্লায়েন্টটি টেবিল থেকে পড়তে বা লিখতে পারে। অন্যান্য ক্লায়েন্টরা এটি থেকে পড়তে বা লিখতে পারে না। অন্য কোনও ক্লায়েন্ট পড়া বা লেখার জন্য টেবিলটি লক করতে পারবেন না।

স্থানীয় পড়ুন

পড়ার জন্য একটি টেবিল লক করে, তবে সমবর্তী সন্নিবেশগুলিকে অনুমতি দেয়। একটি সমকালীন সন্নিবেশ "পাঠক ব্লক লেখকদের" নীতিটির ব্যতিক্রম। এটি কেবল মাইআইএসএএম টেবিলগুলিতে প্রযোজ্য। যদি কোনও মাইআইএসএএম টেবিলের মোছা বা আপডেট হওয়া রেকর্ডগুলির ফলে মাঝখানে কোনও ছিদ্র না থাকে তবে সারণি সর্বদা সারণির শেষে হয়। সেক্ষেত্রে, কোনও ক্লায়েন্ট যে কোনও টেবিল থেকে পড়ছেন তা অন্য ক্লায়েন্টদের টেবিলের মধ্যে প্রবেশের অনুমতি দেওয়ার জন্য এটি একটি READ LOCAL লক দিয়ে লক করতে পারে যখন পাঠক লকযুক্ত ক্লায়েন্টটি এটি থেকে পড়ে reads যদি কোনও মাইআইএসএএম টেবিলের গর্ত থাকে তবে আপনি টেবিলটিকে ডিফল্ট করতে অপ্টিমাইজ টেবিল ব্যবহার করে এগুলি সরাতে পারেন।


উত্তরের জন্য ধন্যবাদ. যেহেতু আমার কাছে এই টেবিলটি রয়েছে এবং 100 টি ক্লায়েন্ট মুলতুবি আইটেমগুলি পরীক্ষা করছে আমি প্রচুর সংঘর্ষ পাচ্ছিলাম - 2-3 ক্লায়েন্টরা একই মুলতুবি সারি পাচ্ছে। টেবিল লকটি ধীর করতে হবে।
উইজার্ড

0

অন্য বিকল্পটি হ'ল একটি কলাম যুক্ত করা হবে যা সর্বশেষ সফল লকটির সময় সঞ্চার করেছিল এবং তারপরে অন্য যে কোনও কিছু সারিটি লক করতে চেয়েছিল এটি পরিষ্কার হওয়া বা 5 মিনিট (বা যা কিছু) না পেরে অপেক্ষা করা দরকার to

কিছুটা এইরকম...

Schema

id (int)
name (varchar50)
status (enum 'pending', 'working', 'complete')
created (datetime)
updated (datetime)
lastlock (int)

লাস্টলক হ'ল একটি ইনট যেমন এটি ইউনিক্স টাইমস্ট্যাম্পটিকে তুলনামূলক সহজ (এবং সম্ভবত আরও দ্রুত) হিসাবে সংরক্ষণ করে।

// শব্দার্থকদের ক্ষমা করুন, আমি এগুলি একটালি চালিত তা পরীক্ষা করে দেখিনি, তবে তারা যদি এটি না করে তবে যথেষ্ট পরিমাণে হওয়া উচিত।

UPDATE items 
  SET lastlock = UNIX_TIMESTAMP() 
WHERE 
  lastlock = 0
  OR (UNIX_TIMESTAMP() - lastlock) > 360;

তারপরে কতগুলি সারি আপডেট হয়েছিল তা পরীক্ষা করে দেখুন, কারণ সারিগুলি একবারে দুটি প্রক্রিয়া দ্বারা আপডেট করা যায় না, আপনি যদি সারিটি আপডেট করেন তবে আপনি লকটি পেয়েছেন। ধরে নিই যে আপনি পিএইচপি ব্যবহার করছেন, আপনি mysql_affected_rows () ব্যবহার করবেন, যদি এর থেকে প্রাপ্ত ফলাফল 1 হয়, আপনি সফলভাবে এটি লক করে রেখেছেন।

তারপরে আপনি যা করতে হবে তা করার পরে আপনি লকলকটি 0 এ আপডেট করতে পারেন, বা অলস হয়ে 5 মিনিট অপেক্ষা করুন যখন পরবর্তী লক প্রচেষ্টা যেভাবেই সফল হবে।

সম্পাদনা: গ্রীষ্মের সময় পরিবর্তনের আশেপাশে যেমনটি কাজ করা হয় ঠিক তেমন পরীক্ষা করার জন্য আপনার কিছুটা কাজের প্রয়োজন হতে পারে কারণ ঘড়িগুলি এক ঘন্টা ফিরে যেতে পারে, সম্ভবত চেকটি বাতিল করে দেয়। ইউনিক্সের টাইমস্ট্যাম্পগুলি ইউটিসি-তে ছিল তা আপনাকে নিশ্চিত করতে হবে - যা সে যাই হোক না কেন।


-1

বিকল্পভাবে, আপনি সমান্তরাল লেখার অনুমতি দিতে এবং সারি লকিং (খণ্ডিত জসন জোড় স্টাইল) কে বাইপাস করতে রেকর্ড ক্ষেত্রগুলিকে টুকরো টুকরো করতে পারেন। সুতরাং কোনও যৌগের পাঠের রেকর্ডের একটি ক্ষেত্র যদি পূর্ণসংখ্যার / বাস্তব হয় তবে আপনার সেই ক্ষেত্রের 1-8 টুকরা থাকতে পারে (8 টি রেকর্ড লিখুন / সারি কার্যকর হবে)। তারপরে প্রতিটি লেখার পরে টুকরো টুকরো রাউন্ড-রবিনের একটি পৃথক পঠন অনুসন্ধানে যোগ করুন। এটি সমান্তরাল পর্যন্ত 8 সমবর্তী ব্যবহারকারীকে মঞ্জুরি দেয়।

যেহেতু আপনি কেবল প্রতিটি খণ্ডকে আংশিক মোট তৈরির সাথে কাজ করছেন, কোনও সংঘর্ষ এবং সত্য সমান্তরাল আপডেট নেই (অর্থাত আপনি সম্পূর্ণ ইউনিফাইড পঠিত রেকর্ডের চেয়ে প্রতিটি খণ্ডকে লক লিখুন)। এটি কেবল সংখ্যাগত ক্ষেত্রগুলিতে স্পষ্টতই কাজ করে। ফলাফল সংরক্ষণের জন্য এমন কিছু যা গাণিতিক পরিবর্তনের উপর নির্ভর করে।

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

এমএমআরপিজি এই সমস্যাটি নিয়ে ব্যাপকভাবে ক্ষতিগ্রস্থ হয়, যখন বিপুল সংখ্যক খেলোয়াড়রা প্রভাবের দক্ষতার ক্ষেত্র দিয়ে একে অপরকে মারতে শুরু করে। এই একাধিক প্লেয়ারকে সমান্তরালে প্রতিটি অন্যান্য খেলোয়াড়কে ঠিক একই সময়ে লিখতে / আপডেট করতে হবে, ইউনিফাইড প্লেয়ারের রেকর্ডে রাইটিং সারি লকিং ঝড় তৈরি করে।

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