mysql對大表執行update速度慢時,試試改用insert可能會有意想不到的發現

實例:需要根據用戶日誌的ip地址計算出其地理地址

表結構:

用戶日誌表(200萬條記錄),其中address是待填充的字段:

CREATE TABLE `tmp_open_ip` (
  `email` varchar(60) NOT NULL DEFAULT '',
  `address` varchar(50) NOT NULL DEFAULT '',
  `ip` int(10) unsigned NOT NULL DEFAULT '0',
  KEY `email` (`email`),
  KEY `ip` (`ip`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8

另ip地址數據庫表(44萬條記錄)

CREATE TABLE `ip` ( `s` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '開始ip', `e` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '結束ip', `a` varchar(50) NOT NULL DEFAULT '', KEY `s` (`s`), KEY `e` (`e`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8       

需要根據用戶日誌表 tmp_open_ip 裏的 ip字段到ip地址數據庫表裏查詢出對應的地理地址,將地址填充到address字段。

使用如下update語句執行:

UPDATE tmp_open_ip AS u 
INNER JOIN ip 
ON u.ip BETWEEN ip.s AND ip.e 
SET u.address = ip.a

在筆者的電腦上運行了速度非常之慢,執行了一個多小時(4500s)都沒有完,也不知道還要多久。

實在看不過去,於是想到使用insert 是否會快一些,於是重新導一張表 tmp_open_log 與tmp_open_log完全一致。

創建一張表 tmp_open_address,是insert的目標表,爲了速度更快,沒建索引:

CREATE TABLE `tmp_open_address` ( `email` varchar(60) NOT NULL DEFAULT '', `address` varchar(50) NOT NULL DEFAULT '', `ip` int(10) unsigned NOT NULL DEFAULT '0' ) ENGINE=MyISAM DEFAULT CHARSET=utf8      

執行insert 語句

insert into tmp_open_address (email,address,ip) select l.email,ip.a,l.ip  from  tmp_open_log as l inner join ip on l.ip between ip.s and ip.e ;     
/* Affected rows: 2,543,124  Found rows: 0  Warnings: 0  Duration for 3 queries: 16.922 sec. */     

不到17s!本來還想去倒杯水、稍事休息一下,結果已經執行完畢。

到本文寫完時,前面的update語句已經執行了5000s,結束仍是遙遙無期。

所以,對於大數據量執行update時,可以考慮改用insert 語句實現,可能麻煩一些,但高速帶來的收益遠大於麻煩!

後記:

直接殺死了update進程,去看看update執行了多少:運行

SELECT * FROM `tmp_open_ip` where address!=''

結果只有 11,373 ,照這個速度,要運行N天....

轉載自:http://www.path8.net/tn/archives/5881

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章