2011-11-07 64 views
3

我有一个问题,这个查询....或者,没有像我会很快。目前,'marketingDatabase'表格大约有11万行,但在下个月内,它可能会接近10万行,到3月份可能增长到50万。优化随机记录查询

我知道使用ORDER BY RAND()是不是要走的路,但它是我已经得到了工作的唯一的东西。我试过其他的东西,但是第一个WHERE语句似乎把我抛弃了。我使用的是PHP,所以我也可以在PHP中处理其中的一些。

什么是最好的方法,该查询,从适合在WHERE语句行选择一个随机行?

这里的查询:

SELECT id 
FROM `marketingDatabase` 
WHERE do_not_call != 'true' 
    AND status = 'Pending' 
    AND install_id = 'AN ID HERE' 
    AND NOT EXISTS(
    SELECT recordID 
    FROM reminders rem 
    WHERE rem.id = marketingDatabase.id 
) 
ORDER BY rand() 
LIMIT 1 

如何使这项工作更有什么想法?我只需要一个随机的'身份证'。

+0

的[MySQL的可能重复:替代品以ORDER BY兰德()](http://stackoverflow.com/questions/1823306/mysql-alternatives-to-order-by-rand) –

回答

3

首先,看看我们是否可以优化查询一点:

SELECT `m`.`id` 
FROM `marketingDatabase` AS `m` 
    LEFT JOIN `reminders` AS `r` ON (`r`.`id` = `m`.`id`) 
WHERE 
    `m`.`do_not_call` != 'true' 
    AND `m`.`status` = 'Pending' 
    AND `m`.`install_id` = 'AN ID HERE' 
    AND `r`.`id` IS NULL 
ORDER BY 
    rand() 
LIMIT 1 

注:这只是一个想法,并没有在野外进行了测试。

为什么不能计算可能的记录数量,然后使用PHP从该计数中查找一个随机行数,然后重新找到它。

$rowCount = 0; 

$rowCountSql = "SELECT COUNT(*) AS `rowcount` 
    FROM `marketingDatabase` AS `m` 
    LEFT JOIN `reminders` AS `r` ON (`r`.`id` = `m`.`id`) 
    WHERE 
    `m`.`do_not_call` != 'true' 
    AND `m`.`status` = 'Pending' 
    AND `m`.`install_id` = 'AN ID HERE' 
    AND `r`.`id` IS NULL"; 

if($rowCountRes = mysql_query($rowCountSql) 
    && mysql_num_rows($rowCountRes) 
    && $r = mysql_fetch_assoc($rowCountRes)) 
    $rowCount = $r['rowcount']; 

$oneRow = false; 

$oneRowSql = "SELECT `m`.`id` AS `rowid` 
    FROM `marketingDatabase` AS `m` 
    LEFT JOIN `reminders` AS `r` ON (`r`.`id` = `m`.`id`) 
    WHERE 
    `m`.`do_not_call` != 'true' 
    AND `m`.`status` = 'Pending' 
    AND `m`.`install_id` = 'AN ID HERE' 
    AND `r`.`id` IS NULL 
    LIMIT ".(int) $rowCount.", 1"; 

if($oneRowRes = mysql_query($rowCountSql) 
    && mysql_num_rows($oneRowRes) 
    && $r = mysql_fetch_assoc($oneRowRes)) 
    $oneRow = $r['rowid']; 

这可能证明有没有性能优势,但我只是想我会把它在那里,看是否有更多我了解到的同事能更好的IT。

以上的进一步勘探(我将考验,如果我有访问数据库的...)

SELECT `m`.`id` AS `rowid` 
    FROM `marketingDatabase` AS `m` 
    LEFT JOIN `reminders` AS `r` ON (`r`.`id` = `m`.`id`) 
    WHERE 
    `m`.`do_not_call` != 'true' 
    AND `m`.`status` = 'Pending' 
    AND `m`.`install_id` = 'AN ID HERE' 
    AND `r`.`id` IS NULL 
    LIMIT (FLOOR(RAND() * (
    SELECT COUNT(*) AS `rowcount` 
    FROM `marketingDatabase` AS `m` 
     LEFT JOIN `reminders` AS `r` ON (`r`.`id` = `m`.`id`) 
    WHERE 
     `m`.`do_not_call` != 'true' 
     AND `m`.`status` = 'Pending' 
     AND `m`.`install_id` = 'AN ID HERE' 
     AND `r`.`id` IS NULL))) , 1 

只是一个想法...

+1

@ user969352,我有完全相同的查询作为顶部的卢卡斯... ...只有另外没有具体说明,通过使用粒度最小的索引作为关键字的第一部分来优化查询...在这种情况下,我将在(Install_ID,Status,Do_Not_Call)上创建索引。 – DRapp

0

我们遇到了同样的问题,您现在面临的问题是,行数太多,rand()的顺序实际上导致连接挂起并抛出白页,所以我们必须提出不同的解决方案。我们采取了

一种方案是在1000组块了IDS,扔缓存,然后我们会随机我们选择哪一组,然后随机选择其中id列组。

我们还每天一次向平面文件写入一个随机ID样本,并从中读取数字,但我相信我们已从以前的缓存解决方案的解决方案中移开。

只是一些想法。