2011-03-18 49 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个一样的东西如果你喜欢的话)。