【问题标题】:MySQL Query Optimization - Random RecordMySQL 查询优化 - 随机记录
【发布时间】:2012-03-13 04:43:22
【问题描述】:

我在使用 MySQL 查询时遇到了麻烦。我周末的大部分时间和今天的大部分时间都在试图让这个查询运行得更快一些。我已经把它做得更快了,但我知道我可以做得更好。

SELECT m.id,other_fields,C.contacts_count FROM marketingDatabase AS m 
LEFT OUTER JOIN 
 (SELECT COUNT(*) as contacts_count, rid 
  FROM contacts 
  WHERE status = 'Active' AND install_id = 'XXXX' GROUP BY rid) as C
 ON C.rid = m.id 
WHERE (RAND()*2612<50) 
  AND do_not_call != 'true' 
  AND `ACTUAL SALES VOLUME` >= '800000'  
  AND `ACTUAL SALES VOLUME` <= '1200000' 
  AND status = 'Pending'
  AND install_id = 'XXXXX' 
ORDER BY RAND()

我在“install_id”、“category”和“status”上有一个索引,但 EXPLAIN 显示它是根据 9100 行排序的。

我的解释在这里: https://s3.amazonaws.com/jas-so-question/Screen+Shot+2012-03-13+at+12.34.04+AM.png

有人对我可以做些什么来加快速度有什么建议吗?查询的全部要点是从帐户记录 (install_id) 中选择一条随机记录,该记录与销售量、状态和 do_not_call 等特定条件相匹配。我目前正在收集 25 条记录并将其缓存(使用 PHP),因此我只需每 25 个请求运行一次此查询,但我已经每天处理数千个请求。当前运行需要 0.2 秒。我意识到通过使用 ORDER BY RAND() 已经对性能造成重大影响,但它只是对 25 行进行排序。

提前感谢您的帮助。

**编辑:我忘了提到'contact_sort' 索引在'contacts' 表上,并且索引 install_id、status 和 rid。 (rid 引用了 marketingDatabase 中的记录 ID,因此它知道联系人属于哪条记录。

**编辑2:查询中的2612数字代表marketingDatabase中符合条件(install_id、status、实际销量等)的行数

【问题讨论】:

  • 看看dev.mysql.com/doc/refman/5.0/en/group-by-optimization.html 使用 GROUP BY 和索引时会出现限制和复杂性。引用手册“对 GROUP BY 使用索引的最重要的先决条件是所有 GROUP BY 列都引用来自同一索引的属性,并且索引按顺序存储其键(例如,这是 BTREE 索引而不是 HASH指数)。”您正在按非索引字段进行分组,并且还在子查询中选择和排序整个表。我认为(不确定)按 RAND() 排序也是一个坏主意。
  • ORDER BY RAND() 非常非常bad idea
  • 是的,我知道这是个坏主意,虽然我读过因为 ORDER BY RAND() 只订购 25 行,这没什么大不了的。我错了吗?我应该如何修复它并仍然获得随机记录?我没有任何无间隙自动递增的列...我的 id 列是自动递增的,但在行已被删除的地方有间隙。
  • 我认为WHERE (RAND()*2612&lt;50)意味着MySQL仍然需要为表中的每一行计算一个随机值。大概这就是导致查询如此缓慢的原因?
  • 看看这个可能会给你一些启发stackoverflow.com/questions/31495446/…

标签: php mysql


【解决方案1】:

由于我没有看到您的索引定义,我不确定它们是否正确。该查询将受益于以下索引:

  1. contacts 上的复合索引(install_id、status、rid)

  2. marketingDatabase 上的复合索引(install_id、状态、`ACTUAL SALES VOLUME`)

【讨论】:

  • 是的,这正是我目前拥有的索引。
【解决方案2】:

我尝试了一些查询,但我认为您永远无法获得与 RAND() 一起使用的索引查询,尤其是当您同时在 WHERE 子句和 ORDER 中使用它时BY 子句。如果可能的话,我会在我的 PHP 逻辑中引入随机元素,并且可能会看看两个简单的查询是否比一个相当复杂的查询更有意义。除此之外,您在随机结果集上有 LEFT OUTER JOIN,这也可能会增加必须完成的工作量。

总而言之,我的猜测是 - 重写以排除 RAND,看看你是否可以摆脱 LEFT OUTER JOIN。两个简单的索引查询,中间有一点 PHP 可能会好很多。

【讨论】:

  • 好的,有道理。我应该如何看待这件事?查询数据库中所有符合条件的记录,然后使用array_rand() 来选择一个随机元素?
  • 很难说,因为我真的不知道你为什么需要随机元素,但是是的,这听起来很合理。您只有 2612 个条目,因此返回整个表并不太糟糕(取决于其中的内容)。至少查询会被缓存,所以从 MySQL 和 PHP 的角度来看,这将是一件轻而易举的事。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-11-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-01-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多