PostgreSQL এ বাছাইয়ের মাধ্যমে আমি একটি নির্দিষ্ট সংখ্যক সারি কীভাবে মুছব?


107

আমি পোস্টগ্রিজ এসকিউএলে কিছু পুরানো মাইএসকিউএল ক্যোয়ারীগুলি পোর্ট করার চেষ্টা করছি, তবে এইটি নিয়ে আমার সমস্যা হচ্ছে:

DELETE FROM logtable ORDER BY timestamp LIMIT 10;

পোস্টগ্র্রেএসকিউএল এর মোছার সিনট্যাক্সে অর্ডার বা সীমাবদ্ধকরণের অনুমতি দেয় না এবং টেবিলটিতে প্রাথমিক কী নেই তাই আমি সাবকিউরি ব্যবহার করতে পারি না। অতিরিক্তভাবে, আমি এমন আচরণটি সংরক্ষণ করতে চাই যেখানে ক্যোয়ারী প্রদত্ত নম্বর বা রেকর্ডগুলি হুবহু মুছে ফেলে - উদাহরণস্বরূপ, যদি টেবিলটিতে 30 টি সারি থাকে তবে সেগুলির মধ্যে একই টাইমস্ট্যাম্প থাকে তবে আমি এখনও 10 মুছতে চাই, যদিও এটি কোনও ব্যাপার নয় although যা 10।

এরূপই PostgreSQL এ বাছাইয়ের মাধ্যমে আমি একটি নির্দিষ্ট সংখ্যক সারি কীভাবে মুছব?

সম্পাদনা করুন: কোনও প্রাথমিক কী মানে কোনও log_idকলাম বা অনুরূপ নেই। আহা, উত্তরাধিকার ব্যবস্থার আনন্দ!


1
প্রাইমারি কীটি যোগ করবেন না কেন? পিস O 'PostgreSQL মধ্যে পিষ্টক: alter table foo add column id serial primary key
ওয়েইন কনরাড

এটি আমার প্রাথমিক পদ্ধতির ছিল, তবে অন্যান্য প্রয়োজনীয়তা এটির প্রতিরোধ করে।
হোয়াটস

উত্তর:


159

আপনি এটি ব্যবহার করে দেখতে পারেন ctid:

DELETE FROM logtable
WHERE ctid IN (
    SELECT ctid
    FROM logtable
    ORDER BY timestamp
    LIMIT 10
)

ctidহল:

এর সারণির মধ্যে সারি সংস্করণের শারীরিক অবস্থান। মনে রাখবেন যে ctidসারিটি সংস্করণটি খুব দ্রুত সনাক্ত করতে ব্যবহার করা যেতে পারে, তবে একটি সারি ctidপরিবর্তিত হবে যদি তা আপডেট হয় বা সরিয়ে নেওয়া হয় VACUUM FULL। সুতরাং ctidএকটি দীর্ঘমেয়াদী সারি সনাক্তকারী হিসাবে অকেজো।

এর রয়েছে oidকিন্তু যে শুধুমাত্র যদি উপস্থিত থাকে আপনি নির্দিষ্টভাবে যখন আপনি সারণি তৈরি এটা জন্য জিজ্ঞাসা করুন।


এটি কাজ করে, তবে এটি কতটা নির্ভরযোগ্য? আমার কি খুঁজে পাওয়ার দরকার আছে? কোয়েরিটি চলমান থাকাকালীন VACUUM FULLযদি তারা ctidটেবিলের মানগুলি পরিবর্তন করে তবে অটোভ্যাকুমের জন্য সমস্যা সৃষ্টি করা সম্ভব ?
হোয়াটস

2
বর্ধিত ভ্যাকুয়াম সিটিড পরিবর্তন করবে না বলে আমি মনে করি না। যেহেতু প্রতিটি পৃষ্ঠার মধ্যে কেবল কমপ্যাক্ট থাকে এবং সিটিডি হ'ল একটি লাইন নম্বর কোনও পৃষ্ঠা অফসেট নয়। একটি ভ্যাকুয়াম পূর্ণ বা একটি ক্লাস্টার অপারেশন হবে ctid পরিবর্তন করেন, কিন্তু যারা অপারেশন প্রথম টেবিলের উপর একটি অ্যাক্সেস একচেটিয়া লক নিতে।
আরাকনিদ

@ হোয়াটসিট: ctidডকুমেন্টেশনের আমার ছাপটি হ'ল এই ডিলেটটি কাজটি ঠিকঠাক ctidকরার পক্ষে যথেষ্ট স্থিতিশীল তবে যথেষ্ট স্থিতিশীল নয়, উদাহরণস্বরূপ, ঘেটো-এফকে হিসাবে অন্য টেবিলে রাখুন। সম্ভবত আপনি আপডেট করবেন না logtable, যাতে আপনার সম্পর্কে যে পরিবর্তন চিন্তা করতে হবে না ctids এবং VACUUM FULLসারণী (লক করে postgresql.org/docs/current/static/routine-vacuuming.html ) আপনি সম্পর্কে চিন্তা করতে হবে না অন্য যে উপায় ctidপরিবর্তন করতে পারে। @ আরাকনিডের পোস্টগ্রিএসকিউএল-ফু বেশ শক্তিশালী এবং ডক্সগুলি বুট করার জন্য তার সাথে একমত হয়।
মিউ খুব ছোট

