【问题标题】:best practice php array and RAM usage最佳实践 php 数组和 RAM 使用
【发布时间】:2012-11-16 01:08:46
【问题描述】:

我有 12 个 mysql 数据库表,例如 table1、table2、....table12。每个表有 200,000 条记录。每条记录包括国家、用户类型、包列。我想获得以上 3 列的统计信息。为此,首先,我正在创建数组。然后使用数组,我得到统计数据。

for ($i=1; $i<=12; $i++)
{
   $query="SELECT `country`, `usertype`, `package` FROM `table$i`";
   $result=mysql_query($query);
   while ($row = mysql_fetch_assoc($result))
   {
      $country= $row['country'];
      $usertype= $row['usertype'];
      $package= $row['package'];

      $stat_array[$country][$usertype][$package]= 1 + $stat_array[$country][$usertype][$package]
   }
}

需要很多时间才能得到结果。这是获得统计数据的最佳方法吗?请教我一个好方法。另外,这会使用更多的 RAM 内存吗?我需要一种减少内存使用的方法

提前致谢

【问题讨论】:

  • 它使用多少内存?你希望它减少多少?你试过什么?
  • 感谢先生的快速回复。我没有检查ram的使用情况。我需要一种最好的方法来使用更少的 ram 来获得 statistac
  • 如果你不检查使用情况,那么你怎么知道你做了什么来使用更少的内存?

标签: php mysql arrays memory


【解决方案1】:

12 个查询?请注意,SQL 中有 UNION 命令。 试试这个:

for ($i=1; $i<=12; $i++)
   $query=($i>1?'UNION ALL ':'')."SELECT `country`, `usertype`, `package` FROM `table$i` ";
$result=mysql_query($query);
// other code below

【讨论】:

  • 不能解决内存问题,但多次降低处理时间。
  • 不要使用 UNION,而是使用 UNION ALL。您想计算所有表中的所有记录。 UNION 将丢弃单独表中的重复行。
【解决方案2】:

这里的一个问题是因为你在同一个函数中所有的php不会删除变量分配的内存。因此,您覆盖/创建一个新行,...。

您需要在 while 循环结束时取消设置行、国家、用户类型和包。这应该有助于记忆(至少在 PHP 5.3 之前,我在遍历大量数据行时遇到了类似的问题)。另一个问题是 stat_arr 变量,因为它为数据库中 3 个字段的每个组合创建 1 个数组字段。最坏的情况是您有 200k 个条目。这本身会占用很多内存。

此外,据我所知,您只想计算这 3 个列。这可以通过不同的方式完成:

使用(我不知道您如何调用您的 ID/主字段,因此我在以下代码中将其称为 id):

$Query = "SELECT count(id) AS c_u_p_statistics,`country`, `usertype`, `package` FROM `table$i` GROUP BY `country`, `usertype`, `package`";

这样您就不必手动汇总它们,而是可以通过 SQL 来完成(大多数时候效率更高)。

【讨论】:

  • 迭代mysql结果集并不会造成巨大的内存消耗,而取消设置$row也无助于大量减少内存消耗
  • 根据我在 PHP 5.4 之前使用 php 的经验,如果在下一行重用变量之前没有取消设置,至少还有几个字节存在。过去我有一些小的内存泄漏(非常小),但是当我迭代 1-2 个 mio 行时,它累积到几兆字节的总内存泄漏。 (当我在循环结束时使用 unset 时,泄漏消失了)。
  • 大声笑...我不认为这是有道理的,对不起,如果我太天真了。每次迭代只是再次设置现有变量,它对额外内存有何贡献?
  • 我过去有过内存泄漏(php 5.2 和 5.3),经过几次测试后我找不到原因,并且尝试取消设置,我发现问题仅发生在 $当我在 while 循环结束时使用 no unset 时的行部分。我知道这听起来不合逻辑(特别是如果有人考虑垃圾收集应该如何工作),但当时它是唯一有助于解决几百万行数据累积的小(2-7 字节)内存泄漏到相当大的泄漏。也许其他人知道那里出现这种现象的原因。
  • 我很难相信这一点,我一直在使用 5.3,并且处理了 2000 万次结果迭代,我从来没有遇到过这个问题,也许你的方式不同,例如,附加功能调用每次迭代,通过引用传递..等
