Php 选择查询花费的时间太长
这两个查询需要很长时间才能产生结果(有时需要1分钟,有时甚至会出现错误),并给服务器带来了沉重的负载:Php 选择查询花费的时间太长,php,mysql,Php,Mysql,这两个查询需要很长时间才能产生结果(有时需要1分钟,有时甚至会出现错误),并给服务器带来了沉重的负载: ("SELECT SUM(`rate`) AS `today_earned` FROM `".PREFIX."traffic_stats` WHERE `userid` = ?i AND from_unixtime(created) > CURRENT_DATE ORDER BY created DESC", $user->data->userid) ("SELECT CO
("SELECT SUM(`rate`) AS `today_earned` FROM `".PREFIX."traffic_stats` WHERE `userid` = ?i AND from_unixtime(created) > CURRENT_DATE ORDER BY created DESC", $user->data->userid)
("SELECT COUNT(`userid`) AS `total_clicks` FROM `".PREFIX."traffic_stats` WHERE `userid` = ?i", $user->data->userid)
这个表大约有400万行
这是表结构:
我在交通id
上有一个索引:
如果您从traffic\u stats
表中选择任何内容,都将花费很长时间,但是插入此表是正常的
是否可以减少执行此查询所花费的时间?我使用PDO,对这一切我都是新手。
orderby
将花费大量时间,而且由于您只需要聚合数据(添加数字或计数数字是可交换的),orderby
将执行大量无用的排序,耗费您的时间和服务器电源
您需要确保您的索引是正确的,您可能需要为用户id和(用户id,已创建)创建索引
user\u id
是数字吗?如果不是,那么您可以考虑将其转换为数值类型,例如int。
这些都在改进您的查询和结构。但我们也要改进这个概念。插入和修改是否非常频繁?您是否绝对需要实时数据,或者您也可以使用准实时数据
如果插入/修改不是很频繁,或者您可以使用较旧的数据,或者问题造成了巨大的麻烦,那么您可以通过定期运行cron作业来实现这一点,该作业将计算并缓存这些值。应用程序会从缓存中读取它们。我不知道你为什么会接受答案,而你确实没有触及问题的核心 我还想澄清一下,这是一个mysql问题,您使用PDO或PHP来解决这个问题并不重要 人们建议你使用解释。我想进一步告诉您,您需要使用EXPLAIN EXTENDED,可能还需要使用format=json选项来全面了解正在发生的事情。看看你的解释屏幕截图,你应该看到的是,查询查看了超过100万行才能得到答案。这就是为什么你的查询要花这么长时间 在一天结束时,如果您已经正确地为表编制了索引,那么您的目标应该是在这样一个大表中,让检查的行数相当接近最终结果集 让我们来看第二个查询,它非常简单:
("SELECT COUNT(`userid`) AS `total_clicks` FROM `".PREFIX."traffic_stats` WHERE `userid` = ?i", $user->data->userid)
在这种情况下,唯一真正重要的是在traffic_stats.userid上有一个索引
我建议,如果此时还不确定,请删除除原始主键(traffic_id)索引之外的所有索引,并仅从userid列上的索引开始。运行您的查询。结果如何,需要多长时间?看下面的例子。鉴于查询的简单性,您应该看到只使用了索引,并且行应该与结果匹配
现在转到您的第一个查询:
("SELECT SUM(`rate`) AS `today_earned` FROM `".PREFIX."traffic_stats` WHERE `userid` = ?i AND from_unixtime(created) > CURRENT_DATE ORDER BY created DESC", $user->data->userid)
查看WHERE条款,有以下标准:
- 用户ID=
- 从\u unixtime(已创建)>当前\u日期
mysql> select UNIX_TIMESTAMP(), UNIX_TIMESTAMP(CURRENT_DATE);
+------------------+------------------------------+
| UNIX_TIMESTAMP() | UNIX_TIMESTAMP(CURRENT_DATE) |
+------------------+------------------------------+
| 1490059767 | 1490054400 |
+------------------+------------------------------+
1 row in set (0.00 sec)
从这个快速示例中可以看到,UNIX_时间戳本身就是当前时间,但当前_日期本质上是一天的开始,这显然是您要寻找的
我敢打赌,在系统历史记录中,当前日期的行数将少于用户的总行数,因此,这就是为什么您不希望在用户上创建索引的原因,正如先前在接受的答案中建议的那样。您可能会从创建的userid上的索引中获益
我的建议是在每一列上分别创建一个单独的索引
("SELECT SUM(`rate`) AS `today_earned` FROM `".PREFIX."traffic_stats` WHERE `userid` = ?i AND created > UNIX_TIMESTAMP(CURRENT_DATE)", $user->data->userid)
对于重新编写的查询,再次假设结果集相对较小,您应该会看到一个清晰的解释,其中的行与最终结果集匹配
至于您是否应该应用ORDER BY,这不应该是出于性能原因而取消的,而是因为它与您期望的结果无关。如果您需要或希望结果按用户排序,请保留它。除非您正在生成一个大的结果集,否则它不应该是一个大问题
在这个特定的查询中,由于您执行的是SUM(),因此对数据进行排序没有任何价值,因为您只需要返回一行,因此在这种情况下,我同意Lajos的观点,但很多时候您可能会使用GROUP BY,在这种情况下,您可能希望对最终结果进行排序。相关数据库表和列上是否有索引?@Zach yes“userid”上也有一个索引。您应该在user_id上创建一个复合索引并创建。。。阅读:在第一次查询中使用
orderby
没有任何意义。您只返回一行和。对于每个查询,EXPLAIN
说了什么?是的,用户ID是int,并且根本没有对该表进行任何修改,只是插入和选择,这是非常经常和实时的。我删除了订单,并制作了您建议的索引,将60秒的加载时间减少到15秒,这是一个很大的改进。对于此查询“”(“从中选择origin
FROM