4

csv ファイルを mysql テーブルにインポートしようとしていますが、現在 1 行ずつ実行しているスクリプトがあります。これは、id を別の id と組み合わせてハッシュし、mysql 形式の日付をフォーマットする必要があるためです。

csv ファイルには、現在インポートしているよりも多くの列があります。すべての列をインポートする方が簡単ですか?

LOAD DATA INFILE (http://dev.mysql.com/doc/refman/5.1/en/load-data.html) について読んでいましたが、これをどのように使用して ID をハッシュし、日付をフォーマットするのか疑問に思っています。行ごとの実行を行わずに。現在のスクリプトに時間がかかりすぎて、実行中にサイトのパフォーマンスの問題が発生しています。

ここに私が持っているものがあります:

$url = 'http://www.example.com/directory/file.csv';
if (($handle = fopen($url, "r")) !== FALSE) 
{
fgetcsv($handle, 1000, ",");
while (($data = fgetcsv($handle, 1000, ",")) !== FALSE) 
{
    $EvID = $data[0];
    $Ev = $data[1];
    $PerID = $data[2];
    $Per = $data[3];
    $VName = $data[4];
    $VID = $data[5];
    $VSA = $data[6];
    $DateTime = $data[7];
    $PCatID = $data[8];
    $PCat = $data[9];
    $CCatID = $data[10];
    $CCat = $data[11];
    $GCatID = $data[12];
    $GCat = $data[13];
    $City = $data[14];
    $State = $data[15];
    $StateID = $data[16];
    $Country = $data[17];
    $CountryID = $data[18];
    $Zip = $data[19];
    $TYN = $data[20];
    $IMAGEURL = $data[21];
    $URLLink = $data[22];

        $data[7] = strtotime($data[7]);
        $data[7] = date("Y-m-d H:i:s",$data[7]);

    if((($PCatID == '2') && (($CountryID == '217') or ($CountryID == '38'))) || (($GCatID == '16') or ($GCatID == '19') or ($GCatID == '30') or ($GCatID == '32'))) 
    {
            if(!mysql_query("INSERT IGNORE INTO TNDB_CSV2 
                (id, EvID, Event, PerID, Per, VName,
                     VID, VSA, DateTime, PCatID, PCat,                
                CCatID, CCat, GCatID, GCat, City,
                     State, StateID, Country, CountryID, Zip,
                TYN, IMAGEURL) VALUES
                ('".md5($EventID.$PerformerID)."','".addslashes($data[0])."','".addslashes($data[1])."','".addslashes($data[2])."','".addslashes($data[3])."','".addslashes($data[4])."',
                    '".addslashes($data[5])."','".addslashes($data[6])."','".addslashes($data[7])."','".addslashes($data[8])."','".addslashes($data[9])."',
                '".addslashes($data[10])."','".addslashes($data[11])."','".addslashes($data[12])."','".addslashes($data[13])."','".addslashes($data[14])."',
                    '".addslashes($data[15])."','".addslashes($data[16])."','".addslashes($data[17])."','".addslashes($data[18])."','".addslashes($data[19])."',
                '".addslashes($data[20])."','".addslashes($data[21])."')"))
            {                    
                exit("<br>" . mysql_error());
            }
    }
}
fclose($handle);
}

どんな助けでも大歓迎です。前もって感謝します。

4

3 に答える 3

5

最初にスクリプトを最適化してみてください。まず、他に選択肢がない限り、インポート時に単一のクエリを実行しないでください。ネットワークのオーバーヘッドが致命的なものになる可能性があります。

次のようなことを試してください(明らかにテストされておらず、SOテキストボックスにコード化されています。括弧が一致することを確認してください):

$url = 'http://www.example.com/directory/file.csv';
if (($handle = fopen($url, "r")) !== FALSE) 
{
fgetcsv($handle, 1000, ",");

$imports = array();

while (($data = fgetcsv($handle, 1000, ",")) !== FALSE) 
{
    $EvID = $data[0];
    $Ev = $data[1];
    $PerID = $data[2];
    $Per = $data[3];
    $VName = $data[4];
    $VID = $data[5];
    $VSA = $data[6];
    $DateTime = $data[7];
    $PCatID = $data[8];
    $PCat = $data[9];
    $CCatID = $data[10];
    $CCat = $data[11];
    $GCatID = $data[12];
    $GCat = $data[13];
    $City = $data[14];
    $State = $data[15];
    $StateID = $data[16];
    $Country = $data[17];
    $CountryID = $data[18];
    $Zip = $data[19];
    $TYN = $data[20];
    $IMAGEURL = $data[21];
    $URLLink = $data[22];

        $data[7] = strtotime($data[7]);
        $data[7] = date("Y-m-d H:i:s",$data[7]);

    if((($PCatID == '2') && (($CountryID == '217') or ($CountryID == '38'))) || (($GCatID == '16') or ($GCatID == '19') or ($GCatID == '30') or ($GCatID == '32'))) 
    {

    $imports[] = "('".md5($EventID.$PerformerID)."','".addslashes($data[0])."','".addslashes($data[1])."','".addslashes($data[2])."','".addslashes($data[3])."','".addslashes($data[4])."',
                    '".addslashes($data[5])."','".addslashes($data[6])."','".addslashes($data[7])."','".addslashes($data[8])."','".addslashes($data[9])."',
                '".addslashes($data[10])."','".addslashes($data[11])."','".addslashes($data[12])."','".addslashes($data[13])."','".addslashes($data[14])."',
                    '".addslashes($data[15])."','".addslashes($data[16])."','".addslashes($data[17])."','".addslashes($data[18])."','".addslashes($data[19])."',
                '".addslashes($data[20])."','".addslashes($data[21])."')";



    }
}

$importarrays = array_chunk($imports, 100);
foreach($importarrays as $arr) {

 if(!mysql_query("INSERT IGNORE INTO TNDB_CSV2 
                (id, EvID, Event, PerID, Per, VName,
                     VID, VSA, DateTime, PCatID, PCat,                
                CCatID, CCat, GCatID, GCat, City,
                     State, StateID, Country, CountryID, Zip,
                TYN, IMAGEURL) VALUES ".implode(',', $arr)){

     die("error: ".mysql_error());

 }

 }

fclose($handle);
}

array_chunk の数値をいじってみると、大きすぎると、クエリが長すぎる (my.cnf に設定可能な制限があります)、小さすぎる、不要なオーバーヘッドなどの問題が発生する可能性があります。

$data[x] を変数に代入する使用をやめることもできます。これは、スクリプトがどれほど小さいかを考えると無駄なので、クエリで直接 $data[x] を使用するだけです (大幅な改善は得られませんが、状況によってはインポートサイズを少し節約できます)。

次は、優先度の低い挿入/更新を使用することです。開始するには、これに関する詳細情報を確認してください:特定のクエリに優先度を与えるには?

結局のところ、mysql構成の最適化について考えることができますが、それはGoogleが実際に説明するものであり、最適な設定は人によって異なり、それぞれの状況によって異なります

編集:以前に行ったもう1つのことは、インポートに必要のない多くのキーが設定されている場合、それらのキーを一時的に削除し、スクリプトが完了したときにそれらを追加し直すことができるということです. これにより、時間の短縮も期待できますが、ライブ データベースで作業しているため、そのルートをたどると回避すべき落とし穴があります。

于 2012-09-27T13:09:34.463 に答える
1

implode()関数を使用してバッチ挿入を実行してみてください。詳細な説明と例については、このスレッドを参照してください

于 2012-09-27T13:05:30.180 に答える
1

このクエリを使用しました

$sql = "
        LOAD DATA LOCAL INFILE 'uploads/{$fileName}'
        REPLACE INTO TABLE `order`
        FIELDS
            TERMINATED BY '\t'
        LINES
            TERMINATED BY '\r\n'
        IGNORE 1 LINES
        (product_id, `date`, quantity)
        ";

それは超高速です

于 2014-08-06T19:16:46.050 に答える