বর্তমানে গৃহীত উত্তর একটি একক দ্বন্দ্ব লক্ষ্য, কয়েক দ্বন্দ্ব, ছোট tuples এবং কোন ট্রিগার জন্য ঠিক বলে মনে হয়। এটি দৃ force় শক্তি সহ সম্মতিসূত্র ইস্যু 1 (নীচে দেখুন) এড়িয়ে চলে । সহজ সমাধানটির আবেদন রয়েছে, পার্শ্ব প্রতিক্রিয়াগুলি কম গুরুত্বপূর্ণ হতে পারে।
অন্যান্য সমস্ত ক্ষেত্রে, প্রয়োজন ছাড়া অভিন্ন সারি আপডেট করবেন না । এমনকি যদি আপনি পৃষ্ঠে কোনও পার্থক্য না দেখেন তবে বিভিন্ন পার্শ্ব প্রতিক্রিয়া রয়েছে :
এটি সম্ভবত ট্রিগারগুলিকে গুলি চালাতে পারে যা গুলি করা উচিত নয়।
এটি "নির্দোষ" সারিগুলি লিখতে লক করে, সম্ভবত সমবর্তী লেনদেনের জন্য ব্যয় বহন করে।
এটি সারিটি নতুন বলে মনে হতে পারে যদিও এটি পুরানো (লেনদেনের টাইমস্ট্যাম্প)।
সর্বাধিক গুরুত্বপূর্ণ , পোস্টগ্রিসএসকিউএল এর এমভিসিসি মডেলের সাথে প্রত্যেকের জন্য একটি নতুন সারি সংস্করণ লেখা হয় UPDATE
, সারিটির ডেটা পরিবর্তিত হয় কিনা তা বিবেচনা করেই। এটি ইউপিএসইআরটি নিজেই, টেবিল ব্লাট, সূচক ফোটা, টেবিলে পরবর্তী ক্রিয়াকলাপের জন্য পারফরম্যান্স পেনাল্টি, VACUUM
ব্যয়ের ব্যয় করে। কয়েকটি অনুলিপিগুলির জন্য একটি সামান্য প্রভাব, তবে বেশিরভাগ ধরণের জন্য massive
এছাড়াও , কখনও কখনও এটি ব্যবহারিক বা এমনকি ব্যবহার করা সম্ভব হয় না ON CONFLICT DO UPDATE
। ম্যানুয়াল:
জন্য ON CONFLICT DO UPDATE
, একটি সরবরাহ করা conflict_target
আবশ্যক।
একাধিক সূচক / সীমাবদ্ধতা জড়িত থাকলে একটি একক "দ্বন্দ্ব লক্ষ্য" সম্ভব নয়।
খালি আপডেট এবং পার্শ্ব প্রতিক্রিয়া ছাড়াই আপনি প্রায় (প্রায়) একইটি অর্জন করতে পারেন। উত্থিত হতে পারে এমন সমস্ত সম্ভাব্য দ্বন্দ্বগুলি ON CONFLICT DO NOTHING
ধরার জন্য নীচের কয়েকটি সমাধান ("কোনও বিরোধের লক্ষ্য নয়") নিয়েও কাজ করে - যা কাঙ্ক্ষিত বা নাও হতে পারে।
একযোগে লেখার বোঝা ছাড়াই
WITH input_rows(usr, contact, name) AS (
VALUES
(text 'foo1', text 'bar1', text 'bob1') -- type casts in first row
, ('foo2', 'bar2', 'bob2')
-- more?
)
, ins AS (
INSERT INTO chats (usr, contact, name)
SELECT * FROM input_rows
ON CONFLICT (usr, contact) DO NOTHING
RETURNING id --, usr, contact -- return more columns?
)
SELECT 'i' AS source -- 'i' for 'inserted'
, id --, usr, contact -- return more columns?
FROM ins
UNION ALL
SELECT 's' AS source -- 's' for 'selected'
, c.id --, usr, contact -- return more columns?
FROM input_rows
JOIN chats c USING (usr, contact); -- columns of unique index
source
কলাম প্রদর্শন করতে কিভাবে এই কাজ করে একটি ঐচ্ছিক ছাড়াও। উভয়ের ক্ষেত্রে পার্থক্য বলতে খালি আপনার প্রয়োজন হতে পারে (খালি লেখার ক্ষেত্রে আরও একটি সুবিধা)।
চূড়ান্ত JOIN chats
কাজ করে কারণ সংযুক্ত ডেটা-সংশোধনকারী সিটিই থেকে সদ্য সন্নিবেশ করা সারিগুলি অন্তর্নিহিত সারণীতে এখনও দৃশ্যমান নয়। (একই এসকিউএল স্টেটমেন্টের সমস্ত অংশ অন্তর্নিহিত সারণীর একই স্ন্যাপশট দেখতে পাবে))
যেহেতু VALUES
এক্সপ্রেশনটি মুক্ত-স্থিত (সরাসরি কোনও সংযুক্ত নয় INSERT
) পোস্টগ্রাগেস লক্ষ্য কলামগুলি থেকে ডেটা ধরণের সংগ্রহ করতে পারে না এবং আপনাকে স্পষ্টত ধরণের ক্যাসেট যুক্ত করতে হতে পারে। ম্যানুয়াল:
কখন VALUES
ব্যবহার করা হয় INSERT
, মানগুলি স্বয়ংক্রিয়ভাবে সংশ্লিষ্ট গন্তব্য কলামের ডেটা টাইপের সাথে জোর করে। যখন এটি অন্য প্রসঙ্গে ব্যবহৃত হয়, সঠিক ডেটা ধরণের নির্দিষ্ট করা প্রয়োজন হতে পারে। যদি এন্ট্রিগুলি সমস্ত উদ্ধৃত আক্ষরিক ধ্রুবক হয় তবে সবার জন্য অনুমানিত ধরণ নির্ধারণ করতে প্রথমে জোর দেওয়া যথেষ্ট।
নিজেই ক্যোয়ারী (পার্শ্ব প্রতিক্রিয়াগুলি গণনা করছে না) সিটিইর ওভারহেডের কারণে এবং অতিরিক্ত (যা নিখুঁত সূচকটি সংজ্ঞা অনুসারে রয়েছে সেহেতু সস্তা হওয়া উচিত) - এর ফলে কয়েকটি দ্বিপের জন্য কিছুটা ব্যয়বহুল হতে পারে SELECT
- এর সাথে একটি অনন্য বাধা কার্যকর করা হয়েছে একটি সূচক)।
অনেক অনুলিপি জন্য দ্রুত হতে পারে (অনেক) । অতিরিক্ত লেখার কার্যকর ব্যয় অনেকগুলি বিষয়ের উপর নির্ভর করে।
তবে কোনও ক্ষেত্রে পার্শ্ব প্রতিক্রিয়া এবং লুকানো ব্যয় কম রয়েছে । এটি সম্ভবত সামগ্রিকভাবে সস্তা।
সংযুক্তি ক্রমগুলি এখনও উন্নত, যেহেতু দ্বন্দ্বগুলির পরীক্ষার আগে ডিফল্ট মান পূরণ করা হয় ।
সিটিই সম্পর্কে:
একযোগে লেখার বোঝা সহ
ডিফল্ট READ COMMITTED
লেনদেনের বিচ্ছিন্নতা ধরে নেওয়া । সম্পর্কিত:
বর্ণের অবস্থার বিরুদ্ধে রক্ষা করার সর্বোত্তম কৌশল নির্ভর করে সঠিক প্রয়োজনীয়তা, সারণীতে এবং ইউপিএসআরটিগুলিতে সারিগুলির সংখ্যা এবং আকার, একত্রে লেনদেনের সংখ্যা, দ্বন্দ্বের সম্ভাবনা, উপলভ্য সংস্থান এবং অন্যান্য কারণগুলির উপর ...
সংহত ইস্যু 1
যদি আপনার একযোগে লেনদেন কোনও সারিটিতে লিখিত থাকে যা আপনার লেনদেন এখন ইউপিএসআরটি-তে চেষ্টা করে, আপনার লেনদেনের অপরটির সমাপ্তির জন্য অপেক্ষা করতে হবে।
যদি অন্য লেনদেনটি ROLLBACK
(বা কোনও ত্রুটি, অর্থাৎ স্বয়ংক্রিয় ROLLBACK
) দিয়ে শেষ হয় তবে আপনার লেনদেন স্বাভাবিকভাবে এগিয়ে যেতে পারে। সামান্য সম্ভাব্য পার্শ্ব প্রতিক্রিয়া: অনুক্রমিক সংখ্যার ফাঁক। তবে কোনও সারি নেই।
যদি অন্য লেনদেনটি স্বাভাবিকভাবে শেষ হয় (অন্তর্নিহিত বা স্পষ্টভাবে COMMIT
), আপনি INSERT
একটি বিরোধ সনাক্ত করতে পারবেন ( UNIQUE
সূচক / সীমাবদ্ধতা নিখুঁত) এবং DO NOTHING
সুতরাং সারিটিও ফিরে পাবেন না। (এছাড়াও নীচে সামঞ্জস্য ইস্যুতে প্রদর্শিত সারিটি 2 টি লক করতে পারে না , কারণ এটি দৃশ্যমান নয় )) SELECT
কোয়েরির শুরু থেকে একই স্ন্যাপশটটি দেখায় এবং এখনও অদৃশ্য সারিটিও ফিরে আসতে পারে না।
ফলাফলের সেট থেকে এই জাতীয় কোনও সারি নিখোঁজ রয়েছে (যদিও তারা অন্তর্নিহিত টেবিলে বিদ্যমান রয়েছে)!
এটি যেমন ঠিক আছে তেমনও হতে পারে । বিশেষত যদি আপনি উদাহরণের মতো সারিগুলি না ফিরিয়ে থাকেন এবং সারিটি রয়েছে তা জেনে সন্তুষ্ট হন। যদি এটি যথেষ্ট ভাল না হয় তবে এর চারপাশে বিভিন্ন উপায় রয়েছে।
আপনি আউটপুটটির সারি গণনাটি পরীক্ষা করতে পারেন এবং বিবৃতিটি যদি ইনপুটটির সারি গণনার সাথে মেলে না তবে এটি পুনরাবৃত্তি করতে পারেন। বিরল ক্ষেত্রে যথেষ্ট হতে পারে। বিষয়টি হ'ল একটি নতুন ক্যোয়ারি শুরু করা (একই লেনদেনে হতে পারে), যা পরে সদ্য প্রতিশ্রুতিবদ্ধ সারিগুলি দেখতে পাবে।
অথবা ফলাফলের সারি অনুপস্থিত জন্য চেক মধ্যে একই প্রশ্নের সাথে এবং ওভাররাইট পাশব বল কৌতুক প্রদর্শিত যাদের Alextoni এর উত্তর ।
WITH input_rows(usr, contact, name) AS ( ... ) -- see above
, ins AS (
INSERT INTO chats AS c (usr, contact, name)
SELECT * FROM input_rows
ON CONFLICT (usr, contact) DO NOTHING
RETURNING id, usr, contact -- we need unique columns for later join
)
, sel AS (
SELECT 'i'::"char" AS source -- 'i' for 'inserted'
, id, usr, contact
FROM ins
UNION ALL
SELECT 's'::"char" AS source -- 's' for 'selected'
, c.id, usr, contact
FROM input_rows
JOIN chats c USING (usr, contact)
)
, ups AS ( -- RARE corner case
INSERT INTO chats AS c (usr, contact, name) -- another UPSERT, not just UPDATE
SELECT i.*
FROM input_rows i
LEFT JOIN sel s USING (usr, contact) -- columns of unique index
WHERE s.usr IS NULL -- missing!
ON CONFLICT (usr, contact) DO UPDATE -- we've asked nicely the 1st time ...
SET name = c.name -- ... this time we overwrite with old value
-- SET name = EXCLUDED.name -- alternatively overwrite with *new* value
RETURNING 'u'::"char" AS source -- 'u' for updated
, id --, usr, contact -- return more columns?
)
SELECT source, id FROM sel
UNION ALL
TABLE ups;
এটি উপরের প্রশ্নের মতো, তবে আমরা সম্পূর্ণ ফলাফলের সেটটি ups
ফেরত দেওয়ার আগে, আমরা সিটিইর সাথে আরও একটি পদক্ষেপ যুক্ত করি । সেই শেষ সিটিই বেশিরভাগ সময় কিছুই করবে না। যদি ফিরে আসা ফলাফল থেকে সারিগুলি নিখোঁজ হয় তবে আমরা নিষ্ঠুর শক্তি ব্যবহার করি।
আরও ওভারহেড, এখনও। প্রাক-বিদ্যমান সারিগুলির সাথে যত বেশি দ্বন্দ্ব, তত সহজেই এটি সহজ পদ্ধতির তুলনায় কার্যকর হবে।
একটি পার্শ্ব প্রতিক্রিয়া: ২ য় ইউপিএসআরটি সারি সারি লিখে দেয়, সুতরাং একই সারিতে তিন বা ততোধিক লেনদেন ওভারল্যাপ করে লিখলে এটি ডেডলকের সম্ভাবনা পুনরায় পরিচয় করিয়ে দেয় (নীচে দেখুন) । যদি সমস্যা হয় তবে আপনার আলাদা সমাধান দরকার - যেমন উপরে বর্ণিত পুরো বক্তব্যটি পুনরাবৃত্তি করা।
সংক্ষিপ্ত বিবরণ 2
যদি সমবর্তী লেনদেনগুলি প্রভাবিত সারিগুলির জড়িত কলামগুলিতে লিখতে পারে এবং আপনাকে নিশ্চিত করতে হবে যে সারিগুলি আপনি খুঁজে পেয়েছেন একই লেনদেনের পরবর্তী পর্যায়ে এখনও রয়েছে, আপনি বিদ্যমান সারিগুলি সস্তাভাবে সিটিইতে লক করতে পারেন ins
(যা অন্যথায় আনলক হয়ে যাবে) সঙ্গে:
...
ON CONFLICT (usr, contact) DO UPDATE
SET name = name WHERE FALSE -- never executed, but still locks the row
...
এবং পাশাপাশি একটি লকিং ক্লজ যুক্ত করুনSELECT
FOR UPDATE
।
এটি প্রতিযোগিতামূলক লেখার ক্রিয়াকলাপ লেনদেনের সমাপ্তি অবধি অপেক্ষা করে, যখন সমস্ত লক প্রকাশিত হয়। সুতরাং সংক্ষিপ্ত হতে।
আরও বিশদ এবং ব্যাখ্যা:
ডেডলক?
বিরুদ্ধে রক্ষার জন্য ডেডলক সারি সন্নিবেশ করার মাধ্যেমে সামঞ্জস্যপূর্ণ অর্ডার । দেখা:
ডেটা টাইপ এবং কাস্ট
ডেটা ধরণের টেমপ্লেট হিসাবে বিদ্যমান টেবিল ...
ফ্রি-স্ট্যান্ডিং VALUES
এক্সপ্রেশনটিতে ডেটার প্রথম সারির জন্য সুস্পষ্ট প্রকারের কাস্টগুলি অসুবিধা হতে পারে। এর চারপাশে উপায় আছে। সারি টেম্পলেট হিসাবে আপনি যে কোনও বিদ্যমান সম্পর্ক (টেবিল, দেখুন, ...) ব্যবহার করতে পারেন। লক্ষ্য সারণি ব্যবহারের ক্ষেত্রে সুস্পষ্ট পছন্দ। ইনপুট তথ্য স্বয়ংক্রিয়ভাবে উপযুক্ত ধরনের করতে বাধ্য করা হয়, মত VALUES
একটি ধারা INSERT
:
WITH input_rows AS (
(SELECT usr, contact, name FROM chats LIMIT 0) -- only copies column names and types
UNION ALL
VALUES
('foo1', 'bar1', 'bob1') -- no type casts here
, ('foo2', 'bar2', 'bob2')
)
...
এটি কিছু ডেটা ধরণের জন্য কাজ করে না। দেখা:
... এবং নাম
এটি সমস্ত ডেটা ধরণের জন্যও কাজ করে ।
সারণীর সমস্ত (শীর্ষস্থানীয়) কলামগুলিতে প্রবেশ করার সময়, আপনি কলামের নাম বাদ দিতে পারেন। chats
উদাহরণে ধরে নেওয়া সারণীটি কেবল ইউপিএসআরটিতে ব্যবহৃত 3 টি কলামগুলি নিয়ে গঠিত:
WITH input_rows AS (
SELECT * FROM (
VALUES
((NULL::chats).*) -- copies whole row definition
('foo1', 'bar1', 'bob1') -- no type casts needed
, ('foo2', 'bar2', 'bob2')
) sub
OFFSET 1
)
...
একপাশে: ব্যবহার করবেন না সংরক্ষিত শব্দ মত "user"
শনাক্তকারী হিসেবে। এটি একটি বোঝা ফুটগান। আইনী, লোয়ার-কেস, অব্যর্থ সনাক্তকারী সনাক্ত করুন। আমি এটি দিয়ে প্রতিস্থাপন usr
।
ON CONFLICT UPDATE
সারিটিতে পরিবর্তন রয়েছে তাই ব্যবহার করুন । তারপরেRETURNING
এটি ক্যাপচার করবে।