MySQL重複データの削除方法

5516 ワード

この例では、MySQLの重複データを削除する方法について説明します.皆さんの参考にしてください.具体的な方法は以下の通りです.
プロジェクトの背景
最近やったlinux性能採集プロジェクトでは、スレッドのプログラムの入庫が遅いことがわかり、さらによく位置決めすると、データベースに冗長なデータがたくさんあることがわかりました.収集では、同じデバイスの場合、同じ時点で1つのデータしかないはずですが、データベースには複数のデータが格納されています.どのようにしてこの結果をもたらしたのか、しばらくは考えられませんでしたが、入庫が遅いという問題を解決するためには、まず冗長データを削除します.
問題の説明
データベースのテーブル構造は、次のように簡単です.

   +----------------+--------------+------+-----+---------+-------+ 
  
| Field          | Type         | Null | Key | Default | Extra |
+----------------+--------------+------+-----+---------+-------+
| id             | varchar(255) | NO   | PRI | NULL    |       |
| conf_id        | varchar(255) | NO   | MUL | NULL    |       |
| insert_time    | datetime     | YES  |     | NULL    |       |
| cpu_usage      | float(11,2)  | YES  |     | NULL    |       |
| memory_usage   | float(11,2)  | YES  |     | NULL    |       |
| io_usage_write | float(11,2)  | YES  |     | NULL    |       |
| io_usage_read  | float(11,2)  | YES  |     | NULL    |       |
+----------------+--------------+------+-----+---------+-------+

すべてのデータ量の問合せ

   select count(*) from perf_linux; 
 

出力427366
すべての時点で異なるデバイスのデータ量をクエリー

   select count(distinct conf_id, insert_time) from perf_linux ; 
 

出力42387
以上のデータから、データが10倍ほど冗長になっていることがわかります.
時間別にグループ分けしてみてください.

   select id, conf_id ,insert_time from perf_linux order by insert_time, conf_id; 
 

出力:

   | 2a79f7cd-43a9-4c7b-adb2-316b6c04283e | 1       | 2014-12-09 15:09:14 | 
  
| 50d6f6c2-9c8b-45fd-98fd-2be211221cfd | 1       | 2014-12-09 15:09:14 |
| 740b52e1-e868-4074-ba36-74e2634401b3 | 1       | 2014-12-09 15:09:14 |
| 8b0096a4-9e85-417b-a131-e3505ca79a9c | 1       | 2014-12-09 15:09:14 |
| 90a9e882-5220-4508-a56f-8d4ab4a7929b | 1       | 2014-12-09 15:09:14 |
| d17403ed-24a4-45e8-b51b-2a95118383d9 | 1       | 2014-12-09 15:09:14 |
| 0c2da917-579b-4080-857d-7159f38b44ac | 2       | 2014-12-09 15:09:14 |
| 263083eb-8f63-4d2b-a03f-3320aa678735 | 2       | 2014-12-09 15:09:14 |
| d6c57a38-080b-465a-a55a-beafd9daf32d | 2       | 2014-12-09 15:09:14 |
| f672227b-1fb8-4b85-880d-2cc34b02880d | 2       | 2014-12-09 15:09:14 |
| f80020fe-6cb5-48ec-beb0-4e8ebeb0ca57 | 2       | 2014-12-09 15:09:14 |
| ff633a35-824d-49ba-b78c-5bcc5df8d1cc | 2       | 2014-12-09 15:09:14 |
| 5c41e48a-abfc-4108-a00e-ca7def7d5a5a | 3       | 2014-12-09 15:09:14 |
| 60b7ab9e-c91a-4020-a6d3-7bceb1dc47c5 | 3       | 2014-12-09 15:09:14 |
| 7b6cd2b8-ac6d-43eb-8858-e15885e676c8 | 3       | 2014-12-09 15:09:14 |
| d53a3df5-08c4-4604-8fac-cb51077935f6 | 3       | 2014-12-09 15:09:14 |
| d9e4ba14-f98d-42a8-b3bc-2879d58aa797 | 3       | 2014-12-09 15:09:14 |
| f56f82f6-32a7-47f7-ae07-b13168743884 | 3       | 2014-12-09 15:09:14 |
| 076c4c1b-0028-4a9c-a8c4-de655bd6ab6b | 4       | 2014-12-09 15:09:14 |
| 2a90ad9e-11a5-4707-95e8-78491da658ad | 4       | 2014-12-09 15:09:14 |
| 3b17ad1d-e589-4b65-93a7-d61fc99b4071 | 4       | 2014-12-09 15:09:14 |
| 6988d6cf-44ef-47f7-808d-09791caf2d90 | 4       | 2014-12-09 15:09:14 |
| 8404d281-f9e5-4153-a47e-128c05386758 | 4       | 2014-12-09 15:09:14 |
| e042e310-7ff2-4e4d-8c98-71e3e4d57828 | 4       | 2014-12-09 15:09:14 |
+--------------------------------------+---------+---------------------+

上の図から分かるように、同じ時点の同じデバイスのデータには冗長性があります.今、これらの冗長性データを削除します.
解決策
まずconf_に従うべきだidと時点で判断し,グループクエリーを行い,各グループからもう1つ取ればよい.グループ分けは簡単ですが、グループ分けはどうやって1つ取りますか?中間表の形式を採用しました.
中間テーブルを作成し、データを中間テーブルにインポート

   create table perf_linux_t like perf_linux; 
  
insert into perf_linux_t select * from perf_linux;

中間テーブルにフィールドを追加します.このフィールドは自己成長です.

   ALTER TABLE `perf_linux_t` 
  
ADD COLUMN `auto_id` INT NOT NULL AUTO_INCREMENT ,
DROP PRIMARY KEY,
ADD PRIMARY KEY (`auto_id`);

不要なデータの削除
まず調べてみます

   select min(auto_id) as auto_id from perf_linux_t group by insert_time ; 
 

間違ったデータを削除

   delete  from perf_linux_t where auto_id not in (select min(auto_id) as auto_id from perf_linux_t group by insert_time); 
 

スロー、出力エラー:
You can't specify target table 'perf_linux_t' for update in FROM clause
削除できませんね.じゃ、中間表をもう一つ作るしかありません.
中間表の再構築

   create table tmp like perf_linux_t; 
 

考え方を変えて、合わないデータを削除するのではなく、合ったデータをこの新しいテーブルに保存します.

   insert into tmp select * from perf_linux_t where auto_id in (select min(auto_id) as auto_id from perf_linux_t group by insert_time,conf_id ); 
 

この表の不要な列を削除する

   ALTER TABLE `tmp` 
  
DROP COLUMN `auto_id`,
DROP PRIMARY KEY;

リードバックデータ
元のデータを削除

   truncate table perf_linux; 
 

データの挿入

   insert into perf_linux select * from tmp; 
 

中間テーブルの削除

   drop table tmp; 
  
drop table perf_linux_t;

まとめ
この方法により,データは42387個となり,冗長なデータが削除された.しかし、実際にはプログラムの問題は完全に位置決めされていないので、問題を位置決めするには観察する必要があります.
本稿で述べたmysqlデータベースのプログラム設計に役立つことを願っています.