পোস্টগ্রেস আপডেট ... লিমিট 1


77

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

আমি একটি স্ট্যান্ডবাই - শুধু এক - এর স্থিতি পরিবর্তন করতে এবং ব্যবহার করতে হবে এমন সার্ভারের আইপি ফিরিয়ে দিতে একটি ডাটাবেস ক্যোয়ারী চাই। চয়নটি নির্বিচারে হতে পারে: যেহেতু ক্যোয়ারির সাথে সার্ভারের স্থিতি পরিবর্তন হয়, তাই কোন স্ট্যান্ডবাই নির্বাচন করা যায় তা বিবেচ্য নয়।

আমার জিজ্ঞাসাটি কেবলমাত্র একটি আপডেটে সীমাবদ্ধ করা সম্ভব?

আমার এখন পর্যন্ত যা আছে তা এখানে:

UPDATE server_info SET status = 'active' 
WHERE status = 'standby' [[LIMIT 1???]] 
RETURNING server_ip;

পোস্টগ্রিস এটি পছন্দ করে না। আমি আলাদাভাবে কি করতে পারি?


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

@eckes এটি একটি আকর্ষণীয় ধারণা। আমার ক্ষেত্রে "কোডে সার্ভারটি বাছাই করা" এর অর্থ হ'ল প্রথমে ডিবি থেকে উপলব্ধ সার্ভারগুলির একটি তালিকা পড়া এবং তারপরে একটি রেকর্ড আপডেট করা উচিত। কারণ অ্যাপ্লিকেশনটির অনেকগুলি উদাহরণ এই ক্রিয়াটি সম্পাদন করতে পারে, রেসের শর্ত রয়েছে এবং একটি পারমাণবিক অপারেশন প্রয়োজন (বা 5 বছর আগে ছিল)। বাছাইয়ের জন্য নির্দোষ হওয়া দরকার ছিল না।
ਵਿਸ਼ਾਲতা সুপিরিয়রম্যান

উত্তর:


125

একযোগে লেখার অ্যাক্সেস ছাড়াই

একটি সিটিইতে একটি নির্বাচনকে বাস্তবায়িত করুন এবং এর 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 LOCKEDPostgreSQL 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()ম্যানুয়াল:

একবার অধিবেশন স্তরে অধিগ্রহণ করার পরে, স্পষ্টভাবে প্রকাশ না হওয়া বা সেশন শেষ না হওয়া পর্যন্ত একটি পরামর্শক লক রাখা হয়।

সম্পর্কিত:

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