1

重複の可能性:
データベースからphpのcsvへのメモリ使用量のエクスポート

大規模なデータベースをエクスポートしていて、メモリフットプリントを低くするための最良の方法を知りたいと思いました。

時間制限があり、メモリの使用量が少ないサイクルでこれを実行する必要があることを認識しています。一度に100行をフェッチし、情報をファイルに保存してから、前のサイクルで終了したところから新しいサイクルを開始するようにリダイレクトします。

データをファイルにバッファリングし、メモリが不足しないようにする最善の方法は何でしょうか。現在、スクリプトはすべてのデータを文字列として取得し、データベースからすべての行を取得し終えたらファイルに保存します。時々それはメモリを使い果たします、それ故に修正する必要があります。

varに入れたり、一時ファイルを使用したりする代わりに、データベースからフェッチしたデータにfwrite()を使用しますか?一時ファイルを使用する場合、バックアップファイルにマージ/名前変更するのはいつですか?

基本的に、「致命的なエラー:PHPで許可されたメモリサイズが使い果たされました」というエラーが発生せずに、スクリプトがデータベースデータをファイルにエクスポートするための最良の方法は何ですか?

    function backup_tables($host, $user, $pass, $db, $tables = '*')
    {
            set_time_limit(0);

            $mysqli = new mysqli($host,$user,$pass, $db);
            if ($mysqli->connect_errno)
            {
                echo "Failed to connect to MySQL: (" . $mysqli->connect_errno . ") " . $mysqli->connect_error;
            }

            $return = '';

            $return .= "--\n";
            $return .= "-- Database: `$db`\n";
            $return .= "--\n\n";
            $return .= "-- --------------------------------------------------------\n\n";

            $numtypes = array(
                'tinyint', 
                'smallint',
                'mediumint',
                'int',
                'bigint',
                'float',
                'double',
                'decimal',
                'real'
            );

            // get all of the tables
            if ($tables == '*')
            {
                    $tables = array();
                    $result = $mysqli->query('SHOW TABLES');
                    while ($row = $result->fetch_row())
                    {
                            $tables[] = $row[0];
                    }

                    $result->close();
            }
            else
            {
                    $tables = is_array($tables) ? $tables : explode(',',$tables);
            }

            for ($z = 0; $z == 0; $z++)
            {
                echo $z.'<br>';

            // cycle through tables
            foreach ($tables as $table)
            {
                    //
                    $typesarr = array();
                    $result = $mysqli->query("SHOW COLUMNS FROM `".$table."`");

                    while ($row = $result->fetch_assoc())
                    {
                            $typesarr[] = $row;
                    }
                    $result->close();

                    #echo '<h2>'.$table.'</h2>';
                    #print("<pre>" . print_r($typesarr, true). "</pre>");

                    // table structure dump
                    $return .= "--\n";
                    $return .= "-- Table structure for table `$table`\n";
                    $return .= "--\n\n";                        
                    $return.= 'DROP TABLE IF EXISTS `'.$table.'`;'."\n\n";
                    $result = $mysqli->query("SHOW CREATE TABLE `".$table."`");
                    $row = $result->fetch_array();
                    $return.= $row[1].";\n\n";
                    $result->close();

                    // table data dump
                    $return .= "--\n";
                    $return .= "-- Dumping data for table `$table`\n";
                    $return .= "--\n\n";

                    $result = $mysqli->query("SELECT * FROM `".$table."`");
                    $num_fields = $result->field_count;

                    if ($result->num_rows > 0)
                    {
                            // put field names in array and into sql insert for dump
                            $fields_str = '';
                            $fields =  array();
                            $finfo = $result->fetch_fields();

                            foreach ($finfo as $val)
                            {
                                    $fields_str .= '`'.$val->name.'`, ';
                                    $fields[] = $val->name;
                            }                                

                            $fields_str = '('.rtrim($fields_str, ', ').')';
                            $return.= 'INSERT INTO `'.$table.'` '.$fields_str.' VALUES'."\n";

                            // cycle through fields and check if int for later use
                            for ($i = 0; $i < $num_fields; $i++) 
                            {
                                    // strip brackets from type
                                    $acttype = trim(preg_replace('/\s*\([^)]*\)/', '', $typesarr[$i]['Type']));
                                    $acttype = explode(' ', $acttype);

                                    // build array, is field int or not
                                    if (is_numeric(array_search($acttype[0], $numtypes)))
                                    {
                                            $numflag[$i] = 1;
                                    }
                                    else
                                    {
                                            $numflag[$i] = 0;        
                                    }
                            }
                    }  

                    $x = 0;
                    $num_rows = $result->num_rows;

                    // cycle through table rows
                    while($row = $result->fetch_row())
                    {
                            $x++;

                            // cycle through rows fields
                            for($j=0; $j<$num_fields; $j++) 
                            {          
                                    if (isset($row[$j]) and $j === 0) { $return .= '('; }

                                    // field data has value or not NULL
                                    if (isset($row[$j]))
                                    { 
                                            // field data dump (INT)
                                            if ($numflag[$j]==1)
                                            {
                                                    #echo '(INT) '. $fields[$j].' = '.$row[$j].'<br>';
                                                    $return.= $mysqli->real_escape_string($row[$j]);
                                            } 
                                            else
                                            {
                                                    // field data dump values (empty string, NULL and INT)
                                                    $return.= "'".$mysqli->real_escape_string($row[$j])."'";
                                                    #echo $fields[$j]." = '".$mysqli->real_escape_string($row[$j])."'<br>";
                                            }
                                    }
                                    else
                                    {
                                            // field data dump (NULL)
                                            if (is_null($row[$j]))
                                            {
                                                    $row[$j] = 'NULL';
                                                    #echo '(NULL) '. $fields[$j].' = '.$row[$j].'<br>';
                                                    $return.= $row[$j]; 
                                            }
                                            else
                                            {
                                                    // field data dump (empty string)
                                                    $return.= "''";
                                            }
                                    }

                                    if ($j<($num_fields-1)) { $return.= ', '; }
                            }

                            if ($x<$num_rows) { $return.= "),\n"; } else { $return .= ");\n"; }

                            #echo '<br>';
                    }
                    #echo 'Rows: '.$rows.'<br>';
                    #echo 'Iterations: '.$x.'<br>';
                    $return.="\n-- --------------------------------------------------------\n\n";
            }

            }

            $result->close();

            //save file
            $handle = fopen('/db-backup-'.time().'.sql','a');
            fwrite($handle,$return);
            fclose($handle);
    }

例を歓迎します

4

2 に答える 2

0

の最近のバージョンはmysqldumpデフォルトで--opt有効になっています--quick。これには、テーブル全体をメモリにバッファリングせずに、行が一度に1つずつフェッチされることを示します。したがって、のメモリフットプリントはmysqldumpすでにかなり低いはずです。

使用時に実際に問題があると思いますmysqldumpか?もしそうなら、それらはどのように現れますか?メモリが不足していますか、それともmysqlサーバーですかmysqldump、それとも完全に他の何かですか?

于 2012-09-30T19:19:15.583 に答える
0

結果を一度に1行ずつ繰り返し、すべてを1つの束でPHPに転送せずに、呼び出しにパラメーターMYSQLI_USE_RESULTとして追加します。のドキュメントも参照してください。resultmodemysqli::querymysqli::use-result

$result変数を避けて、各行を出力ファイルに直接書き込みます。上記と組み合わせると、各行がサーバーからフェッチされてファイルに書き込まれる可能性があるため、PHPは一度に複数の行を格納する必要がありません。

于 2012-09-30T21:31:26.730 に答える