看了該文章之后,很受啟發,mysql在update時,一般也是先select。但注意,在Read Committed隔離級別下,如果沒有使用索引,並不會鎖住整個表,
還是只鎖住滿足查詢條件的記錄而已。使用索引的最佳方式是使用主鍵,如果我們知道主鍵的范圍(只要是精確范圍的超集就可以了),那可以在查詢
條件中加上主鍵的范圍,這樣查詢時,會使用主鍵索引,就可以提高查詢的速度了。這樣,我們不用單獨再給其它字段加索引,使用已知的索引就可以
加速查詢,這種方式感覺很屌。
原文:http://blog.csdn.net/bruce128/article/details/17426671
問題sql背景:項目有6個表的要根據pid字段要寫入對應的brand_id字段。但是這個其中有兩個表是千萬級別的。我的worker運行之后,線上的MySQL主從同步立刻延遲了!運行了一個多小時之后,居然延遲到了40分鍾,而且只更新了十幾萬行數據。問題sql如下:
UPDATE product SET brand_id = [newBrandId] WHERE pid = [pid] AND brand_id = 0
項目組的mysql專家幫我分析了下,因為pid字段沒有索引,mysql引擎要逐行掃描出與傳入的pid值相等的列,然后更新數據,也就是要掃描完1000W+行磁盤數據才能執行完這個sql。因為是update操作,沒有用到索引,於是導致這個sql會占用表鎖,其它的sql只能等這個sql執行完成之后才能開始執行。更嚴重的是,這個千萬級的表里面有多少個不同的pid,我就要執行多少個這樣的sql。
同事給我的建議的根據id字段進行sql代碼層次的橫向分表。每次更新1000行的數據,這樣mysql引擎就不用每次在掃全表了,數據庫壓力是之前的萬分之一。而且id作為主鍵,是有索引的,這個時候占用的是這1000行數據的行級鎖,不會影響其它的數據。有索引能大大優化查詢性能,優化后的sql如下:
UPDATE product SET brand_id = [newBrandId] WHERE pid = [pid] AND brand_id = 0 AND id BETWEEN [startNum] AND [endNum]
僅僅用了id限區間的語句,將一個千萬級的大表代碼層次上進行橫向切割。重新上線worker后,mysql主從沒有任何延遲!而且經過監控,短短10分鍾就更新了十幾萬數據,效率是之前的6倍!更重要的是數據庫負載均衡,應用健康運行。