2016-07-19 20 views
1

私は.csvファイルにエクスポートする必要がある非常に大きなデータベーステーブル(700kレコード以上)を持っています。それをエクスポートする前に、いくつかのオプション(GUIを使用してユーザが提供する)をチェックし、レコードをフィルタリングする必要があります。残念ながら、このフィルタ処理はSQLコードでは実現できません(たとえば、列にはシリアル化されたデータが含まれているため、シリアル化を解除してレコードがフィルタリングルールを "通過"するかどうかを確認する必要があります)。PHP:MySQLデータベースから大量のデータをフィルタリングしてエクスポートする

すべてのレコードを一度に実行すると、 50KBのレコードを読み込むのではなく、50KBのレコードをロードし、フィルタを適用し、.csvファイルに保存してから、他の50kレコードをロードして(これは700kレコードに達するまでです)このようにしてメモリの問題は回避していますが、約3分かかります(レコード数が増えるとこの時間が増えます)。

他の方法はありますかデータベース構造を変更することなく、このプロセス(時間の点でより良い)?

ありがとうございます!

+1

あなたは[key_buffers](http://stackoverflow.com/questions/3663515/mysql-what-is-the-key-buffer)で回り込み、読んでいる間にInnoDBからMyISAMに切り替えることができます。他の方法があることは確かです。とりわけ、mysqlの設定に惑わされてしまいます。 – Andrew

+0

700K行は中程度のサイズです。 *現代システムでは非常に大きな*は100M以上の行です。 –

+0

申し訳ありません@OllieJones、私はそれについて知らなかった –

答えて

0

あなたがそれ以外のことを言わない限り、PHPは結果セット全体を一度にRAMにスラップします。これは、バッファリングされたクエリと呼ばれています。発見したように、結果セットに数百行以上含まれている場合は機能しません。

phpのデザイナーは、いくつかのデータ行を読み込んで表示する必要のあるWebサイト開発者にとって、バッファリングされたクエリを使用して簡単にしました。

あなたがしていることを行うにはunbuffered queryが必要です。あなたのPHPプログラムは一度に1つの行を読み込んで処理します。しかし、あなたのプログラムがバッファリングされていない結果セットのすべての行を読み込ませるように注意してください。部分的な結果セットをMySQLとあなたのPHPプログラムの間で忘れたままにしておけば、あなたは本当に事態を悪化させる可能性があります。

mysqliPDOのどちらを使用しているかは明示していません。両方とも、クエリをバッファしないようにするモード設定を提供します。 old-skool mysql_インターフェイスを使用している場合、おそらく運が悪いです。

+0

ありがとう@Ollie Jones。私はPDOを使用しています。あなたの提案は、メモリ使用量を減らしますが、サーバーの負荷を増やすつもりはありませんか? –

+0

あなたが意味するサーバーが不明です。 MySQLサーバを傷つけることはありません。実際には、複数のクエリではなく、1つのクエリしか実行していないため、役立ちます。あなたはあなたの断片を生成するために 'ORDER BY ... LIMIT'節を使う必要はありません。あなたのPHPプログラムを実行しているあなたのWebサーバーは、どちらの方法でも同じレベルの作業を行います。 3分間は、特に商用ホスティングサービスの共有サーバーにある場合は、不合理ではありません。 –

+0

バッファリングされていないクエリを使用している場合、プロセスの終了時までテーブルがロックされているか、別のプロセスが読み書きできるようになりますか? –

1

できるだけ多くの人ができることは、できるだけPHPをミックスの外に出すことです。常にCSVを読み込んだり、エクスポートしたりする場合。

以下では、私は2600万行の学生テーブルを持っています。私はそれの200K行をエクスポートします。与えられた列数は学生テーブルでは小さいです。私は学生のためのキャンパス情報を使って他のことをテストします。しかし、あなたは私が望む考えを得るでしょう。問題はあなたのためにどれくらい時間がかかります:

...そして、レコードがフィルタリングルールを "通過"するかどうかを確認してください。

PHPがないと理論的にdbエンジンを介して発生する可能性があります。 PHPがなければ、マントラでなければなりません。しかし、それはまだ決定されていません。要点は、PHPの処理を式から外すことです。 PHPは多くのことです。 DB処理の適切なパートナーはそうではありません。

select count(*) from students; 
-- 26.2 million 

select * from students limit 1; 
+----+-------+-------+ 
| id | thing | camId | 
+----+-------+-------+ 
| 1 |  1 | 14 | 
+----+-------+-------+ 

drop table if exists xOnesToExport; 
create table xOnesToExport 
( id int not null 
); 
insert xOnesToExport (id) select id from students where id>1000000 limit 200000; 
-- 200K rows, 5.1 seconds 

alter table xOnesToExport ADD PRIMARY KEY(id); 
-- 4.2 seconds 

SELECT s.id,s.thing,s.camId INTO OUTFILE 'outStudents_20160720_0100.txt' 
    FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"' 
    LINES TERMINATED BY '\r\n' 
    FROM students s 
    join xOnesToExport x 
    on x.id=s.id; 
-- 1.1 seconds 

200K行と上記1AMのタイムスタンプファイルが参加を経由してCSVとしてエクスポートされました。それは1秒かかりました。

LOAD DATA INFILEおよびSELECT INTO OUTFILEは、1つのことについては、生のテーブル移動が不十分な速度では打ち勝つことができないコンパニオン機能です。第二に、人々はめったに後者を使用していないようです。ユースケースやテクニックを使ってできることをすべて見ても、柔軟性があります。

Linuxの場合は、LINES TERMINATED BY '\n'を使用してください。私は、上記のコードブロックを使用しているWindowsマシンを使用しています。唯一の違いは、ファイルへのパスと行終端文字です。

関連する問題