الخلية إزالة التكرارات من قاعدة بيانات كبيرة بسرعة

StackOverflow https://stackoverflow.com/questions/1651999

  •  22-07-2019
  •  | 
  •  

سؤال

لدي كبيرة (>Mil الصفوف) قاعدة بيانات MySQL افسدت من قبل التكرارات.أعتقد أنه يمكن أن يكون من 1/4 إلى 1/2 من كل db مليئة بهم.أنا بحاجة إلى التخلص منها بسرعة (يعني الاستعلام وقت التنفيذ).هنا كيف يبدو:
معرف (مؤشر) | النص1 | text2 | text3
text1 & text2 ينبغي أن تكون تركيبة فريدة من نوعها ، إذا كان هناك أي تكرار واحد فقط تركيبة مع text3 NOT NULL يجب أن تبقى.على سبيل المثال:

1 | abc | def | NULL  
2 | abc | def | ghi  
3 | abc | def | jkl  
4 | aaa | bbb | NULL  
5 | aaa | bbb | NULL  

...يصبح:

1 | abc | def | ghi   #(doesn't realy matter id:2 or id:3 survives)   
2 | aaa | bbb | NULL  #(if there's no NOT NULL text3, NULL will do)

الهويات الجديدة البارد يكون أي شيء أنها لا تعتمد على الجدول القديم معرفات.
لقد حاولت أشياء مثل:

CREATE TABLE tmp SELECT text1, text2, text3
FROM my_tbl;
GROUP BY text1, text2;
DROP TABLE my_tbl;
ALTER TABLE tmp RENAME TO my_tbl;

أو حدد متميزة وغيرها من الاختلافات.
في حين أنها تعمل على قواعد البيانات الصغيرة الاستعلام وقت التنفيذ على الألغام هو مجرد كبيرة (لم يحصل في نهاية المطاف ، في الواقع.> 20 دقيقة)

هل هناك أي أسرع طريقة للقيام بذلك ؟ الرجاء مساعدتي في حل هذه المشكلة.

هل كانت مفيدة؟

المحلول

وأعتقد أن هذا سوف نفعل ذلك، استخدام على مفتاح مكرر + ifnull ():

create table tmp like yourtable;

alter table tmp add unique (text1, text2);

insert into tmp select * from yourtable 
    on duplicate key update text3=ifnull(text3, values(text3));

rename table yourtable to deleteme, tmp to yourtable;

drop table deleteme;

وينبغي أن يكون أسرع بكثير من أي شيء يتطلب مجموعة من أو متميزا أو فرعي، أو حتى النظام من قبل. هذا حتى لا تحتاج إلى filesort، وهو ذاهب لقتل الأداء على جدول مؤقت كبير. سوف لا تزال بحاجة إلى مسح كامل على الجدول الأصلي، ولكن لا يوجد تجنب ذلك.

نصائح أخرى

وجدت هذا بسيط كود 1 الخط لتفعل بالضبط ما احتاجه:

ALTER IGNORE TABLE dupTest ADD UNIQUE INDEX(a,b);

ومأخوذة من: http://mediakey.dk/~cc/mysql-remove-duplicate-entries/

DELETE FROM dups
WHERE id NOT IN(
    SELECT id FROM (
        SELECT DISTINCT id, text1, text2
            FROM dups
        GROUP BY text1, text2
        ORDER BY text3 DESC
    ) as tmp
)

وهذا يستعلم عن سجلات ومجموعات من مجالات التميز وأوامر من قبل ID (يعني أننا اختيار الأول لم يكن سجل text3 باطل). ثم نختار ال معرف من أن نتيجة (هذه هي هويات جيدة ... هم لن يتم حذفه) وحذف كل المعرفات التي ARE NOT تلك.

وأي استفسار مثل هذا التأثير على الجدول بأكمله سيكون بطيئا. تحتاج فقط لتشغيله والسماح لها طرح حتى تتمكن من منعها في المستقبل.

وبعد أن كنت قد فعلت هذا "إصلاح" أود أن تطبيق INDEX فريد (text1، text2) لهذا الجدول. لمنع بوسيبيليتي من التكرارات في المستقبل.

إذا كنت تريد أن تذهب إلى "إنشاء جدول جديد واستبدال القديم واحد" الطريق. هل يمكن استخدام حدد البيان الداخلي جدا لخلق بيان إدراج الخاص بك.

والخلية محددة (يفترض يدعى الجدول الجديد my_tbl2 ولها بالضبط نفس الهيكل):

INSERT INTO my_tbl2
    SELECT DISTINCT id, text1, text2, text3
            FROM dups
        GROUP BY text1, text2
        ORDER BY text3 DESC

الخلية INSERT ... SELECT للحصول على مزيد من المعلومات.

وإزالة التكرارات دون إزالة المفاتيح الخارجية

