我正在優化我的項目中的很多現有查詢。 Quassnoi的解決方案幫助我加快了查詢速度!但是,我發現很難將所述解決方案合併到所有查詢中,尤其是對於涉及多個大型表上的許多子查詢的複雜查詢。
所以我使用的是一個不太優化的解決方案。基本上它與Quassnoi的解決方案一樣。
SELECT accomodation.ac_id,
accomodation.ac_status,
accomodation.ac_name,
accomodation.ac_status,
accomodation.ac_images
FROM accomodation, accomodation_category
WHERE accomodation.ac_status != 'draft'
AND accomodation.ac_category = accomodation_category.acat_id
AND accomodation_category.acat_slug != 'vendeglatohely'
AND ac_images != 'b:0;'
AND rand() <= $size * $factor/[accomodation_table_row_count]
LIMIT $size
$size * $factor/[accomodation_table_row_count]
作品挑選出來排隨機的概率。 rand()將生成一個隨機數。如果rand()小於或等於概率,則該行將被選中。這有效地執行隨機選擇來限制表格大小。由於有可能返回小於定義的限制數量,我們需要增加概率以確保選擇足夠的行。因此,我們將$ size乘以一個$因子(我通常設置$ factor = 2,在大多數情況下都適用)。最後我們做limit $size
現在的問題是制定出accomodation_table_row_count。 如果我們知道表的大小,我們可以硬編碼表的大小。這會跑得最快,但顯然這並不理想。如果你正在使用Myisam,獲得餐桌計數是非常有效的。自從我使用innodb以來,我只是做一個簡單的計數+選擇。在你的情況下,它看起來像這樣:
SELECT accomodation.ac_id,
accomodation.ac_status,
accomodation.ac_name,
accomodation.ac_status,
accomodation.ac_images
FROM accomodation, accomodation_category
WHERE accomodation.ac_status != 'draft'
AND accomodation.ac_category = accomodation_category.acat_id
AND accomodation_category.acat_slug != 'vendeglatohely'
AND ac_images != 'b:0;'
AND rand() <= $size * $factor/(select (SELECT count(*) FROM `accomodation`) * (SELECT count(*) FROM `accomodation_category`))
LIMIT $size
棘手的部分是找出正確的概率。正如你所看到的,下面的代碼實際上只計算粗略的臨時表大小(實際上太粗糙了!):(select (SELECT count(*) FROM accomodation) * (SELECT count(*) FROM accomodation_category))
但是你可以改進這個邏輯來給出更接近的表大小近似值。 請注意,OVER-select比選擇下面的行更好。即如果概率設置得太低,則可能無法選擇足夠的行。
由於我們需要重新計算表格大小,所以此解決方案運行速度比Quassnoi的解決方案要慢。但是,我發現這種編碼更易於管理。這是在精度+性能與編碼複雜度之間的折衷。儘管如此,在大型表格上,這仍然比Rand()的Order快得多。
注意:如果查詢邏輯允許,請在任何聯接操作之前儘早執行隨機選擇。
可能重複[MySQL從600K行中快速選擇10個隨機行](http://stackoverflow.com/questions/4329396/mysql-select-10-random-rows-from-600k-rows-fast ) – 2015-12-06 10:55:14