সদৃশ এন্ট্রিগুলি কীভাবে মুছবেন?


92

আমাকে বিদ্যমান টেবিলটিতে একটি অনন্য বাধা যুক্ত করতে হবে। টেবিলটিতে ইতিমধ্যে কয়েক মিলিয়ন সারি রয়েছে এবং এটির বেশিরভাগ সারি আমার যুক্ত হওয়া অনন্য বাধা লঙ্ঘন করে This

আপত্তিজনক সারিগুলি সরিয়ে দেওয়ার দ্রুততম পদ্ধতির কী? আমার কাছে একটি এসকিউএল স্টেটমেন্ট রয়েছে যা সদৃশগুলি সন্ধান করে এবং সেগুলি মুছে ফেলে, তবে এটি চালাতে চিরতরে নিচ্ছে। এই সমস্যা সমাধানের অন্য উপায় আছে? টেবিলের ব্যাক আপ করা যেতে পারে, তারপর সীমাবদ্ধতা যুক্ত হওয়ার পরে পুনরুদ্ধার করা?

উত্তর:


101

উদাহরণস্বরূপ আপনি করতে পারেন:

CREATE TABLE tmp ...
INSERT INTO tmp SELECT DISTINCT * FROM t;
DROP TABLE t;
ALTER TABLE tmp RENAME TO t;

4
আপনি কি এটি কলামের গোষ্ঠীর জন্য পৃথক করতে পারেন। হতে পারে "নির্বাচন ডিস্টিন্ট (টা, টিবি, টিসি), * ফ্রম টি"?
gjrwebber


36
সহজ টাইপ করতে: CREATE TABLE tmp AS SELECT ...;। তারপরে আপনার লেআউটটি কী তা নির্ধারণ করার দরকার tmpনেই। :)
র‌্যান্ডাল শোয়ার্টজ

9
এই উত্তরটি বেশ কয়েকটি কারণে আসলে খুব ভাল নয়। @ র‌্যাণ্ডেল একটির নাম দিয়েছে। বেশিরভাগ ক্ষেত্রে, বিশেষত যদি আপনার সূচক, সীমাবদ্ধতা, মতামত ইত্যাদির মতো নির্ভরশীল অবজেক্ট থাকে তবে উচ্চতর পদ্ধতিটি হ'ল একটি প্রকৃত টেম্পারারি টেবিল ব্যবহার করা , আসলটি ট্র্যাঙ্ক করা এবং ডেটা পুনরায় সন্নিবেশ করা।
এরউইন ব্র্যান্ডসেটেটার

7
আপনি সূচক সম্পর্কে সঠিক। ড্রপিং এবং পুনরুদ্ধার করা আরও দ্রুত। তবে অন্যান্য নির্ভরশীল অবজেক্টগুলি পুরোপুরি টেবিলটি ভেঙে ফেলতে বা আটকাতে পারে - যা অনুলিপিটি অনুলিপিটি তৈরি করার পরে খুঁজে পেতে পারে - "দ্রুততম পদ্ধতির জন্য" এত বেশি। তবুও, আপনি ডাউনভোট সম্পর্কে ঠিক বলেছেন। এটি ভিত্তিহীন, কারণ এটি কোনও খারাপ উত্তর নয়। এটা ঠিক যে ভাল না। আপনি ইনডেক্স বা নির্ভরশীল অবজেক্ট সম্পর্কে কিছু পয়েন্টার যুক্ত করতে পারেন বা ম্যানুয়ালটিতে আপনার মতো মন্তব্য বা কোনও ধরণের ব্যাখ্যায় লিঙ্ক রেখেছিলেন। আমার ধারণা, লোকেরা কীভাবে ভোট দেয় সে সম্পর্কে আমি হতাশ হয়ে পড়েছিলাম। ডাউনভোটটি সরানো হয়েছে।
এরউইন ব্র্যান্ডস্টেটার

173

এই পদ্ধতির কয়েকটি কিছুটা জটিল বলে মনে হচ্ছে এবং আমি সাধারণত এটি হিসাবে করি:

