将 mysql 查询移出循环
我有以下代码,
function cron_day_counts()
{
$subids = get_subids();
array_push($subids, '');
$from = '2011-10-19';
$to = '2011-10-20';
$days = days_interval($from, $to);
$result_array = array();
foreach ($subids as $subid)
{
for ($i = 0; $i < $days; $i++)
{
$date = date('Y-m-d', strtotime($from . '+ ' . $i . ' day'));
$date_prev = date('Y-m-d', strtotime($date . '- 1 day'));
$unique_id_query = mysql_query('SELECT (SELECT COUNT(DISTINCT `id`,`subid`) FROM `tb_stats` WHERE `date` <= \'' . $date . '\'' . (!empty($subid) && is_numeric($subid) ? ' AND `subid` = \'' . mysql_real_escape_string($subid) . '\'' : '') . ') - (SELECT COUNT(DISTINCT `id`,`subid`) FROM `tb_stats` WHERE `date` <= \'' . mysql_real_escape_string($date_prev) . '\'' . (!empty($subid) && is_numeric($subid) ? ' AND `subid` = \'' . mysql_real_escape_string($subid) . '\'' : '') . ') AS `unique_ids`');
$unique_id_result = mysql_fetch_assoc($unique_id_query);
$total_id_query = mysql_query('SELECT COUNT(DISTINCT `id`,`subid`) AS `total_ids` FROM `tb_stats` WHERE `date` = \'' . mysql_real_escape_string($date) . '\'' . (!empty($subid) && is_numeric($subid) ? ' AND `subid` = \'' . mysql_real_escape_string($subid) . '\'' : ''));
$total_id_result = mysql_fetch_assoc($total_id_query);
$unique_ip_query = mysql_query('SELECT (SELECT COUNT(DISTINCT `ip`,`subid`) FROM `tb_stats` WHERE `date` <= \'' . $date . '\'' . (!empty($subid) && is_numeric($subid) ? ' AND `subid` = \'' . mysql_real_escape_string($subid) . '\'' : '') . ') - (SELECT COUNT(DISTINCT `ip`,`subid`) FROM `tb_stats` WHERE `date` <= \'' . mysql_real_escape_string($date_prev) . '\'' . (!empty($subid) && is_numeric($subid) ? ' AND `subid` = \'' . mysql_real_escape_string($subid) . '\'' : '') . ') AS `unique_ips`');
$unique_ip_result = mysql_fetch_assoc($unique_ip_query);
$total_ip_query = mysql_query('SELECT COUNT(DISTINCT `ip`,`subid`) AS `total_ips` FROM `tb_stats` WHERE `date` = \'' . mysql_real_escape_string($date) . '\'' . (!empty($subid) && is_numeric($subid) ? ' AND `subid` = \'' . mysql_real_escape_string($subid) . '\'' : ''));
$total_ip_result = mysql_fetch_assoc($total_ip_query);
$global_query = mysql_query('SELECT COUNT(`id`) AS `global` FROM `tb_stats` WHERE `date` = \'' . mysql_real_escape_string($date) . '\'' . (!empty($subid) && is_numeric($subid) ? ' AND `subid` = \'' . mysql_real_escape_string($subid) . '\'' : ''));
$global_result = mysql_fetch_assoc($global_query);
$result = array();
$result['subid'] = $subid;
$result['date'] = $date;
$result['unique_ids'] = $unique_id_result['unique_ids'];
$result['total_ids'] = $total_id_result['total_ids'];
$result['unique_ips'] = $unique_ip_result['unique_ips'];
$result['total_ips'] = $total_ip_result['total_ips'];
$result['global'] = $global_result['global'];
$result_array[] = $result;
}
}
//db insert
return $result_array;
}
我想将所有查询移出 foreach 和 for 循环,我相信它会工作得更快。我被困住了,不知道该怎么做。任何帮助将不胜感激。
i have the following code
function cron_day_counts()
{
$subids = get_subids();
array_push($subids, '');
$from = '2011-10-19';
$to = '2011-10-20';
$days = days_interval($from, $to);
$result_array = array();
foreach ($subids as $subid)
{
for ($i = 0; $i < $days; $i++)
{
$date = date('Y-m-d', strtotime($from . '+ ' . $i . ' day'));
$date_prev = date('Y-m-d', strtotime($date . '- 1 day'));
$unique_id_query = mysql_query('SELECT (SELECT COUNT(DISTINCT `id`,`subid`) FROM `tb_stats` WHERE `date` <= \'' . $date . '\'' . (!empty($subid) && is_numeric($subid) ? ' AND `subid` = \'' . mysql_real_escape_string($subid) . '\'' : '') . ') - (SELECT COUNT(DISTINCT `id`,`subid`) FROM `tb_stats` WHERE `date` <= \'' . mysql_real_escape_string($date_prev) . '\'' . (!empty($subid) && is_numeric($subid) ? ' AND `subid` = \'' . mysql_real_escape_string($subid) . '\'' : '') . ') AS `unique_ids`');
$unique_id_result = mysql_fetch_assoc($unique_id_query);
$total_id_query = mysql_query('SELECT COUNT(DISTINCT `id`,`subid`) AS `total_ids` FROM `tb_stats` WHERE `date` = \'' . mysql_real_escape_string($date) . '\'' . (!empty($subid) && is_numeric($subid) ? ' AND `subid` = \'' . mysql_real_escape_string($subid) . '\'' : ''));
$total_id_result = mysql_fetch_assoc($total_id_query);
$unique_ip_query = mysql_query('SELECT (SELECT COUNT(DISTINCT `ip`,`subid`) FROM `tb_stats` WHERE `date` <= \'' . $date . '\'' . (!empty($subid) && is_numeric($subid) ? ' AND `subid` = \'' . mysql_real_escape_string($subid) . '\'' : '') . ') - (SELECT COUNT(DISTINCT `ip`,`subid`) FROM `tb_stats` WHERE `date` <= \'' . mysql_real_escape_string($date_prev) . '\'' . (!empty($subid) && is_numeric($subid) ? ' AND `subid` = \'' . mysql_real_escape_string($subid) . '\'' : '') . ') AS `unique_ips`');
$unique_ip_result = mysql_fetch_assoc($unique_ip_query);
$total_ip_query = mysql_query('SELECT COUNT(DISTINCT `ip`,`subid`) AS `total_ips` FROM `tb_stats` WHERE `date` = \'' . mysql_real_escape_string($date) . '\'' . (!empty($subid) && is_numeric($subid) ? ' AND `subid` = \'' . mysql_real_escape_string($subid) . '\'' : ''));
$total_ip_result = mysql_fetch_assoc($total_ip_query);
$global_query = mysql_query('SELECT COUNT(`id`) AS `global` FROM `tb_stats` WHERE `date` = \'' . mysql_real_escape_string($date) . '\'' . (!empty($subid) && is_numeric($subid) ? ' AND `subid` = \'' . mysql_real_escape_string($subid) . '\'' : ''));
$global_result = mysql_fetch_assoc($global_query);
$result = array();
$result['subid'] = $subid;
$result['date'] = $date;
$result['unique_ids'] = $unique_id_result['unique_ids'];
$result['total_ids'] = $total_id_result['total_ids'];
$result['unique_ips'] = $unique_ip_result['unique_ips'];
$result['total_ips'] = $total_ip_result['total_ips'];
$result['global'] = $global_result['global'];
$result_array[] = $result;
}
}
//db insert
return $result_array;
}
I want to move all the query out of the foreach and for loops, I believe it would work faster. I'm stuck o this, having no idea how to do this. Any help would be appreciated.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
获取每个表的所有
subid
,
构建单个查询以在最小日期和最大日期之间进行过滤,
并按日期分组
迭代结果,并将结果存储到数组中,
最后以 subid、date 为键,迭代 $subids 和日期,就像
上面那样,您只需要 5 个查询,而不是
get all the
subid
for each table,
build a single query to filter between the smallest date, and largest date,
and group by the date
iterate the result, and stored the result into array, with subid, date as key
lastly, iterate the $subids and date, like
with something like above, you only required 5 queries instead of
获取所有
subids
,并使用IN
谓词进行提取,以一次性获取所有值。将其填充到数组中,然后循环该数组。Take all of your
subids
, and do a fetch with anIN
predicate to get all of the values at once. Stuff that in to an array, then loop the array.使用 PDO::MySQL 扩展而不是 MySQL 或 MySQLi 扩展。这样,您就可以准备查询,这将大大加快 mysql 调用的执行时间。
Use the PDO::MySQL extension instead of the MySQL or MySQLi extensions. This way, you can prepare the queries which will speed up considerably the execution time of the mysql calls.
我想说至少你应该将循环中的查询合并为每天一个。因此,对于 5 天的范围,您将有 5 个查询。
或者您可以对整个日期范围进行单个查询并将其移到循环之外(如 ajreal 所描述)。然后用PHP来整理一下。
对于大型数据库,我宁愿稍微拆分查询以平衡负载和超时风险。还有助于保持代码的可维护性。
您还应该查看数据库的结构和索引方式。
是不是明显很慢?
array_push 函数有必要吗? (并不是说它会节省很多,只是想知道因为它看起来多余)
如果它真的很慢,那么也许可以考虑完全根据你如何使用它来重构过程。
例如,您可以在每天 00:01 执行如下操作:
这样您就可以执行简单的查询来查看数据并操作良好的表现让您心满意足。通过归档,您可以删除不必要的行,但在以后需要时维护日志,从而保持查询表较小。
当然,这可能不适合您的数据库设置方式。
I would say at the very least you should combine the queries in the loop to just one for each day. So for a 5 day range you would have 5 queries.
Or you could have a single query for the whole date range and move it outside the loop (as described by ajreal). Then use PHP to sort it all out.
For large databases I would rather split up queries a little to balance out the load and risk of timeouts. Also helps keep the code maintainable.
You should also look at how your database is structured and indexed.
Is it noticeably slow?
and is the array_push function necessary? (not that it would save much, just wondered cause it looks redundant)
If its really slow then maybe think about restructuring the process completely depending on how you use it.
You could, for example, at 00:01 each day do something like this:
This way you can perform simple querys to view the data and manipulate the numbers to your hearts content with good performance. And by archiving you're keeping the query table small by removing unecessary rows but maintaining a log if needed later.
Of course, this may not fit in with how your db is setup.