2011-03-18 73 views
0

我有兩個表:上優化MySQL隨機查詢

Table GAME: id(int), added_at(bigint) 
Table META: id_game(int), meta(VARCHAR(64)) 

現在,每場比賽可以有0個或更多元與之相關的標籤。我試圖找回9場比賽:

  • 1隨機遊戲 「精選」 META
  • 1隨機遊戲 「溢價」 META
  • 1隨機遊戲 「doublepoints」 META
  • 3個最新遊戲(ORDER BY added_at DESC)
  • 3個隨機的遊戲不屬於任何的6場以上

截至目前我已經做的相當胡思亂想系統,它看起來更Ø [R少這樣的:

$feat = getGameMetaRandom(1, 'featured'); 
$prem = getGameMetaRandom(1, 'premium'); 
$dubl = getGameMetaRandom(1, 'doublepoints'); 
$last = getGameLatest(3); 
$rand = getGameRandom(3); 

目前各隨機函數有兩個查詢(從getGameMetaRandom($count, $meta);):

SELECT FLOOR(RAND() * (COUNT(*) - " . ($count - 1) .")) AS `offset` 
FROM table_meta WHERE meta = '{$meta}' 

SELECT t1.* FROM table_meta t2 
LEFT JOIN table_game t1 ON t1.id = t2.id_game 
WHERE t2.meta = '{$meta}' LIMIT {$offset}, {$count} 

(gameRandom很相似),正如你可以看到這忽略了我的限制這些不是以上的6個遊戲中的任何一個,再加上所有這些都需要9個查詢,並且隨機化並不是真正的隨機性。

所以我的三個目標,我的可能的解決方案是:

  1. 如何讓3級隨機的遊戲沒有任何重複的aforeselected遊戲。在選擇前六場比賽之後,我可能會列出他們的ID,並在NOT IN()的最後一個查詢中使用它們,但不會過度優化。
  2. 如何隨機隨機抽取遊戲,而不是選擇隨機選擇並採取n來自它的遊戲?顯然使用ORDER BY RAND(),但是我聽說關於它的速度有多慢真的很糟糕,儘管我猜想除非我的表有數百行,它並沒有什麼區別?
  3. 如何減少查詢次數?集團前三查詢爲一體,我留下了5個查詢,或通過使用ORDER BY RAND()我可以忽略第一個「偏移檢索」查詢與和東西去像SELECT t1.* FROM table_meta t2 LEFT JOIN table_game t1 ON t1.id = t2.id_game WHERE t2.meta = '{$meta}' ORDER BY RAND() LIMIT {$count}

但儘管如此,thiese通常需要使用ORDER BY RAND(),並且我看到一些測試使它看起來非常慢。任何提示,以改善它甚至更多?

+0

有三個問題,沒有一個是直接或微不足道的...... – RichardTheKiwi 2011-03-18 11:21:14

+0

@Richard又名cyberkiwi:我..猜。我已經添加了一些可能的解決方案和我對它們的關注,如果這樣可以更容易考慮。我是MySQL的新手,我幾乎不知道任何事情。 – Maurycy 2011-03-18 11:34:27

回答

1

的比賽用表:

[email protected] [kris]> show create table games\G 
*************************** 1. row *************************** 
     Table: games 
Create Table: CREATE TABLE `games` (
    `id` int(11) NOT NULL AUTO_INCREMENT, 
    `flags` enum('features','premium','doublepoints') NOT NULL, 
    `added_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, 
    PRIMARY KEY (`id`) 
) ENGINE=InnoDB AUTO_INCREMENT=8184 DEFAULT CHARSET=latin1 
1 row in set (0.00 sec) 

樣本遊戲:

[email protected] [kris]> insert into games values (NULL, floor(rand() * 4), now() - interval 1200 second); 
Query OK, 1 row affected, 1 warning (0.00 sec) 

Note (Code 1592): Statement may not be safe to log in statement format. 

更多樣的遊戲:

[email protected] [kris]> insert into games select NULL, floor(rand() * 4), now() - interval 1200 second from games; 
Query OK, 1 row affected, 1 warning (0.00 sec) 
Records: 1 Duplicates: 0 Warnings: 0 

Note (Code 1592): Statement may not be safe to log in statement format. 

重複上述說法,直到有足夠的樣本數據。數據截斷的警告可以被忽略,它們是將0插入到enum()列中的僞像,導致無旗的遊戲,這是我們想要的。

[email protected] [kris]> select count(*) from games; 
+----------+ 
| count(*) | 
+----------+ 
|  8192 | 
+----------+ 
1 row in set (0.00 sec) 

我們創建的遊戲改組名單:

[email protected] [kris]> create table shuffle like games; 
Query OK, 0 rows affected (0.09 sec) 

[email protected] [kris]> alter table shuffle modify column id integer not null, drop primary key, add column shuffleid integer not null auto_increment, add primary key (shuffleid), add index(flags), add index(added_at), add index(id); 
Query OK, 0 rows affected (0.13 sec) 
Records: 0 Duplicates: 0 Warnings: 0 

洗牌遊戲:

[email protected] [kris]> insert into shuffle select id, flags, added_at, NULL from games order by rand(); 
Query OK, 8192 rows affected, 1 warning (0.34 sec) 
Records: 8192 Duplicates: 0 Warnings: 0 

Note (Code 1592): Statement may not be safe to log in statement format. 

現在,只需獲取你所需要的:

[email protected] [kris]> select min(id) as id from shuffle where flags = 'premium' 
    union all select min(id) from shuffle where flags = 'features' 
    union all select min(id) from games where flags = 'doublepoints' 
    union all (select id from shuffle order by added_at limit 3); 
+------+ 
| id | 
+------+ 
| 8216 | 
| 8214 | 
| 8218 | 
| 8213 | 
| 8214 | 
| 8216 | 
+------+ 
6 rows in set (0.00 sec) 

更有效地選擇3個隨機行S中的沒有在上面設置在第二查詢:

[email protected] [kris]> select id from shuffle where id not in (8216, 8214, 8218, 8213, 8214, 8216) limit 3; 
+------+ 
| id | 
+------+ 
| 8215 | 
| 8219 | 
| 8220 | 
+------+ 
3 rows in set (0.00 sec) 

然後從洗牌刪除9個值,從而使隨後使用該表將產生9個新值(或保留最近3個一樣的東西如果你喜歡的話)。