2012-05-01 5 views
2

Webフォームを介してデータベースにCSVファイルをロードしています。なぜ私のテーブルにデータを入力するのに時間がかかりますか?

生データの順序は各CSVファイルで一貫していますが、ソースごとにファイルごとに変更されるため、5行を表示するプレビューフォームがあり、ドロップで列を割り当てることができます表の有効な列名のリスト。

次に、cgiフォームを使用してINSERT文を作成し、csvファイルを行単位で解析して表に移入します。

しかし、それは非常に遅いです。私は同時に、961402行(値を持つ7つの列)と1835538​​行(値を持つ1つの列)を持つ2つの表を同時に投入しており、それぞれ少なくとも30分実行しています。私は毎秒100の新しい行のような何かを見ているだけです。

ここで私が遅くなるものは見えますか?

注:私はここにいくつかの醜いコードがあることを知っています、それは私がこの言語を理解しながら書いた最初のpython CGIスクリプトの一つでした。

for item in form: 
      field = form.getvalue(item) 
      field = cgi.escape(field) 
      if field == 'null': 
        pass 
      elif item == 'csvfile': 
        pass 
      elif item == 'campaign': 
        pass 
      elif item == 'numfields': 
        pass 
      else: 
        colname = str(colname) + ", " + str(item) 

        colnum.append(field) 
    assert(numfields > 0) 
    placeholders = (numfields-1) * "%s, " + "%s" 
    query = ("insert into %s (%s)" % (table, colname.lstrip(","))) 
    with open(fname, 'rb') as f: 
      reader = csv.reader(f) 
      try: 
        record = 0 
        errors = 0 
        for row in reader: 
          try: 
            record = record + 1 
            data = '' 
            for value in colnum: 
              col = int(value) 
              rawrow = row[col] 
              saferow = rawrow.replace("'", "-") 
              saferow = saferow.replace("-", "") 
              data = str(data) + ", '" + saferow + "'" 
            dataset = data.lstrip(',') 
            insert = query + (" values (%s)" % dataset) 
            cur.execute(insert) 
            con.commit() 
            print ".", 
          except IndexError, e: 
            print "Row:%d file %s, %s<br>" % (reader.line_num, fname.lstrip("./files/"), e) 
            errors = errors + 1 
          except csv.Error, e: 
            print "Row:%s file %s, line %d: %s<br>" % (record, fname, reader.line_num, e) 
            errors = errors + 1 
          except mdb.Error, e: 
            print "Row:%s Error %d: %s<br>" % (record, e.args[0], e.args[1]) 
            errors = errors + 1 
          except: 
            t,v,tb = sys.exc_info() 
            print "Row:%s %s<br>" % (record, v) 
            errors = errors + 1 
      except csv.Error, e: 
        print "except executed<br>" 
        sys.exit('file %s, line %d: %s' % (fname, reader.line_num, e)) 
    print "Succesfully loaded %s into Campaign %s, <br>" % (fname.lstrip("./files/"), table) 
    print record - errors, "new records.<br>" 
    print errors, "errors.<br>" 

EDIT/UPDATE:LOAD DATA LOCAL INFILEを使用するには、魔法のように働いていた、私は分未満で600Kレコードをロード。

新しいコードもクリーナーです。

else: 
      colnum.append([field, item]) 
sortlist = sorted(colnum, key=itemgetter(0)) 
cols = '' 
for colname in sortlist: 
    cols = cols + "%s, " % colname[1] 
cur.execute("LOAD DATA LOCAL INFILE '%s' IGNORE INTO TABLE %s FIELDS TERMINATED BY ',' LINES TERMINATED BY '\n' (%s)" % (fname, table, cols.rstrip(', '))) 
con.commit() 

唯一の難点は、そうでない場合は、魔法のように動作し、私はデータの整合性を確保するために、私のCSVファイルを準備するsmidgeより多くの仕事をしなければならないということです。

+0

行番号を削除してください - 作業が難しくなります。 –

+0

大きなテーブルにINSERT INTO sqlクエリを実行するとかなり遅くなることがあります。 INSERT INTOでいっぱいになったファイルを作成し、手動でSQLクライアントを実行して、私の意図を確認してください。 – Paul

+0

それは私が思っていることです、@ポール、しかしこれは遅いですか? 2つの間に200レコードがクロールしているようです。それをスピードアップする方法はありますか?列はすべてCHARデータ型です。 – TaoJoannes

答えて

4

一度に1行で済むINSERT INTOは、mySQLのような一部のSQLが単一の挿入コマンドで複数の行を持つか、CSVファイルをすぐにサーバーに読み込むことができるLOAD DATA文をサポートしている。

も参照してください:https://dba.stackexchange.com/questions/16809/why-is-load-data-infile-faster-than-normal-insert-statements

+0

上記のコメントの後、私はmysqlimportを調べ始めました。私は現在のように列名を作成して、一度にcsvファイルをインポートすることができると考えています。 – TaoJoannes

1

いくつかの簡単な擬似コード。このください:

for row in data_to_be_inserted: 
    stmt = compose_statement("lalala") 
    cursor.execute() 

connection.commit() 

ない

for row in data_to_be_inserted: 
    stmt = compose_statement("lalala") 
    cursor.execute() 
    connection.commit() 

あなたのコードは、(コミット)は、一度入力の行あたりです。それは大幅に遅くなります。

+0

私は、処理時間のために、ページを提供するのにあまりにも長い時間がかかってしまったという問題を抱えていました。 – TaoJoannes

関連する問題