প্রদত্ত সারণী table, সর্বাধিক ফিল্ড 3 এর সাথে রেখে এটি (ফিল্ড 1, ফিল্ড 2) অনন্য করতে চান:

DELETE FROM table USING table alias 
  WHERE table.field1 = alias.field1 AND table.field2 = alias.field2 AND
    table.max_field < alias.max_field

উদাহরণস্বরূপ, আমার একটি টেবিল রয়েছে user_accountsএবং আমি ইমেইলে একটি অনন্য বাধা যুক্ত করতে চাই, তবে আমার কিছু নকল রয়েছে। এও বলুন যে আমি সর্বাধিক নির্মিত একটি (নকলের মধ্যে সর্বোচ্চ আইডি) রাখতে চাই keep

DELETE FROM user_accounts USING user_accounts ua2
  WHERE user_accounts.email = ua2.email AND user_account.id < ua2.id;
  • দ্রষ্টব্য - USINGস্ট্যান্ডার্ড এসকিউএল নয়, এটি একটি পোস্টগ্র্যাসকিউএল এক্সটেনশন (তবে একটি খুব দরকারী), তবে মূল প্রশ্নটি বিশেষত পোস্টগ্র্রেএসকিউএল উল্লেখ করেছে।

4
পোস্টগ্রাগে সেই দ্বিতীয় পন্থাটি খুব দ্রুত! ধন্যবাদ
এরিক বোম্যান - বিমূর্ত -

4
@ টিম আপনি কি আরও ভালভাবে পোস্টগ্রেসকিএল-তে কী ব্যাখ্যা করতে পারেন USING?
ফোপা লোন কনস্টান্টিন

4
এটি এখন পর্যন্ত সেরা উত্তর। আইডি তুলনার জন্য আপনার টেবিলে কোনও ক্রমিক কলাম না থাকলেও এই সহজ পদ্ধতির ব্যবহারের জন্য অস্থায়ীভাবে একটি যুক্ত করা ভাল।
শেন

4
আমি সবেমাত্র চেক করেছি। উত্তর হ্যাঁ, এটি হবে। অপেক্ষাকৃত কম (<) ব্যবহার করা আপনাকে কেবল সর্বোচ্চ আইডি সহ ছেড়ে দেয়, যখন এর চেয়ে বেশি (>) আপনাকে কেবল মিনি আইডি দিয়ে রেখে দেয়, বাকী অংশগুলি মুছে দেয়।
আন্দ্রে সি। অ্যান্ডারসন

4
@ শ্যান কেউ এটি ব্যবহার করতে পারেন: WHERE table1.ctid<table2.ctid- সিরিয়াল কলাম যুক্ত করার দরকার নেই
অ্যালেক্সকোভেলস্কি

25

নতুন টেবিল তৈরি করার পরিবর্তে, আপনি কাটা কাটার পরে একই টেবিলটিতে অনন্য সারিগুলি পুনরায় সন্নিবেশ করতে পারেন। এটা সব কি এক লেনদেন । Allyচ্ছিকভাবে, আপনি লেনদেন শেষে অস্থায়ী টেবিলটি স্বয়ংক্রিয়ভাবে দিয়ে ফেলতে পারেন ON COMMIT DROP। নিচে দেখ.

এই পদ্ধতিটি কেবল তখনই কার্যকর যখন সমস্ত টেবিলের উপর থেকে মুছে ফেলার জন্য প্রচুর সারি রয়েছে। মাত্র কয়েকটি অনুলিপি জন্য, একটি সমতল ব্যবহার করুন DELETE

আপনি লক্ষ লক্ষ সারি উল্লেখ করেছেন। অপারেশনটি দ্রুত করতে আপনি সেশনের জন্য পর্যাপ্ত অস্থায়ী বাফার বরাদ্দ করতে চান । আপনার বর্তমান সেশনে কোনও টেম্প বাফার ব্যবহারের আগে সেটিংসটি সামঞ্জস্য করতে হবে । আপনার টেবিলের আকারটি সন্ধান করুন:

