优化随机记录查询


Optimize Random Record Query

我有一个问题与此查询....或者,现在还没有那么多,但我很快就会。目前'marketingDatabase'表大约有11k行,但在接下来的一个月里,它可能会接近100000行,到3月份可能会增长到500k。

我知道使用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

关于如何使它更好地工作有什么想法吗?我只需要一个随机的"id"。

首先,看看我们是否可以稍微优化一下这个查询:

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'];

这可能被证明对性能没有好处,但我只是想把它放在那里,看看我更有学问的同事是否能更好。

对上述内容的进一步探索(如果我可以访问您的数据库…,我会进行测试)

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

我们有同样的问题,你现在面临的,行数增长太高,rand()的顺序实际上是导致连接挂起和抛出白页,所以我们不得不提出不同的解决方案。

我们采取的一种选择是将id分成1000组并将它们放入缓存中,然后我们将随机选择我们选择的组,然后随机选择组中的哪个id。

我们还每天写一个随机id的样本到一个平面文件中,并从中读取数字,但我相信我们已经放弃了之前的缓存解决方案。

只是一些想法。