眾所周知,在MySQL中,如果直接 ORDER BY RAND() 的話,效率非常差,因為會多次執行。事實上,如果等值查詢也是用 RAND() 的話也如此,我們先來看看下面這幾個SQL的不同執行計劃和執行耗時。
首先,看下建表DDL,這是一個沒有顯式自增主鍵的InnoDB表:
| [yejr@imysql]> show create table t_innodb_random/G*************************** 1. row ***************************Table: t_innodb_randomCreate Table: CREATE TABLE `t_innodb_random` (`id` int(10) unsigned NOT NULL,`user` varchar(64) NOT NULL DEFAULT '',KEY `idx_id` (`id`)) ENGINE=InnoDB DEFAULT CHARSET=latin1 |
往這個表里灌入一些測試數據,至少10萬以上, id 字段也是亂序的。
| [yejr@imysql]> select count(*) from t_innodb_random/G*************************** 1. row ***************************count(*): 393216 |
1、常量等值檢索:
| [yejr@imysql]> explain select id from t_innodb_random where id = 13412/G*************************** 1. row ***************************id: 1select_type: SIMPLEtable: t_innodb_randomtype: refpossible_keys: idx_idkey: idx_idkey_len: 4ref: constrows: 1Extra: Using index |
| [yejr@imysql]> select id from t_innodb_random where id = 13412;1 row in set (0.00 sec) |
可以看到執行計劃很不錯,是常量等值查詢,速度非常快。
2、使用RAND()函數乘以常量,求得隨機數后檢索:
| [yejr@imysql]> explain select id from t_innodb_random where id = round(rand()*13241324)/G*************************** 1. row ***************************id: 1select_type: SIMPLEtable: t_innodb_randomtype: indexpossible_keys: NULLkey: idx_idkey_len: 4ref: NULLrows: 393345Extra: Using where; Using index |
| [yejr@imysql]> select id from t_innodb_random where id = round(rand()*13241324)/GEmpty set (0.26 sec) |
可以看到執行計劃很糟糕,雖然是只掃描索引,但是做了全索引掃描,效率非常差。因為WHERE條件中包含了RAND(),使得MySQL把它當做變量來處理,無法用常量等值的方式查詢,效率很低。
我們把常量改成取t_innodb_random表的最大id值,再乘以RAND()求得隨機數后檢索看看什么情況:
| [yejr@imysql]> explain select id from t_innodb_random where id = round(rand()*(select max(id) from t_innodb_random))/G*************************** 1. row ***************************id: 1select_type: PRIMARYtable: t_innodb_randomtype: indexpossible_keys: NULLkey: idx_idkey_len: 4ref: NULLrows: 393345Extra: Using where; Using index*************************** 2. row ***************************id: 2select_type: SUBQUERYtable: NULLtype: NULLpossible_keys: NULLkey: NULLkey_len: NULLref: NULLrows: NULLExtra: Select tables optimized away |