下面這些方法在我虛擬機上做的測試,內存384M,交換分區1024M, test共300W數據,重複記錄3.5W,需求如題目所示,表結構如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | CREATE DATABASE /*!32312 IF NOT EXISTS*/ `test` /*!40100 DEFAULT CHARACTER SET utf8 */ ; USE `test`; /*Table structure for table `test` */ DROP TABLE IF EXISTS `test`; CREATE TABLE `test` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` char(20) DEFAULT NULL COMMENT '姓名' ,
`age` tinyint(4) DEFAULT NULL COMMENT '年齡' ,
`mate` tinyint(4) DEFAULT '1' COMMENT '有無配偶(1-有 0-無)' ,
PRIMARY KEY (`id`),
KEY `idx_name` (`name`),
KEY `idx_age` (`age`) ) ENGINE=MyISAM AUTO_INCREMENT=10 DEFAULT CHARSET=utf8; /*!40101 SET SQL_MODE=@OLD_SQL_MODE */ ; /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */ ; |
現有記錄:
1 2 3 4 5 6 7 8 | insert into `test`(`id`,`name`,`age`,`mate`) values (2, 'aaaaa' ,28,0), (3, 'bbbb' ,23,0), (4, 'cccc' ,25,1), (5, 'dddd' ,26,0), (6, 'eeee' ,24,0), (7, 'fffff' ,18,0), (8, 'eeee' ,40,1), (9, 'eeee' ,60,1); |
想去掉name重名的記錄,方法如下:
1.給name字段修改成唯一索引:
1 2 | drop index idx_name on test; alter table test add unique index (name); |
這樣當向表中添加相同記錄的時候,會返回1062的添加失敗信息。
但是有一種情況是表中已經有n個重複的記錄,這時候我們纔想起來要添加唯一索引,再執行上面的操作時,數據庫會告訴你已經有重複的記錄了,建立索引失敗,這時候,我們可以用下面的操作:
1 | alter ignore table test add unique idx_name (name); |
它會刪除重複的記錄(別怕,會保留一條),然後建立唯一索引,高效而且人性化。
2.重建表方法一:
創建另外一個表,爲了防止原來的表結構丟失,可以先創建一個這樣的”臨時表”,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | USE `test`; /*Table structure for table `test` */ DROP TABLE IF EXISTS `uniq_test`; CREATE TABLE `uniq_test` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` char(20) DEFAULT NULL COMMENT '姓名' ,
`age` tinyint(4) DEFAULT NULL COMMENT '年齡' ,
`mate` tinyint(4) DEFAULT '1' COMMENT '有無配偶(1-有 0-無)' ,
PRIMARY KEY (`id`),
KEY `idx_name` (`name`),
KEY `idx_age` (`age`) ) ENGINE=MyISAM AUTO_INCREMENT=10 DEFAULT CHARSET=utf8; |
從test表中查找數據,添加到uniq_test中:
1 2 3 | insert into uniq_test select * from test group by name; drop table test; rename table uniq_test to test; |
3.刪除重複記錄法:
創建一個表用來存放,要刪除的記錄的id信息:
1 2 3 4 | CREATE TABLE `tmp_ids` (
`id` int(11),
`name` char(20) ) ENGINE=MyISAM; |
如果要刪除的記錄不多的話,可以把這個表創建成內存表形式:
1 2 3 4 | CREATE TABLE `tmp_ids` (
`id` int(11),
`name` char(20) ) ENGINE=HEAP; |
然後在test表中刪除重複記錄:
1 2 3 | insert into tmp_ids select min(id),name from test group by name having count (*)>1 order by null; delete a.* from test a,tmp_ids b where b.name=a.name and a.id>b.id; truncate table tmp_ids; |
4.效率低下方法
1 2 3 4 5 6 7 8 9 | DELETE test AS a FROM test AS a, ( SELECT * FROM test GROUP BY name HAVING count (1) >1 order by null ) AS b WHERE a.name = b.name AND a.id > b.id; |
總結:
第一種方法歷史22分鐘,系統負載5左右;
第二種方法效率非常低下,把未知索引文件破壞,終止執行
第三種方法歷時17分鐘,其中
1 | insert into tmp_ids select min(id),name from test group by name having count (*)>1 order by null |
歷時15分鐘,刪除動作歷時2分鐘,系統負載3左右
第四種方法,執行過程中,把它test的索引文件都破壞了,可見”威力”之大。