如何优化此数据库查询以计算收到的SMS消息的每日总计

时间:2014-08-25 16:52:46

标签: mysql sql database

为了简要解释我的问题,SMS网关使用GET请求连接到我的PHP脚本,并提取消息内容并保存到MySQL数据库。消息内容包括时间戳值,该值保存在同一个表中。只使用了一个表,列是ID(int),sender(int),message(varchar),timestamp(timestamp)。

SMS网关接收来自大约100个不同号码的消息,并且每天将从每个号码接收的最大消息数量为400,尽管他们不会每天发送消息。在这个月中,该脚本可能会保存多达300,000条消息。

我必须创建一个基于浏览器的报告,该报告生成一个表,其中包含每个数字的行,然后是从该数字接收的消息数的每日总数,因此表中的第一列显示数字,第二列列显示8月1日收到的邮件总数,第3列显示8月2日收到的邮件总数等。

由于需要检索的总数,脚本本身工作正常但超时。我已经通过以下两种方式实现了查询,但都没有在60秒的最大脚本执行时间内完成:

  1. 检索数据库中不同的数字列表,然后遍历数字列表,并为每个数字运行最多31个查询,以使用COUNT()语句检索每日总数。

    < / LI>
  2. 检索数据库中不同的数字列表,然后遍历数字列表并运行单个查询以检索月内收到的每封邮件的时间戳值。一旦检索到时间戳列表,就会循环结果并提取时间戳的日期部分并更新数组 - 数组键是月中的某一天,值是该月收到的消息总数。当timestamp值与数组值增加1的那天匹配时。

  3. 这些解决方案似乎都不理想,因为第一个解决方案必须运行太多单独的查询,第二个解决方案检索大量数据,这些数据也必须进行处理。

    我在此阶段考虑的方法是要么考虑添加某种GROUP BY子句,要么只提取时间戳的日期部分,将其保存到单独的列中,然后再将其编入索引已编入索引的编号列。

    感谢您提供任何建议或帮助。我对优化数据库的选择是有限的,因为我无法更改数据库类型而且我无法编辑MySQL配置文件,所以我必须确保我的查询设计正确并且数据库模式是最佳的。

1 个答案:

答案 0 :(得分:1)

通常,使用单个查询检索所需的结果会更有效。

就原始MySQL性能而言,使用这样的查询可能会更好:

SELECT t.number
     , DATE(t.message_datetime) AS dt
     , COUNT(1)                 AS cnt
  FROM sms_messages t
 WHERE t.message_datetime >= '2014-07-01'
   AND t.message_datetime <  '2014-07-01' + INTERVAL 1 MONTH
 GROUP
    BY t.number
     , DATE(t.message_datetime)

但是,这不能给你的是单独列中的计数,并且它不会给你任何计数为零的行。 (如果给定的号码在一个月内没有任何消息,那么你就不会得到任何包含该号码的行。如果给定的号码在给定日期没有任何消息,那么你也不会为此争吵。)

可以修改查询以返回零缺失&#34;日期&#34;给定数字的值,但这需要在MySQL服务器上进行更多处理,以生成适当的行。查询也可以修改为返回所有数字,但同样,这是一个更复杂的查询和更多处理。

也可以修改查询以在单独的列中返回每天的计数,但同样,以更复杂的SQL和更多处理为代价。

所以,如果你可以处理&#34;缺少&#34;行,那么这个查询可能是最有效的。


为了获得最佳的MySQL原始性能,如果你只有&#34; date&#34;日期时间的一部分存储为单独的列,然后是此查询:

SELECT t.number
     , t.dt
     , COUNT(1) AS cnt
  FROM sms_messages t
 WHERE t.message_datetime >= '2014-07-01'
   AND t.message_datetime <  '2014-07-01' + INTERVAL 1 MONTH
 GROUP
    BY t.number
     , t.dt

可以使用适当的索引来优化GROUP BY,以避免&#34;使用filesort&#34;否则将需要的操作:

... ON sms_messages (number, dt)