স্পষ্টির জন্য আপনাকে উভয়কে ধন্যবাদ। আমি দস্তাবেজগুলি সন্ধান করেছি কিন্তু আমি নিশ্চিত ছিলাম না যে আমি তাদের সঠিকভাবে ব্যাখ্যা করছি। আমি এর আগে কখনও সিটিডের মুখোমুখি হইনি।
হোয়াটস

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

53

পোস্টগ্রিস ডক্স আইএন এবং সাবকিউয়ের পরিবর্তে অ্যারে ব্যবহার করার পরামর্শ দেয়। এটি আরও দ্রুত কাজ করা উচিত

DELETE FROM logtable 
WHERE id = any (array(SELECT id FROM logtable ORDER BY timestamp LIMIT 10));

এটি এবং অন্যান্য কিছু কৌশল এখানে পাওয়া যাবে


@ কনরাড গারুস এখানে আপনি লিঙ্কটি যান , 'দ্রুত প্রথম এন সারিগুলি সরিয়ে
ফেলুন

1
@ ব্ল্যাকেরেগালিয়া না, কারণ সারণীতে কোনও প্রাথমিক কী নেই। এটি প্রথম 10-তে পাওয়া একটি "আইডি" সহ সমস্ত সারি মুছে ফেলবে all
ফিলিপ হোয়াইটহাউস

6
যদি কোয়েরি অপটিমাইজারের মধ্যে বাগের মতো শোনার any (array( ... ));চেয়ে দ্রুত হয় in ( ... )- তবে এটি সেই রূপান্তরটি চিহ্নিত করতে এবং ডেটা দিয়ে নিজেই একই জিনিসটি করতে সক্ষম হওয়া উচিত।
rjmunro

1
আমি এই পদ্ধতিটি INএকটি UPDATE(যা পার্থক্য হতে পারে) ব্যবহার করার চেয়ে যথেষ্ট ধীর বলে মনে করেছি ।
jmervine

1
12 জিবি টেবিলে পরিমাপ: প্রথম ক্যোয়ারী 450..1000 এমএস, দ্বিতীয় এক 5..7 সেকেন্ড: দ্রুত এক: সিএস_লগিং থেকে আইডি = যে কোনওটি (অ্যারে (সিএস_লগিং থেকে আইডি নির্বাচন করুন যেখানে তারিখ_ক্রেট করা হয়েছে (এখন)) - বিরতি 1 দিন '* 30 এবং পার্টিশন_কি'% আই 'এর মতো আইডি সীমা 500 এর অর্ডার দিয়ে করুন) আস্তে আস্তে: সিএস_লগিং থেকে আইডিটি মুছে ফেলুন (সিএস_লগিং থেকে আইডি নির্বাচন করুন যেখানে তারিখ_তখন তৈরি হয়েছে <এখন () - ব্যবধান' 1 দিন '* 30 এবং পার্টিশন_কি'% এর মত) আমি আইডি সীমা 500 দ্বারা অর্ডার করছি)। সিটিডি ব্যবহার করা ছিল অনেক ধীর (মিনিট)।
গাইডো endণদানকারীরা


2

ধরে নিই যে আপনি যে কোনও 10 টি রেকর্ড মুছতে চান (অর্ডার না করে) আপনি এটি করতে পারেন:

DELETE FROM logtable as t1 WHERE t1.ctid < (select t2.ctid from logtable as t2  where (Select count(*) from logtable t3  where t3.ctid < t2.ctid ) = 10 LIMIT 1);

আমার ব্যবহারের ক্ষেত্রে, 10 এম রেকর্ডস মোছা, এটি দ্রুত পরিণত হয়েছিল।


1

আপনি কোনও পদ্ধতি লিখতে পারবেন যা পৃথক লাইনের জন্য মুছে ফেলার জন্য লুপ করে, প্রক্রিয়াটি আপনি মুছতে চান এমন আইটেমের সংখ্যা নির্দিষ্ট করতে একটি পরামিতি নিতে পারে। তবে এটি মাইএসকিউএলের তুলনায় কিছুটা ওভারকিল।


0

আপনার যদি প্রাথমিক কী না থাকে তবে আপনি সম্মিলিত কী সহ যেখানে বিন্যাসটি অ্যারে ব্যবহার করতে পারেন।

delete from table1 where (schema,id,lac,cid) in (select schema,id,lac,cid from table1 where lac = 0 limit 1000);

এটি আমার পক্ষে কাজ করেছে।

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