SELECT pg_size_pretty(pg_relation_size('tbl'));

সে temp_buffersঅনুযায়ী সেট করুন । উদারভাবে গোল হয়ে উঠুন কারণ মেমরির প্রতিনিধির জন্য আরও কিছুটা র‌্যাম দরকার।

SET temp_buffers = 200MB;    -- example value

BEGIN;

-- CREATE TEMPORARY TABLE t_tmp ON COMMIT DROP AS -- drop temp table at commit
CREATE TEMPORARY TABLE t_tmp AS  -- retain temp table after commit
SELECT DISTINCT * FROM tbl;  -- DISTINCT folds duplicates

TRUNCATE tbl;

INSERT INTO tbl
SELECT * FROM t_tmp;
-- ORDER BY id; -- optionally "cluster" data while being at it.

COMMIT;

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

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

নোট TRUNCATEযেটির চেয়ে বেশি আক্রমণাত্মক লকিংয়ের প্রয়োজন DELETE। ভারী, একযোগে বোঝা সহ টেবিলগুলির জন্য এটি একটি সমস্যা হতে পারে।

যদি TRUNCATEকোনও বিকল্প না হয় বা সাধারণত ছোট থেকে মাঝারি টেবিলের জন্য একটি ডেটা-সংশোধনকারী সিটিই (পোস্টগ্রিস 9.1 +) সহ একই কৌশল থাকে :

WITH del AS (DELETE FROM tbl RETURNING *)
INSERT INTO tbl
SELECT DISTINCT * FROM del;
-- ORDER BY id; -- optionally "cluster" data while being at it.

বড় টেবিলগুলির জন্য ধীরে ধীরে, কারণ TRUNCATEসেখানে দ্রুত। ছোট টেবিলগুলির জন্য দ্রুত (এবং সহজ!) হতে পারে।

আপনার যদি কোনও নির্ভরযোগ্য অবজেক্ট না থাকে তবে আপনি একটি নতুন টেবিল তৈরি করতে পারেন এবং পুরাতনটিকে মুছতে পারেন, তবে আপনি এই সার্বজনীন পদ্ধতির মাধ্যমে খুব কমই কিছু অর্জন করতে পারেন।

খুব বড় টেবিলগুলির জন্য যা উপলব্ধ র‍্যামের সাথে খাপ খায় না , একটি নতুন টেবিল তৈরি করা যথেষ্ট দ্রুত হবে। নির্ভরশীল অবজেক্টের সাথে আপনাকে সম্ভাব্য সমস্যা / ওভারহেডের বিরুদ্ধে এটিকে বিবেচনা করতে হবে।


4
আমি এই পদ্ধতিরও ব্যবহার করেছি। তবে এটি ব্যক্তিগতভাবে হতে পারে তবে আমার টেম্প টেবিলটি মুছে ফেলা হয়েছে, এবং ছাঁটাইয়ের পরে পাওয়া যায় না ... যদি টেম্প টেবিলটি সফলভাবে তৈরি করা হয়েছিল এবং উপলভ্য থাকে তবে এই পদক্ষেপগুলি করতে সাবধান হন।
xlash

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

সতর্কতা: @ স্প্ল্যাশ থেকে সাবধান থাকুন - আমাকে আমার ডেটা পুনরায় আমদানি করতে হবে কারণ অস্থায়ী টেবিলটি অস্তিত্বহীন ছিল TRUNCATE। এরউইন যেমন বলেছিলেন, আপনার টেবিলটি কেটে ফেলার আগে নিশ্চিত হয়ে নিন যে এটি বিদ্যমান। @ কোডবিক্যাট এর উত্তর দেখুন
জর্ডান আর্সেনো

