2011-11-22 105 views
2

的我有以下代码移动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循环,我相信它会工作得更快。我被卡住了,不知道该怎么做。任何帮助,将不胜感激。

回答

0

我想至少是说,你应该在结合查询循环每天只有一个。所以对于5天的范围,你会有5个查询。

或者您可以对整个日期范围进行单个查询并将其移至循环外部(如ajreal所述)。然后使用PHP将其全部排序。

对于大型数据库,我宁愿分解一些查询来平衡负载和超时风险。也有助于保持代码的可维护性。

您还应该看看数据库的结构和索引。

它明显慢吗?

并且array_push功能是必需的吗? (不是说它会节省很多,只是想知道它看起来多余)

如果它真的很慢,那么可能会考虑根据您的使用方式完全重构流程。

你可以,例如,在00:01每天做这样的事情:

  • 查询日志天数和独特/总IP/ID达
  • 只插入计数数字和日期到一个单独的表
  • 归档天登录到一个单独的存档表,甚至一个单独的数据库就像mongoDB

这样,您就可以进行简单的querys查看数据并以良好的性能操纵数字到你的心中。通过归档,您可以通过删除不必要的行来保持查询表的小型化,但如果以后需要维护日志。

当然,这可能不适合你的数据库设置。

+0

这个函数还没有完成,我这样做完全查询插入值到单独的表。它将通过cron每天执行。 – mintobit

+0

是有道理的,可以看到在最后返回一个分贝,但不知道什么。 – Taylor

+0

如果这是每天执行的,为什么你需要基于天的循环?当然你可以取消很多代码并只查询一次? – Taylor

-1

取所有的subids,并使用IN谓词进行提取以同时获取所有值。填写数组,然后循环数组。

+0

感谢您的快速回复。问题是我在WHERE子句中也有'date'列,它依赖于FOR循环。 – mintobit

+0

您仍然需要循环日期,因为这些值是“正在改变”的值,除非您想创建一个这样的数组,并将它们包含在另一个“IN”部分中。 –

+0

我有大约400,000条记录,我想这会显着提高性能,是吗?(我的意思是将查询移出循环)。我还有另一个想法,将所有的疑问合并为一个,希望能够获得更多的表现。告诉我我错在哪里。 – mintobit

-1

使用PDO :: MySQL扩展而不是MySQL或MySQLi扩展。这样,你可以准备查询,这将大大加快mysql调用的执行时间。

0

得到所有subid

为每个表,
建立一个单一的查询最小日期间进行过滤,和最大的日期,
和group by日期

select subid, `date`, count(*) ... 
where subid IN($subids) and `date` between $smallest and $largest 
group by subid, `date` 

迭代结果,并将结果存储到数组中,并以subid,日期作为密钥

$mysql_results = array[$subid][$date] ... 

最后,迭代$ subids和日期,像

foreach ($subids as $subid) 
{ 
    for ($i = 0; $i < $days; $i++) 
    { 
    // set $date 

    // check $mysql_results[$subid][$date] exists 
    } 
} 

喜欢的东西上面,你只需要5个查询,而不是

5 x total days x size of the subids 
+0

听起来很完美!我试图调整你的模式到这个查询:“SELECT(SELECT COUNT(DISTINCT'id','subid')FROM'tb_stats' WHERE'date' <= $ date AND'subid' = $ subid) - (SELECT COUNT(DISTINCT'id','subid')FROM'tb_stats' WHERE'date' <= $ date_prev AND'subid' = $ subid)AS'unique_ids'“ – mintobit

+0

嗯,我再次卡住了。我需要计数(选择计数(distinct id,subid),其中从tb_stats其中subid在(...)和日期...和...之间) - (select count(distinct id,subid)where tb_stats where subid在...和...之间的日期)但是这不起作用,因为我需要提供不同ID的数量,subid其中subid = ...和date = ... MINUS不同ID的数量,subid其中subid = ...和日期=之前的日子 – mintobit