【问题标题】:Optimize Random Record Query优化随机记录查询
【发布时间】:2011-11-07 05:27:34
【问题描述】:

我遇到了这个查询的问题......或者,还没有我很快就会遇到的问题。目前,“marketingDatabase”表大约有 11k 行,但在下个月内,它可能会接近 100k 行,到 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”。

【问题讨论】:

标签: php mysql


【解决方案1】:

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

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

只是一个想法......

【讨论】:

  • @user969352,我在顶部有与Lucanos完全相同的查询......唯一没有特别说明的补充是通过将最小粒度的索引作为键的第一部分来优化查询......在这种情况下,我会在 (Install_ID, Status, Do_Not_Call) 上有索引。
【解决方案2】:

我们遇到了您现在面临的相同问题,即行数增长过多,rand() 的顺序实际上导致连接挂起并抛出白页,因此我们不得不提出不同的解决方案。

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

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

只是一些想法。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-08
    • 2019-01-27
    • 2015-11-28
    相关资源
    最近更新 更多