Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/263.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Php 选择查询花费的时间太长_Php_Mysql - Fatal编程技术网

Php 选择查询花费的时间太长

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

这两个查询需要很长时间才能产生结果(有时需要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 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日期
您已经有一个关于userid的索引。尽管前面给出了建议,但在userid上创建索引并不一定是正确的,在您的情况下,它没有任何价值

原因是您正在使用来自_unixtime(created)的mysql函数来转换所创建列的原始值

无论何时执行此操作,都无法使用索引。如果使用的是本机时间戳类型,那么在与当前_日期进行比较时,您不会有任何顾虑,但在本例中,要处理不匹配的情况,只需转换当前_日期而不是创建的列

您可以通过将当前\u日期作为参数传递给UNIX\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