2014-01-17 42 views
2

我想找到一個合適的方式獲取X隨機記錄。另外我想檢查特定記錄的使用情況,所以我不會像其他人一樣經常使用相同的隨機記錄。通過MySQL獲取最少的隨機記錄集

我測試了一套與這3個表,一張表的問題,對於用戶來說一個表,併爲特定用戶所服務的問題一個表。我想用6000個問題來完成這個任務。

CREATE TABLE `questions` (
    `id` int(11) NOT NULL AUTO_INCREMENT, 
    `question` varchar(128) DEFAULT NULL, 
    PRIMARY KEY (`id`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8; 


CREATE TABLE `served` (
    `user` int(11) NOT NULL DEFAULT '0', 
    `question` int(11) NOT NULL DEFAULT '0', 
    `count` varchar(128) DEFAULT NULL, 
    PRIMARY KEY (`user`,`question`), 
    KEY `count` (`count`) USING BTREE 
) ENGINE=InnoDB DEFAULT CHARSET=utf8; 


CREATE TABLE `users` (
    `id` int(11) NOT NULL AUTO_INCREMENT, 
    `nickname` varchar(128) DEFAULT NULL, 
    PRIMARY KEY (`id`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8; 

我發現從問題表中獲取隨機記錄工作得很好的查詢是如下:

SELECT id, question 
     FROM (
       SELECT @cnt := COUNT(*) + 1, 
         @lim := 10 
       FROM questions 
       ) vars 
     STRAIGHT_JOIN 
       (
       SELECT q.*, 
         @lim := @lim - 1 
       FROM questions q 
       WHERE (@cnt := @cnt - 1) 
         AND RAND() < @lim/@cnt 
       ) i 

但現在我想結合的服務表,以確保隨機值從最不受歡迎的問題中挑選出來。我想到的查詢是如下:

SELECT id, question, count 
     FROM (
       SELECT @cnt := COUNT(*) + 1, 
         @lim := 10 
       FROM questions 
       ) vars 
     STRAIGHT_JOIN 
       (
       SELECT q.*, 
         s.count, 
         @lim := @lim - 1 
       FROM questions q 
       LEFT JOIN served s 
       ON s.question = q.id 
       WHERE (@cnt := @cnt - 1) 
         AND RAND() < @lim/@cnt 
       ORDER BY count ASC) i 

與此查詢的問題是,它從來沒有給我的10個結果的限制+它從來沒有給我想要的記錄。有誰能把我推向正確的方向嗎?

按照要求一個SQL撥弄一些數據來測試:http://sqlfiddle.com/#!2/3e5ed/5。我預計結果將是10個問題,其中用戶1的「計數」是最少的(或不存在的偏差)。

我已經結束了使用修改後的查詢,它必須是快速:

SELECT q.*, s1.count AS count_a, s2.count AS count_b 
FROM questions q 
LEFT JOIN served s1 
ON (s1.question = q.id AND s1.user = 1) 
LEFT JOIN served s2 
ON (s2.question = q.id AND s2.user = 2) 
WHERE q.categorie = 1 
ORDER BY IFNULL(s1.count, 0) + IFNULL(s2.count, 0) + RAND() 
LIMIT 10 
+0

考慮提供適當的DDLs(和/或一個sqlfiddle)與一小部分合法結果一起 – Strawberry

+0

我添加了一個URL與我的測試數據+我期望我的第二個查詢做什麼。 – Wesley

回答

2

一種常見的方式,人們在MySQL中獲得隨機記錄是這樣的:

要獲得10個隨機記錄:

SELECT * FROM questions 
ORDER BY RAND() 
LIMIT 10 

當然,可能很明顯,這將獲取數據庫中的所有記錄,然後將它們隨機排序以獲得10條記錄。它實際上並不僅僅是從數據庫中選擇10個隨機記錄。但是,這種方法很容易避免重複。

現在,使用相同的技術,如果你想少青睞送達的問題,你可以做這樣的事情:

SELECT questions.* FROM questions 
LEFT JOIN served 
ON served.question = questions.id 
ORDER BY IFNULL(served.count, 0) + RAND() 
LIMIT 10 

扭捏的算法來改變你贊成發球算量。

有更好的性能的方式來獲取隨機記錄,如獲得最大的主鍵值(假設AUTO_INCREMENT),然後在使用RAND(),然後挑出一個記錄。您可以使用LIMIT 1以防萬一RAND()在您的密鑰中返回間隙。但是,如果您重複此過程以返回多條記錄,則可能有重複。

如果有連續的AUTO_INCREMENT值,你可以輕鬆地利用PHP選擇一個隨機組鍵然後逐個取每個記錄。如果它們不是連續的,你首先獲取一個鍵列表。

這些技術詳細介紹了第16章中隨機選擇,在書中SQL Antipatterns

+0

我只是修復了第二個查詢中的錯誤。 –

+0

對於第二個查詢,它仍然會選擇未提供服務的問題上面已經提供的問題。 – Wesley

+0

@Wesso,多久? –