create table tmp like mytable;
ALTER TABLE tmp ADD UNIQUE INDEX(text1, text2, text3, text4, text5, text6);
insert IGNORE into tmp select * from mytable;
delete from mytable where id not in ( select id from tmp);

إذا كان يمكنك إنشاء جدول جديد, تفعل ذلك مع مفتاح فريد على النص1 + text2 المجالات.ثم تضاف إلى الجدول تجاهل الأخطاء (باستخدام إدراج تجاهل الجملة):

select * from my_tbl order by text3 desc
  • أعتقد أن النظام text3 desc وضع بالقيم الخالية الماضي ، ولكن الاختيار المزدوج.

مؤشرات على جميع هذه الأعمدة يمكن أن تساعد الكثير ، ولكن خلق لهم الآن يمكن أن تكون بطيئة جدا.

لجداول كبيرة مع قليل من التكرارات، قد ترغب في تجنب نسخ الجدول بأكمله إلى مكان آخر. طريقة واحدة لإنشاء جدول مؤقت عقد الصفوف التي تريد الاحتفاظ بها (لكل مفتاح مع التكرار)، ثم حذف التكرار من الجدول الأصلي.

وتم اعطاء مثال هنا .

وليس لدي خبرة كبيرة مع الخلية. إذا كان لديه الدوال التحليلية محاولة:

delete from my_tbl
 where id in (
     select id 
       from (select id, row_number()
                            over (partition by text1, text2 order by text3 desc) as rn
               from my_tbl
               /* optional: where text1 like 'a%'  */
             ) as t2
       where rn > 1
     )

وشرط حيث اختياري يجعل وسائل سيكون لديك لتشغيله عدة مرات، واحدة لكل حرف، الخ إنشاء فهرس على text1؟

وقبل تشغيل هذا، تأكد من أن "تنازلي النص" سوف فرز القيم الخالية آخر في الخلية.

أعرف أن هذا هو الموضوع القديم ولكن لدي إلى حد ما فوضوي الطريقة أسرع بكثير وقابلة للتخصيص من حيث السرعة أقول 10sec بدلا من 100sec (10:1).

طريقة بلدي لا يتطلب كل هذا فوضوي الاشياء تحاول أن تتجنبها:

  • المجموعة من قبل (وبعد)
  • مجموعة concat مع النظام
  • 2 الجداول المؤقتة
  • استخدام الملفات على القرص!
  • بطريقة أو بأخرى (php?) حذف الملف بعد

ولكن عندما نتحدث عن ملايين (أو في حالتي عشرات الملايين) أنه يستحق ذلك.

على أي حال ليس كثيرا لأن التعليق في البرتغالية ولكن هنا هو بلدي العينة:

تحرير:إذا كنت تحصل على التعليقات انا سوف اشرح كيف يعمل :)

START TRANSACTION;

DROP temporary table if exists to_delete;

CREATE temporary table to_delete as (
    SELECT
        -- escolhe todos os IDs duplicados menos os que ficam na BD
        -- A ordem de escolha dos IDs é dada por "ORDER BY campo_ordenacao DESC" em que o primeiro é o que fica
        right(
            group_concat(id ORDER BY campos_ordenacao DESC SEPARATOR ','),
            length(group_concat(id ORDER BY campos_ordenacao DESC SEPARATOR ',')) 
                - locate(",",group_concat(id ORDER BY campos_ordenacao DESC SEPARATOR ','))
        ) as ids,

        count(*) as c

    -- Tabela a eliminar duplicados
    FROM teste_dup

    -- campos a usar para identificar  duplicados
    group by test_campo1, test_campo2, teste_campoN
    having count(*) > 1 -- é duplicado
);

-- aumenta o limite desta variável de sistema para o máx 
SET SESSION group_concat_max_len=4294967295;

-- envia os ids todos a eliminar para um ficheiro
select group_concat(ids SEPARATOR ',') from to_delete INTO OUTFILE 'sql.dat';

DROP temporary table if exists del3;
create temporary table del3 as (select CAST(1 as signed) as ix LIMIT 0);

-- insere os ids a eliminar numa tabela temporaria a partir do ficheiro
load data infile 'sql.dat' INTO TABLE del3
LINES TERMINATED BY ',';

alter table del3 add index(ix);

-- elimina os ids seleccionados
DELETE teste_dup -- tabela 
from teste_dup -- tabela

join del3 on id=ix;

COMMIT;

ويمكنك إزالة كافة إدخالات مكررة باستخدام هذا الاستعلام بسيطة. التي من شأنها تحديد كافة السجلات المكررة وإزالتها.

 DELETE i1 
FROM TABLE i1
LEFT JOIN TABLE i2
  ON i1.id = i2.id
 AND i1.colo = i2.customer_invoice_id
 AND i1.id < i2.id
WHERE i2.customer_invoice_id IS NOT NULL
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top