因?yàn)闃I(yè)務(wù)需要,要求在一個where篩選完的數(shù)據(jù)集中隨機(jī)取出1條數(shù)據(jù)。
經(jīng)典的方法
SELECT * FROM table where 條件 ORDER BY RAND() limit 1;
適用入門級應(yīng)用,怎么這樣說呢?
因?yàn)閿?shù)據(jù)量小時,倒沒多大問題,由于會進(jìn)行全表掃描,當(dāng)數(shù)據(jù)量漸漸巨型時,查詢時間會相當(dāng)變態(tài)。
本地環(huán)境運(yùn)行需時在0.276s左右。
百度出來別人驗(yàn)證過,性能高效的方法是
SELECT *
FROM `table` AS t1 JOIN (SELECT ROUND(RAND() * ((SELECT MAX(id) FROM `table`)-(SELECT MIN(id) FROM `table`))+(SELECT MIN(id) FROM `table`)) AS id) AS t2
WHERE t1.id >= t2.id
ORDER BY t1.id LIMIT 1;
加上我們需要的條件
SELECT *
FROM `table` AS t1 JOIN (SELECT ROUND(RAND() * ((SELECT MAX(id) FROM `table`)-(SELECT MIN(id) FROM `table`))+(SELECT MIN(id) FROM `table`)) AS id) AS t2
WHERE t1.id >= t2.id and 條件1 and 條件2 and 條件3
ORDER BY t1.id LIMIT 1;
我們下面就來測試一下
生產(chǎn)虛擬數(shù)據(jù)
先生成20萬條虛擬數(shù)據(jù),要隨機(jī)生成,保證數(shù)據(jù)的均勻分布。
跑一下
平均只用0.006s左右
統(tǒng)計(jì)符合條件的數(shù)目
SELECT COUNT(*) FROM `table` WHERE 條件1 and 條件2 and 條件3;
符合條件的數(shù)據(jù)有8340條,占比0.0417。
數(shù)據(jù)校驗(yàn)
運(yùn)行8000次
校驗(yàn)通過:0.999875, 檢驗(yàn)不通過:0.000125
計(jì)算了一下,是1條。
運(yùn)行了兩次程序,結(jié)果依舊,原因暫未查明。
數(shù)據(jù)重復(fù)性測試
| 運(yùn)行 | 出現(xiàn)1次 | 2次 | 3次 | 4次 | 5次 | 6次 | 7次 | 8次 | 9次 | 10次 | 11次 | 12次 | 13次 | 14次 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 1000 | 0.7970 | 0.1760 | 0.0270 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 2000 | 0.6355 | 0.265 | 0.0825 | 0.014 | 0.0025 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 3000 | 0.5367 | 0.2853 | 0.1290 | 0.0307 | 0.0100 | 0.0080 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 4000 | 0.4603 | 0.2900 | 0.1388 | 0.0590 | 0.0313 | 0.0150 | 0.0035 | 0.0020 | 0 | 0 | 0 | 0 | 0 | 0 |
| 5000 | 0.3844 | 0.3000 | 0.1632 | 0.0872 | 0.042 | 0.0132 | 0.0084 | 0.0016 | 0 | 0 | 0 | 0 | 0 | 0 |
| 6000 | 0.3405 | 0.2833 | 0.1965 | 0.0967 | 0.0500 | 0.0160 | 0.0070 | 0.0067 | 0.0030 | 0 | 0 | 0 | 0 | 0 |
| 7000 | 0.2990 | 0.2700 | 0.1701 | 0.1000 | 0.0729 | 0.0497 | 0.0230 | 0.0069 | 0.0039 | 0.0043 | 0 | 0 | 0 | 0 |
| 8000 | 0.266 | 0.2593 | 0.1935 | 0.1095 | 0.0719 | 0.0465 | 0.0263 | 0.014 | 0.0034 | 0.0025 | 0.0028 | 0.0045 | 0 | 0 |
由此來看,隨機(jī)性還是挺不錯的,多數(shù)數(shù)據(jù)是出現(xiàn)在前段,這個方法可以使用。
注意:在max,min里面的語句不能再加入where,加入后發(fā)現(xiàn)查詢明顯減慢,經(jīng)EXPLAIN分析是會導(dǎo)致一條或多條select_type為SUBQUERY進(jìn)行全表掃描。