4
@ জর্ডান আরসেনো: আমি বিনা সংস্করণে চলে এসেছি ON COMMIT DROP, যাতে যে লোকেরা আমি "এক লেনদেনে" লিখেছি সেই অংশটি মিস করবেন না। এবং আমি "একটি লেনদেন" স্পষ্ট করতে BEGIN / COMMIT যুক্ত করেছি।
এরউইন ব্র্যান্ডসেটেটার

4
ব্যবহারের সাথে সমাধানটি 14 মিলিয়ন রেকর্ড সহ টেবিলে 3 ঘন্টারও বেশি সময় নিয়েছিল। টেমপোফার্স সহ এই সমাধানটি 13 মিনিট সময় নিয়েছিল। ধন্যবাদ
22

20

আপনি oid বা ctid ব্যবহার করতে পারেন যা সাধারণত টেবিলে একটি "অ-দৃশ্যমান" কলাম হয়:

DELETE FROM table
 WHERE ctid NOT IN
  (SELECT MAX(s.ctid)
    FROM table s
    GROUP BY s.column_has_be_distinct);

4
জায়গায় মুছে ফেলার জন্য , NOT EXISTSযথেষ্ট দ্রুত হওয়া উচিত : DELETE FROM tbl t WHERE EXISTS (SELECT 1 FROM tbl t1 WHERE t1.dist_col = t.dist_col AND t1.ctid > t.ctid)- বা বেঁচে যাওয়া বাছাইয়ের জন্য বাছাইয়ের জন্য অন্য কোনও কলাম বা কলামগুলির সেট ব্যবহার করুন।
এরউইন ব্র্যান্ডস্টেটার

@ ইরউইন ব্র্যান্ডসটেটার, আপনি যে ক্যোয়ারীটি ব্যবহার করবেন তা NOT EXISTSকি?
জন

4
@ জন: এটি অবশ্যই EXISTSএখানে রয়েছে। এটি এর মতো পড়ুন: "সমস্ত সারি মুছুন যেখানে অন্য কোনও সারি একই মানের সাথে dist_colবড় মানের সাথে উপস্থিত রয়েছে ctid"। দ্বিপের প্রতি গ্রুপে একমাত্র বেঁচে থাকা সবচেয়ে বড় সহ এক হবে ctid
এরউইন ব্র্যান্ডস্টেটার

আপনার কাছে কেবল কয়েকটি অনুলিপি সারি থাকলে সহজ সমাধান। LIMITডুপ্লিকেটের সংখ্যা জানা থাকলে এর সাথে ব্যবহার করা যেতে পারে ।
স্কিপি লে গ্র্যান্ড গৌরু

19

PostgreSQL উইন্ডো ফাংশনটি এই সমস্যার পক্ষে কার্যকর।

DELETE FROM tablename
WHERE id IN (SELECT id
              FROM (SELECT id,
                             row_number() over (partition BY column1, column2, column3 ORDER BY id) AS rnum
                     FROM tablename) t
              WHERE t.rnum > 1);

নকল মুছে ফেলা দেখুন ।


এবং "আইডি" এর পরিবর্তে "সিটিডি" ব্যবহার করে এটি পুরোপুরি সদৃশ সারিগুলির জন্য কাজ করে।
bradw2k

দুর্দান্ত সমাধান। আমি বিলিয়ন রেকর্ড সহ একটি টেবিলের জন্য এটি করতে হয়েছিল। আমি খণ্ডগুলিতে এটি করার জন্য অভ্যন্তরীণ নির্বাচনগুলিতে একটি WHERE যুক্ত করেছি।
জানুয়ারী

8

সদৃশ মুছতে সাধারণ জিজ্ঞাসা:

DELETE FROM table_name
WHERE ctid NOT IN (
  SELECT max(ctid) FROM table_name
  GROUP BY column1, [column 2, ...]
);

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


4
একমাত্র সর্বজনীন উত্তর! স্ব / কার্তেসিয়ান যোগ না দিয়ে কাজ করে। যদিও ক্লজটি সঠিকভাবে নির্দিষ্ট করা অপরিহার্য GROUP BY- এটি এখন 'লভ্যতা মাপদণ্ড' হওয়া উচিত যা এখন লঙ্ঘন করা হয়েছে বা যদি আপনি নকলগুলি সনাক্ত করতে চাওয়া চান। ভুল নির্দিষ্ট করা থাকলে এটি সঠিকভাবে কাজ করবে না
msciwoj

