删除非常大的数据库中的重复条目

时间:2018-11-13 14:50:16

标签: mysql

上周,我不小心在我们的网站上引入了一个错误,尽管它正确添加了新条目,但在接收到要插入数据库中的数据时一直报告错误。这样,信息就一直在发送,并且一直在报告,在数据库上写入和写入数据时出错,从而将每个条目复制了几十次到几百次。我不知道为什么循环停止,但最终给出了OK,并停止了编写。

我最初不知道该错误来自于我的代码,因此花了我几天的时间来解决它,与此同时,我们的数据库也遭到轰炸和淹没。

事后知悉,我做得不太好,但是我想修复自己弄错的东西。

我一直在寻找用于清除重复行的方法,并且有很多问题和答案,所以我坦率地提出了一个似乎可行的解决方案。

#include <iostream>
#include <condition_variable>
#include <thread>
#include <chrono>

std::condition_variable cv;
std::mutex cv_m;
int i = 0;
bool done = false;

void waits()
{
    std::unique_lock<std::mutex> lk(cv_m);
    std::cout << "Waiting... \n";
    cv.wait(lk, []{return i == 1;}); //Waiting 
    std::cout << "...finished waiting. i == 1\n";
    done = true;
}

void signals()
{
    std::this_thread::sleep_for(std::chrono::seconds(1));
    std::cout << "Notifying falsely...\n";
    cv.notify_one(); //Notifying

    std::unique_lock<std::mutex> lk(cv_m);//Is it possible for this line to execute
                                         //before cv.waits() in waits() tries to lock ?
    i = 1;
    while (!done)
    {
        std::cout << "Notifying true change...\n";
        lk.unlock();
        cv.notify_one(); 
        std::this_thread::sleep_for(std::chrono::seconds(1));
        lk.lock();
    }
}

int main()
{
    std::thread t1(waits), t2(signals);
    t1.join();
    t2.join();
}

这行得通,但是我必须在id的括号内进行,并限制在那里的搜索,否则它将花费很长时间并且在做任何事情之前都将其取消。即使这样做,网站停止运行也需要3到4分钟(我想数据库太忙了),并且清理数据库需要花费我很多的时间。

我一直在考虑一种简化方法,我认为我可以从介绍之日起搜索所有单个条目,将它们分组并列出列表,然后我可以制作一个循环通过的php文件在列表中搜索与列表中该项目相对应的所有条目,并删除除一个以外的所有条目。

我已经尝试过,使列表很简单,我认为:

DELETE FROM app_info
WHERE  `idinfo` NOT IN (SELECT minid
                        FROM   (SELECT Min(`idinfo`) AS minid
                                FROM   app_info
                                GROUP  BY `when`,
                                          `idbooth`,
                                          `iddongle`,
                                          `typeinfo`,
                                          `money`,
                                          `money2`,
                                          `currency`,
                                          `stock`,
                                          `i1`,
                                          `i2`,
                                          `i3`,
                                          `i4`,
                                          `i5`,
                                          `str1`,
                                          `str2`,
                                          `pbnew`,
                                          `in1`,
                                          `in2`,
                                          `in3`,
                                          `in4`,
                                          `in5`,
                                          `in6`,
                                          `in7`,
                                          `in8`) e)
       AND `idinfo` < 1545000
       AND `idinfo` > 1541500;

但是我无法重新构造我的第一个查询,以考虑第二个查询生成的信息。起初,我认为用我在第二个查询中分组的字段上的信息替换以前用来放在方括号中的“ WHEN”会有所帮助,但是如果这样做,我将得到0行,因此它什么也没做。 / p>

还取决于所选的条目,如果它具有太多副本(例如具有数百个副本),则无论如何都会使数据库崩溃……所以这似乎不是我要找的解决方案。

我不知道该怎么办了。如果重复条目的数量如此之多,我该如何清除它们而又不会使数据库崩溃?我猜想不可避免地会占用数据库,但是我可以发布一个停机维护时间,所以这不是问题。

2 个答案:

答案 0 :(得分:1)

我建议使用临时表存储重复的ID。

  1. 使用选择查询为您提供要删除的重复ID,但将记录插入到新表中。通过此组可能需要一段时间,但不会锁定数据库。

  2. 运行所需的任何测试,以验证临时表仅包含需要删除的ID。

  3. 在维护窗口中,备份后,在其中ID为ID的位置(从temp_table中选择ID)运行删除操作。

  4. 如果仍然太长,则可以从temp表中分批进行操作。

主要优点是您不会在表上运行那么大的查询,而同时锁定表以进行删除,甚至可能导致死锁。

答案 1 :(得分:1)

有效地,您可以利用INSERT IGNORE查询。步骤:

  • 创建一个与现有架构相似的临时表 表。

  • 向我们想要的列添加UNIQUE约束。

  • 运行INSERT IGNORE,将数据从原始表复制到临时表。这样,任何重复的行都会违反UNIQUE约束(已被忽略),因此不会插入到临时表中。

  • 将原始表重命名为其他名称,然后将临时表重命名 表到原始表。

  • 删除冗余表。

希望这会有所帮助。