UPDATE + RAND()怎麼能夠更快?html
有時候,咱們隨機更新幾行數據,可能會下意識的直接寫成下面的SQL:mysql
[yejr@imysql]> UPDATE t1 SET c1 = ? WHERE id = ROUND(RAND() * 102400);
不過你可能不知道,這個SQL的效率極低,須要進行全表掃描,由於沒法使用索引:sql
[yejr]@[imysql.com]> EXPLAIN UPDATE t1 SET c1 = 3 WHERE id = ROUND(RAND() * 102400); *************************** 1. row *************************** id: 1 select_type: UPDATE table: t1 partitions: NULL type: ALL possible_keys: NULL key: NULL key_len: NULL ref: NULL rows: 102400 filtered: 100.00 Extra: Using where
這就尷尬了。函數
關注我網站(http://imysql.com)的同窗,可能還記得我之前還寫過一個關於隨機排序的分享:[MySQL優化案例]系列 — RAND()優化。能夠借鑑這篇文章的思路,把上面的SQL用JOIN改造一下:優化
[yejr@imysql]> EXPLAIN UPDATE t1, (SELECT ROUND(RAND() * (SELECT MAX(id) FROM t1)) AS rndid) t2 SET t1.c1=3 WHERE t1.id=t2.rndid; *************************** 1. row *************************** id: 1 select_type: PRIMARY table: <derived2> partitions: NULL type: system possible_keys: NULL key: NULL key_len: NULL ref: NULL rows: 1 filtered: 100.00 Extra: NULL *************************** 2. row *************************** id: 1 select_type: UPDATE table: t1 partitions: NULL type: const possible_keys: PRIMARY key: PRIMARY key_len: 4 ref: const rows: 1 filtered: 100.00 Extra: NULL *************************** 3. row *************************** id: 2 select_type: DERIVED table: NULL partitions: NULL type: NULL possible_keys: NULL key: NULL key_len: NULL ref: NULL rows: NULL filtered: NULL Extra: No tables used *************************** 4. row *************************** id: 3 select_type: SUBQUERY table: NULL partitions: NULL type: NULL possible_keys: NULL key: NULL key_len: NULL ref: NULL rows: NULL filtered: NULL Extra: Select tables optimized away
再來看下兩種 UPDATE 的代價:我有幾張阿里雲幸運券分享給你,用券購買或者升級阿里雲相應產品會有特惠驚喜哦!把想要買的產品的幸運券都領走吧!快下手,立刻就要搶光了。網站
[yejr@imysql]>UPDATE t1 SET c1 = 3 WHERE id = ROUND(RAND()*102400); Query OK, 1 row affected (0.69 sec) [yejr@imysql]>SHOW STATUS LIKE 'handler%read%'; +-----------------------+--------+ | Variable_name | Value | +-----------------------+--------+ | Handler_read_first | 1 | | Handler_read_key | 1 | | Handler_read_last | 0 | | Handler_read_next | 0 | | Handler_read_prev | 0 | | Handler_read_rnd | 0 | | Handler_read_rnd_next | 799995 | +-----------------------+--------+ [yejr@imysql]>show profile for query 5; ... | System lock | 0.000040 | | updating | 0.691625 | | end | 0.000020 | | query end | 0.000515 | ... [yejr@imysql]>UPDATE t1, (SELECT ROUND(RAND() * (SELECT MAX(id) FROM t1)) AS rndid) t2 SET t1.c1=3 WHERE t1.id=t2.rndid; Query OK, 1 row affected (0.02 sec) [yejr@imysql]>SHOW STATUS LIKE 'handler%read%'; +-----------------------+-------+ | Variable_name | Value | +-----------------------+-------+ | Handler_read_first | 1 | | Handler_read_key | 3 | | Handler_read_last | 1 | | Handler_read_next | 0 | | Handler_read_prev | 0 | | Handler_read_rnd | 1 | | Handler_read_rnd_next | 3 | +-----------------------+-------+ [yejr@imysql]>show profile for query 6; ... | updating reference tables | 0.011772 | | end | 0.000040 | | end | 0.000012 | | removing tmp table | 0.000018 | | end | 0.000005 | ... | query end | 0.014745 | ...
不過,上面這種多表UPDATE(Multiple-table UPDATE)有侷限性,就是隻能更新一行記錄,不能同時更新多行,因此也能夠改寫成下面的SQL:阿里雲
[yejr@imysql]> set @rnd_id=ROUND(RAND()*102400); UPDATE t1 SET c1=3 WHERE id>=@rnd_id LIMIT 2;
最後記住重點:不要在WHERE子句中直接使用RAND()函數。code