একযোগে লেখার অ্যাক্সেস ছাড়াই
একটি সিটিইতে একটি নির্বাচনকে বাস্তবায়িত করুন এবং এর FROM
দফায় এটিতে যোগ দিন UPDATE
।
WITH cte AS (
SELECT server_ip -- pk column or any (set of) unique column(s)
FROM server_info
WHERE status = 'standby'
LIMIT 1 -- arbitrary pick (cheapest)
)
UPDATE server_info s
SET status = 'active'
FROM cte
WHERE s.server_ip = cte.server_ip
RETURNING server_ip;
আমি এখানে মূলত এখানে একটি সরল subquery ছিল, কিন্তু এটি LIMIT
নির্দিষ্ট ক্যোয়ারী পরিকল্পনার জন্য পার্থক্য করতে পারে যেমন ফাইক বলেছেন:
পরিকল্পনাকারী এমন একটি পরিকল্পনা তৈরি করতে বেছে নিতে পারে যা LIMITing
সাবকোয়ারির উপরে নেস্টেড লুপটি কার্যকর করে, এর UPDATEs
চেয়ে বেশি কারণ সৃষ্টি করে LIMIT
:
Update on buganalysis [...] rows=5
-> Nested Loop
-> Seq Scan on buganalysis
-> Subquery Scan on sub [...] loops=11
-> Limit [...] rows=2
-> LockRows
-> Sort
-> Seq Scan on buganalysis
পরীক্ষার কেস পুনরুত্পাদন
LIMIT
উপরেরটি ঠিক করার উপায়টি ছিল সাবকোয়ারিটি তার নিজস্ব সিটিইতে মোড়ানো , কারণ সিটিই বাস্তবায়িত হয়েছে এটি নেস্টেড লুপের বিভিন্ন পুনরাবৃত্তির উপর বিভিন্ন ফলাফল প্রদান করবে না।
অথবা একটি অকুল ব্যবহার সম্পর্কিত subquery সঙ্গে সহজ ক্ষেত্রে জন্যLIMIT
1
। সহজ, দ্রুত:
UPDATE server_info
SET status = 'active'
WHERE server_ip = (
SELECT server_ip
FROM server_info
WHERE status = 'standby'
LIMIT 1
)
RETURNING server_ip;
একযোগে লেখার অ্যাক্সেস সহ
এই সমস্ত জন্য ডিফল্ট বিচ্ছিন্নতা স্তরREAD COMMITTED
অনুমান । কঠোর বিচ্ছিন্নতা স্তর ( REPEATABLE READ
এবং SERIALIZABLE
) এরপরেও সিরিয়ালাইজেশন ত্রুটি হতে পারে। দেখা:
একযোগে লেখার চাপের অধীনে, FOR UPDATE SKIP LOCKED
বর্ণের পরিস্থিতি এড়াতে সারিটি লক করতে যুক্ত করুন । পুরানো সংস্করণগুলির জন্য নীচে দেখুন SKIP LOCKED
পোস্টগ্রিস 9.5 এ যুক্ত করা হয়েছিল । ম্যানুয়াল:
এর সাথে SKIP LOCKED
, যে কোনও নির্বাচিত সারি অবিলম্বে লক করা যায় না তা এড়িয়ে যায়। লক করা সারিগুলিকে এড়িয়ে যাওয়া ডেটাগুলির একটি অসামঞ্জস্য দৃষ্টিভঙ্গি সরবরাহ করে, তাই এটি সাধারণ উদ্দেশ্যে কাজের জন্য উপযুক্ত নয়, তবে একাধিক গ্রাহক একটি সারি-জাতীয় সারণীতে অ্যাক্সেস সহ লক যুক্তি এড়াতে ব্যবহার করতে পারেন।
UPDATE server_info
SET status = 'active'
WHERE server_ip = (
SELECT server_ip
FROM server_info
WHERE status = 'standby'
LIMIT 1
FOR UPDATE SKIP LOCKED
)
RETURNING server_ip;
যদি কোনও যোগ্যতা না থাকে, আনলক করা সারিটি বামে না থাকে তবে এই কোয়েরিতে কিছুই ঘটে না (কোনও সারি আপডেট করা হয়নি) এবং আপনি একটি খালি ফলাফল পান। অবাস্তব ক্রিয়াকলাপের জন্য এর অর্থ আপনার কাজ শেষ হয়েছে।
যাইহোক, সমবর্তী লেনদেনের সারি লক হয়ে থাকতে পারে তবে তারপরে আপডেটটি শেষ করবেন না ( ROLLBACK
বা অন্যান্য কারণে)। নিশ্চিত হতে একটি চূড়ান্ত চেক চালান:
SELECT NOT EXISTS (
SELECT 1
FROM server_info
WHERE status = 'standby'
);
SELECT
লক করা সারিগুলিও দেখে। খারাপ যে ফিরে না true
, এক বা একাধিক সারি এখনও প্রক্রিয়াধীন এবং লেনদেন এখনও ফিরে যেতে পারে। (বা ইতিমধ্যে নতুন সারি যুক্ত করা হয়েছে)) কিছুক্ষণ অপেক্ষা করুন, তারপরে দুটি ধাপটি লুপ করুন: ( UPDATE
যতক্ষণ না আপনি কোনও সারি ফিরে পাবেন না SELECT
... ...) যতক্ষণ না আপনি পান true
।
সম্পর্কিত:
SKIP LOCKED
PostgreSQL 9.4 বা তার চেয়ে পুরানো ছাড়াই
UPDATE server_info
SET status = 'active'
WHERE server_ip = (
SELECT server_ip
FROM server_info
WHERE status = 'standby'
LIMIT 1
FOR UPDATE
)
RETURNING server_ip;
প্রথম সারির এটির লকটি প্রকাশ না হওয়া পর্যন্ত একই সারিতে লক করার চেষ্টা করা সমবর্তী লেনদেনগুলি অবরুদ্ধ করা হবে।
যদি প্রথমটি আবার ঘুরিয়ে দেওয়া হয়, পরবর্তী লেনদেনটি লকটি নিয়ে যায় এবং সাধারণত এগিয়ে যায়; কাতারে থাকা অন্যরা অপেক্ষা করতে থাকে।
যদি প্রথম প্রতিশ্রুতিবদ্ধ হয় তবে WHERE
শর্তটি পুনরায় মূল্যায়ন করা হয় এবং যদি এটি না হয় TRUE
( status
পরিবর্তিত) সিটিই (কিছুটা আশ্চর্যজনকভাবে) কোনও সারি দেয় না। কিছুই ঘটেনি. যে আকাঙ্ক্ষিত আচরণ যখন সমস্ত লেনদেন আপডেট করতে চান একই সারিতে ।
কিন্তু যখন প্রতিটি লেনদেন পরবর্তী সারিতে আপডেট করতে চায় না । এবং যেহেতু আমরা কেবল একটি স্বেচ্ছাসেবক (বা এলোমেলো ) সারিটি আপডেট করতে চাই , তাই অপেক্ষা করার কোনও মানে নেই।
আমরা পরামর্শকৃত লকগুলির সাহায্যে পরিস্থিতিটিকে অবরোধ মুক্ত করতে পারি :
UPDATE server_info
SET status = 'active'
WHERE server_ip = (
SELECT server_ip
FROM server_info
WHERE status = 'standby'
AND pg_try_advisory_xact_lock(id)
LIMIT 1
FOR UPDATE
)
RETURNING server_ip;
এইভাবে, পরবর্তী সারিটি এখনও তালাবদ্ধ নয় আপডেট করা হবে। প্রতিটি লেনদেন কাজ করার জন্য একটি নতুন সারি পায়। এই কৌশলটির জন্য আমার চেক পোস্টগ্র্রেস উইকির সাহায্য ছিল ।
id
কোনো অনন্য হচ্ছে bigint
কলাম (বা মত অন্তর্নিহিত কাস্টের সাথে কোন প্রকার int4
বা int2
)।
উপদেষ্টা কেশ একই সময়ে আপনার ডাটাবেস একাধিক টেবিলের জন্য ব্যবহার করা হয়, তাহলে সঙ্গে দুর্বোধ্য pg_try_advisory_xact_lock(tableoid::int, id)
- id
একটি অনন্য হচ্ছে integer
এখানে।
যেহেতু tableoid
একটি bigint
পরিমাণ, তাই এটি তাত্ত্বিকভাবে উপচে পড়তে পারে integer
। যদি আপনি পর্যাপ্ত পরিমাণে অচল হন তবে (tableoid::bigint % 2147483648)::int
পরিবর্তে ব্যবহার করুন - সত্যিকারের ভৌতিক সমস্যার জন্য একটি তাত্ত্বিক "হ্যাশের সংঘর্ষ" রেখে ...
এছাড়াও, পোস্টগ্র্রেস WHERE
কোনও ক্রমে শর্ত পরীক্ষা করতে নিখরচায় । এটা তোলে পারে পরীক্ষা pg_try_advisory_xact_lock()
এবং একটি লক অর্জন সামনে status = 'standby'
, যা সম্পর্কহীন সারি, যেখানে অতিরিক্ত উপদেষ্টা কেশ হতে পারে status = 'standby'
সত্য নয়। এসও সম্পর্কিত সম্পর্কিত প্রশ্ন:
সাধারণত, আপনি এটিকে এড়িয়ে যেতে পারেন। করার গ্যারান্টি যে শুধুমাত্র কোয়ালিফাইং সারি লক, আপনি পারে নীড় উপরে মত সম্পৃক্ত (গুলি) একটি কোটে অথবা সঙ্গে একটি subquery OFFSET 0
হ্যাক (ইনলাইনিং বাধা দেয়) । উদাহরণ:
বা (অনুক্রমিক স্ক্যানগুলির জন্য সস্তা) নীতির CASE
মতো বিবৃতিতে শর্তগুলির নীড় :
WHERE CASE WHEN status = 'standby' THEN pg_try_advisory_xact_lock(id) END
তবেCASE
কৌতুক এছাড়াও একটি সূচক ব্যবহার করা থেকে Postgres রাখা হবে status
। যদি এই জাতীয় সূচক পাওয়া যায় তবে শুরু করার জন্য আপনার অতিরিক্ত বাসা বাঁধার দরকার নেই: কেবলমাত্র যোগ্যতার সারিগুলি একটি সূচক স্ক্যানে লক হয়ে যাবে।
যেহেতু আপনি নিশ্চিত হতে পারবেন না যে প্রতিটি কলটিতে একটি সূচক ব্যবহৃত হয়, আপনি কেবল এটি করতে পারেন:
WHERE status = 'standby'
AND CASE WHEN status = 'standby' THEN pg_try_advisory_xact_lock(id) END
CASE
কথাটি অপ্রয়োজনীয়, কিন্তু এটা সার্ভার আলোচনা উদ্দেশ্য।
যদি কমান্ডটি দীর্ঘ লেনদেনের অংশ হয় তবে সেশন-লেভেল লকগুলি বিবেচনা করুন যা ম্যানুয়ালি প্রকাশ হতে পারে (এবং হতে হবে)। সুতরাং আপনি লক করা সারিটি সম্পন্ন করার সাথে সাথেই আনলক করতে পারবেন: pg_try_advisory_lock()
এবংpg_advisory_unlock()
। ম্যানুয়াল:
একবার অধিবেশন স্তরে অধিগ্রহণ করার পরে, স্পষ্টভাবে প্রকাশ না হওয়া বা সেশন শেষ না হওয়া পর্যন্ত একটি পরামর্শক লক রাখা হয়।
সম্পর্কিত: