对于有大量重复数据的表添加唯一索引
2014-11-24 14:45
393 查看
遇到如题的这么一个场景:需要在MySQL的一张innodb引擎的表(tableA)上添加一个唯一索引(idx_col1_u)。但是表中已经有大量重复数据,对于每个key(col1),有的重复2行,有的重复N行。
此时,做数据的手工清理,或者SQL处理无疑是非常耗时的。
1.Alterignoretablecometohelp
印象中MySQL有一个独有的alterignoreadduniqueindex的语法。语法如下:
ALTER[ONLINE|OFFLINE][IGNORE]TABLE[code]tbl_name
行为类似于insertignore,即遇到冲突的unique数据则直接抛弃而不报错。对于加唯一索引的情况来说就是建一张空表,然后加上唯一索引,将老数据用insertignore语法插入到新表中,遇到冲突则抛弃数据。
文档中对于alterignore的注释:详见:
IGNOREisaMySQLextensiontostandardSQL.Itcontrolshow
ALTERTABLEworksifthereareduplicatesonuniquekeysinthenewtableorifwarningsoccurwhenstrictmodeisenabled.If
IGNOREisnotspecified,thecopyisabortedandrolledbackifduplicate-keyerrorsoccur.If
IGNOREisspecified,onlythefirstrowisusedofrowswithduplicatesonauniquekey.Theotherconflictingrowsaredeleted.Incorrectvaluesaretruncatedtotheclosestmatchingacceptablevalue.
2.#1062-Duplicateentry
然而在执行了alterignoretabletableAadduniqueindexidx_col1_u(col1)后,还是报了以下错误:#1062-Duplicateentry'111'forkey'col1'.
不是会自动丢弃重复数据么?世界观被颠覆了。查了下资料原来是alterignore的语法不支持innodb。
得知alterignore的实现完全取决于存储引擎的内部实现,而不是server端强制的,具体描述如下:
ForALTERTABLEwiththeIGNOREkeyword,IGNOREisnowpartofthe
informationprovidedtothestorageengine.Itisuptothestorage
enginewhethertousethiswhenchoosingbetweenthein-placeorcopy
algorithmforalteringthetable.ForInnoDBindexoperations,IGNORE
isnotusediftheindexisunique,sothecopyalgorithmisused
详见:
3.解决方案
当然解决这个问题的tricky的方法还是有的,也比较直白粗暴。具体如下:ALTERTABLEtableAENGINEMyISAM;
ALTERIGNORETABLEtableAADDUNIQUEINDEXidx_col1_u(col1)
ALTERTABLEtableENGINEInnoDB;
updatedin2013-09-26:
@jyzhou分享提到,可以不用改成MyISAM,而直接使用setold_alter_table=1;的方法。具体做法如下:
setold_alter_table=1;
ALTERIGNORETABLEtableAADDUNIQUEINDEXidx_col1_u(col1)
具体原理: