2012-05-20 31 views
2

目前我使用:是最快的隨機選擇WHERE列X是Y(NULL)

SELECT * 
FROM 
    table AS t1 
    JOIN (
    SELECT (RAND() * (SELECT MAX(id) FROM table where column_x is null)) AS id 
) AS t2 
WHERE 
    t1.id >= t2.id 
    and column_x is null 
ORDER BY t1.id ASC 
LIMIT 1 

這通常是非常快但是當我包括高亮column_x是Y(空)的條件,它就會慢。

什麼是最快的隨機查詢解決方案,其中記錄的列X爲空?

ID是PK,列X是int(4)。表格包含大約一百萬條記錄,總大小超過1 GB,目前每24小時增加一倍。

column_x被索引。

列ID可能不連續。

本例中使用的數據庫引擎是InnoDB。

謝謝。

+0

是column_x索引? – ChrisWue

+0

是的,它被編入索引,但隨着數據庫的增長,查詢開始花費太長時間,並且很多column_x變爲NOT NULL。 – Phil

+0

該表使用MyISAM或InnoDB引擎嗎?你可以嘗試在'(column_x,id)'上添加一個複合索引嗎? –

回答

1

您是否在查詢上運行了explain?輸出是什麼?

爲什麼不存儲或緩存值:SELECT MAX(id) FROM table where column_x is null並將其用作變量。你的查詢就會變成:

$rand = rand(0, $storedOrCachedMaxId); 

SELECT * 
FROM 
    table AS t1 
WHERE 
    t1.id >= $rand 
    and column_x is null 
ORDER BY t1.id ASC 
LIMIT 1 

一個簡單的查詢可能會更容易在數據庫上。

要知道,如果您的數據包含可觀的漏洞 - 您不是將得到與這些查詢一致的隨機結果。

+0

列X的值不斷變化。對於每個查詢,必須檢查所有column_x,以確定哪些仍爲NULL。 – Phil

+0

這聽起來有點奇怪,但並沒有改變我的答案 - 你不需要在你的MAX(id)查詢中加入'column_x爲null'。在罕見的情況下,你沒有得到任何結果,你可以再次查詢反轉邏輯測試't1.id <$ rand'。你仍然需要將'explain'結果添加到問題中。 – AD7six

3

獲取真正的隨機記錄可能會很慢。這個事實並沒有真正解決。如果您希望它是真正隨機的,那麼查詢必須加載所有相關數據,以便知道哪些記錄可供選擇。

幸運的是,有更快的方式來做到這一點。它們不是隨機的,但如果你樂於爲了速度而交換一些純粹的隨機性,那麼它們應該足夠用於大多數目的。

考慮到這一點,獲得「隨機」記錄的最快方法是在數據庫中添加一個額外的列,該列中填充了一個隨機值。也許是主鍵的鹽味MD5哈希?隨你。在此列上添加適當的索引,然後只需將該列添加到查詢中的ORDER BY子句中,然後您將以隨機順序返回記錄。

要獲得一個隨機記錄,只需指定LIMIT 1並添加WHERE random_field > $random_value其中隨機值將是您的新的領域範圍內的值(比如一個隨機數的MD5哈希值,例如)。

當然,這裏的缺點是,雖然您的記錄將以隨機順序排列,但它們會以相同的隨機順序被卡住。我確實說過,它的查詢速度是完美的。你可以通過定期更新它們來更新它們,但是如果你需要保持新鮮的話,我想這可能會成爲一個問題。

另一個缺點是添加一個額外的列可能太多了,以至於詢問您是否有存儲限制,並且您的數據庫的大小已經很大,或者如果在添加列之前您有嚴格的DBA超過。但是,再次,你必須權衡一些東西;如果你想要查詢速度,你需要這個額外的列。

無論如何,我希望有所幫助。

+0

這是迄今爲止提出的唯一提供真正一致概率的方法。 ID中的差距並不重要。易於實施和索引。 +1 – usr

1

我不認爲你需要一個連接,也不是一個順序,也不是一個限制1(提供的ID是唯一的)。

SELECT * 
FROM myTable 
WHERE column_x IS NULL 
    AND id = ROUND(RAND() * (SELECT MAX(Id) FROM myTable), 0) 
+0

除了ids不是序列化的,所以會返回1 **或0 **行。 – AD7six

+0

這個ID不需要是順序的 - 但是再看一次 - 如果行的id有一個column_x值,那麼什麼都不會返回 - 所以我會再看一次。 – PeteGO

+0

這可能無法正常工作,但*可以*工作。 +1 – usr

0

我是新來的MySQL語法,但挖掘一點進一步我認爲動態查詢可能工作。我們選擇第N行,其中第N個是隨機的:

SELECT @r := CAST(COUNT(1)*RAND() AS UNSIGNED) FROM table WHERE column_x is null; 

PREPARE stmt FROM 
'SELECT * 
FROM table 
WHERE column_x is null 
LIMIT 1 OFFSET ?'; 

EXECUTE stmt USING @r; 
+0

具有巨大偏移量的查詢效率非常低 – AD7six