需求:mysql數據庫中,更新所有message_repo表中所有state='100' and receiver_id = '1'的數據為state='100',表中id為主鍵,state和receiver_id都有索引。
原語句:
update message_repo set state = '101' , update_time = now() , read_time = now() where id in (select a.id from (select id from message_repo where state = '100' and receiver_id = '1') a);
然后發現,workbench提示處於安全模式,即safe mode下只能采用主鍵更新。
我的id不就是主鍵?難道這個還不是主鍵更新,意識到這個sql肯定被mysql錯誤理解了,用執行分析果然發現問題。。。
update的where子句沒有使用主鍵索引,而是進行了全表掃描。
原本sql要表達的意思是:用select子句查詢所有符合條件的主鍵,然后update通過主鍵進行更新,但是實際上,mysql是全表逐行與select子句對比,沒有比這個更傻的操作了,要是表中數據多一點,死鎖是必定的。
更別說:這語句需要關閉safe mode。
優化后語句:
update message_repo a join (select id from message_repo where state = '100' and receiver_id = '1') b on a.id=b.id set state = '101' , update_time = now() , read_time = now();
通過join子句,明確告訴mysql,我要先用主鍵進行篩選。
執行計划
這下就正常,從執行計划上看,所有條件都符合預期。