7

থেকে একটি পুরানো postgresql.org মেইলিং লিস্ট :

create table test ( a text, b text );

অনন্য মান values

insert into test values ( 'x', 'y');
insert into test values ( 'x', 'x');
insert into test values ( 'y', 'y' );
insert into test values ( 'y', 'x' );

সদৃশ মান

insert into test values ( 'x', 'y');
insert into test values ( 'x', 'x');
insert into test values ( 'y', 'y' );
insert into test values ( 'y', 'x' );

আরও একটি ডাবলিকেট

insert into test values ( 'x', 'y');

select oid, a, b from test;

সদৃশ সারি নির্বাচন করুন

select o.oid, o.a, o.b from test o
    where exists ( select 'x'
                   from test i
                   where     i.a = o.a
                         and i.b = o.b
                         and i.oid < o.oid
                 );

সদৃশ সারিগুলি মুছুন

দ্রষ্টব্য: পোস্টগ্রাইএসকিউএল fromএকটি মুছার দফায় উল্লিখিত টেবিলের উপর উপকরণগুলি সমর্থন করে না ।

delete from test
    where exists ( select 'x'
                   from test i
                   where     i.a = test.a
                         and i.b = test.b
                         and i.oid < test.oid
             );

আপনার ব্যাখ্যাটি খুব স্মার্ট, তবে আপনি একটি পয়েন্ট মিস করছেন, তৈরি টেবিলের মধ্যে oid নির্দিষ্ট করুন তবে কেবল ওডটি অ্যাক্সেস করুন ত্রুটি বার্তা প্রদর্শন
কল্যানিধি

@ কালানিধি উত্তরের উন্নতির বিষয়ে আপনার মন্তব্যের জন্য ধন্যবাদ, আমি এই বিষয়টি বিবেচনা করব।
ভাভিক আম্বানি 13 '13


'Oid' আপনাকে একটি ত্রুটি দিলে আপনি সিস্টেম কলাম 'সিটিডি' ব্যবহার করতে পারেন।
sul4bh

4

যোগদানের টেবিলে ডুপ্লিকেটগুলি সরিয়ে দিতে আমি কেবলমাত্র ইরউন ব্র্যান্ডসেট্টরের উত্তর সফলভাবে ব্যবহার করেছি (একটি টেবিলের নিজস্ব প্রাথমিক আইডির অভাব রয়েছে) তবে দেখা গেছে যে একটি গুরুত্বপূর্ণ ক্যাভিয়েট রয়েছে।

ON COMMIT DROPঅর্থ সহ অস্থায়ী টেবিল লেনদেনের শেষে নেমে আসবে। আমার জন্য, এর অর্থ এই যে আমি প্রবেশ করানোর সময় অস্থায়ী টেবিলটি আর উপলব্ধ ছিল না !

আমি সবেমাত্র করেছি CREATE TEMPORARY TABLE t_tmp AS SELECT DISTINCT * FROM tbl;এবং সবকিছু ঠিকঠাক কাজ করেছে।

অস্থায়ী টেবিলটি অধিবেশন শেষে ফেলে দেওয়া হবে।


3

এই ফাংশনটি অনুলিপিগুলি সরিয়ে না করে সদৃশগুলি সরিয়ে দেয় এবং এটি কোনও টেবিলে করে।

ব্যবহার: select remove_duplicates('mytable');

---
--- সরানো_লিপি (টেবিলের নাম) একটি সারণী থেকে সদৃশ রেকর্ডস সরিয়ে (সেট থেকে অনন্য সেট রূপান্তর)
---
ক্রিয়েট করুন বা রিপ্লেস ফাংশনটি সরান_যুক্তিগুলি (পাঠ্য) AS v হিসাবে বাতিল RE
ঘোষণা করুন
  টেবিলের নাম ALIAS FOR 1 এর জন্য;
