咱們在向數據庫裏批量插入數據的時候,會遇到要將原有主鍵或者unique索引所在記錄更新的狀況,而若是沒有主鍵或者unique索引衝突的時候,直接執行插入操做。mysql
這種狀況下,有三種方式執行:sql
直接每條select, 判斷, 而後insert,毫無疑問,這是最笨的方法了,不斷的查詢判斷,有主鍵或索引衝突,執行update,不然執行insert. 數據量稍微大一點這種方式就不行了。數據庫
稍微高級一些的方式。性能
這是mysql自身的一個語法,使用 replace
的時候。其語法爲:大數據
replace into tablename (f1, f2, f3) values(vf1, vf2, vf3),(vvf1, vvf2, vvf3)
這中語法會自動查詢主鍵或索引衝突,若有衝突,他會先刪除原有的數據記錄,而後執行插入新的數據。優化
這也是一種方式,mysql的insert操做中也給了一種方式,語法以下:code
INSERT INTO table (a,b,c) VALUES (1,2,3) ON DUPLICATE KEY UPDATE c=c+1;
在insert時判斷是否已有主鍵或索引重複,若是有,一句update後面的表達式執行更新,不然,執行插入。索引
第一種方式不說了,replace和insert on duplicate key這兩種方式,哪中效率更高一些呢,畢竟,咱們的執行sql,追求的就是高效。事務
在最終實踐結果中,獲得接過以下:
在數據庫數據量不多的時候, 這兩種方式都很快,不管是直接的插入仍是有衝突時的更新,都不錯,但在數據庫表的內容數量比較大(如百萬級)的時候,兩種方式就不太同樣了,內存
首先是直接的插入
操做,兩種的插入效率都略低, 好比直接向表裏插入1000條數據(百萬級的表(innodb引擎)),兩者都差很少須要5,6甚至十幾秒。究其緣由,個人主機性能是一方面,但在向大數據表批量插入數據的時候,每次的插入都要維護索引的, 索引當然能夠提升查詢的效率,但在更新表尤爲是大表的時候,索引就成了一個不得不考慮的問題了。
其次是更新
表,這裏的更新的時候是帶主鍵值的(由於我是從另外一個表獲取數據再插入,要求主鍵不能變)
一樣直接更新1000條數據, replace的操做要比insert on duplicate的操做低太多太多, 當insert瞬間完成(感受)的時候,replace要7,8s, replace慢的緣由我是知道的,在更新數據的時候,要先刪除舊的,而後插入新的,在這個過程當中,還要從新維護索引,因此速度慢,但爲什麼insert on duplicate的更新卻那麼快呢。 在向老大請教後,終於知道,insert on duplicate 的更新操做雖然也會更新數據,但其對主鍵的索引卻不會有改變,也就是說,insert on duplicate 更新對主鍵索引沒有影響.所以對索引的維護成本就低了一些(若是更新的字段不包括主鍵,那就要另說了
)。
在向數據量大的表裏批量插入更新數據的時候,隨着插入的數量愈來愈多,會致使愈來愈慢,這種狀況下,由於咱們用的innodb表,能夠開啓事務, 每次批量執行一批數據更新後提交, 再從新開事務處理下批數據,這樣會有效增長效率
還有說明一下: 當咱們執行數據庫的插入和更新操做很慢的時候,不只僅是語句,主機性能也很重要, 好比內存和cpu, 若是是虛擬機要相應適當調整, 若是在各類優化了以後效率仍是很低, 但cpu和內存的佔用卻不高,那麼就極可能是磁盤的IO性能了,這也會致使數據的更新速度慢。
PS: 數據庫菜鳥一個, 所知有限, 若有紕漏, 還請指教