0

I am trying to build a table of part numbers with this script. I am quickly running out of memory. I have commented out the loops I couldn't even get to:

 foreach ($mat_codes as $mat_code) {
     for ($n = 0; $n < count($shape_codes); $n++){
        for ($d1 = 0; $d1 <= 12; $d1++){
          for ($d1_dec = 1; $d1_dec <= 16; $d1_dec++){
            for ($d2 = 0; $d2 <= 12; $d2++){
              //for ($d2_dec = 1; $d2_dec <= 16; $d2_dec++){
                $build_part = (object) NULL;
                $build_part = $mat_code->part_code;
                $build_part .= $shape_codes[$n]->part_code;
                $build_part .= '.';
                if ($d1 != 0) {
                  $build_part .=  $d1 . '-';
                }
                $build_part .= $d1_dec;
                $build_part .= '.';
                //  if ($d2 != 0) {
                //    $build_part .=  $d2 . '-';
                //  }
                // $build_part .= $d2_dec;
                // $build_part .= '.';

                // * save $build_part to MYSQL * //
             //}
           }
        }
      }
    }
  }

Unsurprisingly this is returning

PHP Fatal error: Allowed memory size of 134217728 byets exhauseted (tried to allocate 71 bytes)

For the record there are about 16 values in $mat_codes and 16 in $shape_codes. By my calculations, I'm trying to create 692,224 part numbers in this example alone. I think I'm going to add more and have up to ~34 million. IMHO, it would be silly to try and get this done by just allocating more memory to the job. My question -- of course -- how do I break this script up into smaller chunks?

Edit: I have a workaround. I apologize it is out of the scope I defined in the original question. I didn't mention that this is simply a table of potential part numbers. Particularly, all the potential part numbers allowed by the logic of the part numbering system. Rather than have a master list of part numbers at the ready just waiting to be used I figure I might be better off validating new part input against the part numbering logic, a function like could_this_be_a_part_number($input). It could just test the inputted string against the part numbering logic as opposed to having some master table I would need to check against.

Edit x2: I'm sorry this is the worst. I moved unset($build_part) into the innermost for loop. The problem was I was trying to a development function in Drupal to print out each $build_part before it was unset - dpm($build_part). The script runs fine, its trying to build a webpage with that many part numbers printed to it is what breaks the script.

4

1 回答 1

1

首先:$build_part似乎不应该是一个对象,因为你把它当作一个字符串,所以不要那样初始化它。

$build_part = NULL;就足够了。

其次:我们不知道您希望如何将数据保存在数据库中,但您可以(正如我最初的回答以某种方式提出的那样)建立一个查询,将其发送到数据库然后继续。

现在让我们看看你的代码:

$i = 0;
foreach ($mat_codes as $mat_code) {
     for ($n = 0; $n < count($shape_codes); $n++){
        for ($d1 = 0; $d1 <= 12; $d1++){
          for ($d1_dec = 1; $d1_dec <= 16; $d1_dec++){
            for ($d2 = 0; $d2 <= 12; $d2++){
              for ($d2_dec = 1; $d2_dec <= 16; $d2_dec++){
                $i++;
                $build_part = (object) NULL;
                $build_part = $mat_code->part_code.".";
                $build_part .= $shape_codes[$n]->part_code;
                $build_part .= '.';
                if ($d1 != 0) {
                  $build_part .=  $d1 . '-';
                }
                $build_part .= $d1_dec;
                $build_part .= '.';
                 if ($d2 != 0) {
                   $build_part .=  $d2 . '-';
                 }
                $build_part .= $d2_dec;
                // echo "$i $build_part <br>";
                // * save $build_part to MYSQL * //
             }
             // This is first triggered when the count reaches 16 items
             echo "--- lvl 5<br>";
           }
           // 208 items
           echo "--- lvl 4<br>";
        }
        // 3328 items
        echo "--- lvl 3<br>";
      }
      echo "--- lvl 2<br>";
    }
    echo "--- lvl 1<br>";
}

我已经确定(你可以在其他地方做)3 级标志作为你可以向数据库发送一些预先构建的 MySQL 查询的点。就像是:

$mysqli->query("INSERT INTO parts (part_id) VALUES $very_long_string;");

另请查看此 MySQL 命令:INSERT DELAYED,我认为它可能(原文如此!)在您的情况下非常有用。

$very_long_string将构建在最内部的循环中,例如:

$very_long_string .= "('$build_part'),";

最后(在我们创建和发送最终查询之前)我们将删除最后一个逗号:

$very_long_string = rtrim($very_long_string, ",");

然后将 3000+ 项长查询发送到数据库中。然后 unset($very_long_string) 并重新开始。

所以我猜最终的代码应该是这样的:

foreach ($mat_codes as $mat_code) {
for ($n = 0; $n < count($shape_codes); $n++){
    for ($d1 = 0; $d1 <= 12; $d1++){
        $very_long_string = null;
        for ($d1_dec = 1; $d1_dec <= 16; $d1_dec++){
            for ($d2 = 0; $d2 <= 12; $d2++){
                for ($d2_dec = 1; $d2_dec <= 16; $d2_dec++){
                $build_part = NULL;
                $build_part = $mat_code->part_code.".";
                $build_part .= $shape_codes[$n]->part_code;
                $build_part .= '.';
                if ($d1 != 0) {
                    $build_part .=  $d1 . '-';
                }
                $build_part .= $d1_dec;
                $build_part .= '.';
                if ($d2 != 0) {
                    $build_part .=  $d2 . '-';
                }
                $build_part .= $d2_dec;
                $very_long_string .= "('$build_part'),";
                }
            }
        }
        $very_long_string = rtrim($very_long_string, ",");
        $mysqli->query("INSERT INTO parts (part_id) VALUES $very_long_string;");
        unset($very_long_string);
    }
}
}

阅读您的编辑后进行编辑:我当然是在处理您想要填充数据库的事实:D .. 如果您需要一个验证功能,那就是另一回事了。

于 2013-06-07T02:23:02.213 回答