শুরু করুন
  'তৈরি করুন টেবিল _DISTINCT_' পরীক্ষা করুন || টেবিলের নাম || 'AS (নির্বাচন থেকে নির্বাচন করুন' || টেবিলের নাম || ');';
  'থেকে মুছে ফেলুন' পরীক্ষা করুন || টেবিলের নাম || ';';
  'অন্তর্ভুক্তি প্রবেশ করুন' || টেবিলের নাম || '(নির্বাচন করুন * FROM _DISTINCT_' || টেবিলের নাম || ');';
  'ড্রপ টেবিল _DISTINCT_' নিষ্ক্রিয় করুন || টেবিলের নাম || ';';
  প্রত্যাবর্তন;
শেষ;
$$ ভাষা plpgsql;

3
DELETE FROM table
  WHERE something NOT IN
    (SELECT     MAX(s.something)
      FROM      table As s
      GROUP BY  s.this_thing, s.that_thing);

আমি বর্তমানে এটিই করছি, তবে এটি চালাতে খুব বেশি সময় নিচ্ছে।
gjrwebber

4
যদি টেবিলের একাধিক সারিগুলির কলামে একই মান থাকে তবে এটি ব্যর্থ হবে না?
শ্রীধর

3

আপনার যদি কেবল একটি বা কয়েকটি সদৃশ এন্ট্রি থাকে এবং সেগুলি সত্যই নকল করা হয় (যা তারা দুটিবার প্রদর্শিত হয়), আপনি ctidউপরে বর্ণিত "লুকানো" কলামটি একত্রে ব্যবহার করতে পারেন LIMIT:

DELETE FROM mytable WHERE ctid=(SELECT ctid FROM mytable WHERE […] LIMIT 1);

এটি নির্বাচিত সারিগুলির মধ্যে প্রথমটি মুছে ফেলবে।


আমি জানি এটি ওপি-র ইস্যুটিকে সম্বোধন করে না, যিনি অনেক মিলিয়ন মিলিতে নকল করেছেন, তবে তা যাইহোক সহায়ক হতে পারে।
স্কিপি লে গ্র্যান্ড গৌরু

এটি প্রতি সদৃশ সারির জন্য একবার চালাতে হবে। শেখবির উত্তরটি একবার চালানো দরকার।
bradw2k

3

প্রথমে আপনার "ডুপ্লিকেটগুলি" আপনি কোনটি রাখবেন তা সিদ্ধান্ত নিতে হবে। যদি সমস্ত কলামগুলি সমান হয়, ঠিক আছে, আপনি সেগুলির কোনওটি মুছতে পারেন ... তবে সম্ভবত আপনি কেবল সাম্প্রতিকতম বা অন্য কোনও মানদণ্ড রাখতে চান?

দ্রুততম উপায়টি উপরের প্রশ্নের আপনার উত্তর এবং টেবিলের নকলের% এর উপর নির্ভর করে। যদি আপনি আপনার সারিগুলির 50% সরিয়ে ফেলে থাকেন তবে আপনি আরও ভাল করছেন CREATE TABLE ... AS SELECT DISTINCT ... FROM ... ;এবং আপনি যদি 1% সারি মুছে ফেলেন তবে ডিলেটটি ব্যবহার করা ভাল।

এছাড়াও এই জাতীয় রক্ষণাবেক্ষণের জন্য, work_memআপনার র‌্যামের ভাল অংশে সেট করা ভাল: এক্সপ্ল্লেইন চালান, বিভিন্ন ধরণের এন / হ্যাশ পরীক্ষা করুন এবং work_mem আপনার র‌্যাম / 2 / এন তে সেট করুন lots প্রচুর র‌্যাম ব্যবহার করুন; এটা গতির জন্য ভাল। যতক্ষণ না আপনার কাছে কেবল একটি সমবর্তী সংযোগ থাকে ...


1