【解决方案3】:

全部在查询中。下面的查询将为您提供每个国家、用户类型和包的计数结果。显然你可以使用循环来创建 12 个表并集,但为了便于阅读,我将其全部写下来。

还要记住使用 UNION ALL 而不仅仅是 UNION。如果使用 UNION 会丢弃重复的行,但是如果表 1 的某个组的计数为 100,而表 2 的同一组也有 100,则您要返回 100 两次,因此总和为 200。如果您使用 UNION 它会返回 100 一次,总和显然也是 100。

SELECT SUM(cnt) as total, `country`, `usertype`, `package` FROM
(
    SELECT COUNT(country) as cnt, `country`, `usertype`, `package` FROM table1 GROUP BY `country`, `usertype`, `package`
    UNION ALL
    SELECT COUNT(country) as cnt, `country`, `usertype`, `package` FROM table2 GROUP BY `country`, `usertype`, `package`
    UNION ALL
    SELECT COUNT(country) as cnt, `country`, `usertype`, `package` FROM table3 GROUP BY `country`, `usertype`, `package`
    UNION ALL
    SELECT COUNT(country) as cnt, `country`, `usertype`, `package` FROM table4 GROUP BY `country`, `usertype`, `package`
    UNION ALL
    SELECT COUNT(country) as cnt, `country`, `usertype`, `package` FROM table5 GROUP BY `country`, `usertype`, `package`
    UNION ALL
    SELECT COUNT(country) as cnt, `country`, `usertype`, `package` FROM table6 GROUP BY `country`, `usertype`, `package`
    UNION ALL
    SELECT COUNT(country) as cnt, `country`, `usertype`, `package` FROM table7 GROUP BY `country`, `usertype`, `package`
    UNION ALL
    SELECT COUNT(country) as cnt, `country`, `usertype`, `package` FROM table8 GROUP BY `country`, `usertype`, `package`
    UNION ALL
    SELECT COUNT(country) as cnt, `country`, `usertype`, `package` FROM table9 GROUP BY `country`, `usertype`, `package`
    UNION ALL
    SELECT COUNT(country) as cnt, `country`, `usertype`, `package` FROM table10 GROUP BY `country`, `usertype`, `package`
    UNION ALL
    SELECT COUNT(country) as cnt, `country`, `usertype`, `package` FROM table11 GROUP BY `country`, `usertype`, `package`
    UNION ALL
    SELECT COUNT(country) as cnt, `country`, `usertype`, `package` FROM table12 GROUP BY `country`, `usertype`, `package`

) temp
GROUP BY `country`, `usertype`, `package`

附注:你不必这样做

$stat_array[$country][$usertype][$package]= 1 + $stat_array[$country][$usertype][$package];

你可以这样做:

$stat_array[$country][$usertype][$package]++;

最后,如果您使用像您这样的多维数组,则在内部必须进行大量检查。简单地说,它会首先在数组中找到正确的国家,这将给出另一个数组。它将在该数组中定位用户类型,然后在第三个数组中再次执行相同的操作。

如果 $country、$usertype 和 $package 都是字符串,你最好加入字符串并使用它。

$key = $country.'_'.$usertype.'_'.$package;
$stat_array[$key]++;

但我想这一切都取决于您将数据存储在数组中后要如何处理数据。如果它只是打印总计数,你甚至不需要数组,而是直接在查询结果循环中打印。

【讨论】:

  • 为什么会杀了它?这就是联合运算符的用途。
  • 假设行数合理
  • 这是假设建立了正确的索引。在这种情况下,将countryusertypepackage 放在一起。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多