আমি পোস্টগ্রিজ এসকিউএল 8.4 এর সাথে কাজ করছি। যখন আমি প্রস্তাবিত কোডটি চালালাম তখন আমি দেখতে পেলাম যে এটি আসলে নকলগুলি সরিয়ে দিচ্ছে না। কিছু পরীক্ষা চালানোর সময়, আমি দেখতে পেলাম যে "DISTINCT চালু (সদৃশ_ কলাম_নাম)" এবং "অর্ডার বাই ডুপ্লিকেট_কলাম_নাম" কৌশলটি করেছে। আমি কোনও এসকিউএল গুরু নই, আমি এটি পোস্টগ্র্যাসকিউএল 8.4 নির্বাচন করুন ... ডিস্টিন্ট ডকটিতে পেয়েছি।

CREATE OR REPLACE FUNCTION remove_duplicates(text, text) RETURNS void AS $$
DECLARE
  tablename ALIAS FOR $1;
  duplicate_column ALIAS FOR $2;
BEGIN
  EXECUTE 'CREATE TEMPORARY TABLE _DISTINCT_' || tablename || ' AS (SELECT DISTINCT ON (' || duplicate_column || ') * FROM ' || tablename || ' ORDER BY ' || duplicate_column || ' ASC);';
  EXECUTE 'DELETE FROM ' || tablename || ';';
  EXECUTE 'INSERT INTO ' || tablename || ' (SELECT * FROM _DISTINCT_' || tablename || ');';
  EXECUTE 'DROP TABLE _DISTINCT_' || tablename || ';';
  RETURN;
END;
$$ LANGUAGE plpgsql;

1

এটি খুব সুন্দরভাবে কাজ করে এবং খুব দ্রুত:

CREATE INDEX otherTable_idx ON otherTable( colName );
CREATE TABLE newTable AS select DISTINCT ON (colName) col1,colName,col2 FROM otherTable;

1
DELETE FROM tablename
WHERE id IN (SELECT id
    FROM (SELECT id,ROW_NUMBER() OVER (partition BY column1, column2, column3 ORDER BY id) AS rnum
                 FROM tablename) t
          WHERE t.rnum > 1);

কলাম (গুলি) দ্বারা সদৃশ মুছুন এবং সর্বনিম্ন আইডি দিয়ে সারি রাখুন। প্যাটার্নটি নেওয়া হয় পোস্টগ্রিস উইকি

সিটিই ব্যবহার করে আপনি এর মাধ্যমে উপরের একটি আরও পাঠযোগ্য সংস্করণ অর্জন করতে পারেন

WITH duplicate_ids as (
    SELECT id, rnum 
    FROM num_of_rows
    WHERE rnum > 1
),
num_of_rows as (
    SELECT id, 
        ROW_NUMBER() over (partition BY column1, 
                                        column2, 
                                        column3 ORDER BY id) AS rnum
        FROM tablename
)
DELETE FROM tablename 
WHERE id IN (SELECT id from duplicate_ids)

1
CREATE TABLE test (col text);
INSERT INTO test VALUES
 ('1'),
 ('2'), ('2'),
 ('3'),
 ('4'), ('4'),
 ('5'),
 ('6'), ('6');
DELETE FROM test
 WHERE ctid in (
   SELECT t.ctid FROM (
     SELECT row_number() over (
               partition BY col
               ORDER BY col
               ) AS rnum,
            ctid FROM test
       ORDER BY col
     ) t
    WHERE t.rnum >1);

আমি এটি পরীক্ষা করেছি এবং এটি কার্যকর হয়েছে; আমি পঠনযোগ্যতার জন্য এটি ফর্ম্যাট করেছি। এটি বেশ পরিশীলিত দেখাচ্ছে তবে এটি কিছু ব্যাখ্যা ব্যবহার করতে পারে। কীভাবে কেউ তার নিজের ব্যবহারের ক্ষেত্রে এই উদাহরণটিকে পরিবর্তন করতে পারে?
টোবিয়াস
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.