2

Web フォームを介して csv ファイルをデータベースにロードしています。

生データの順序は各csvファイルで一貫していますが、ソースに応じてファイルごとに変化するため、5行を表示し、ドロップダウンリストから列を割り当てることができるプレビューフォームがありますテーブル内の有効な列名。

次に、cgi フォームを使用して INSERT ステートメントを作成し、csv ファイルを 1 行ずつ解析してテーブルに入力します。

しかし、実行速度が非常に遅いです。1 つは 961402 行 (7 列に値)、もう 1 つは 1835538​​ 行 (1 列に値) の 2 つのテーブルに同時にデータを入力しており、それぞれが少なくとも 30 分間実行されています。1 秒あたり 100 行しか表示されません。

私を遅くする何かがここに見えますか?

注: ここに醜いコードがあることは知っています。これは、この言語を理解しているときに最初に書いた Python CGI スクリプトの 1 つです。

 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>"

編集/更新: 魔法LOAD DATA LOCAL INFILEのように機能し、1 分もかからずに 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 ファイルを準備するためにもう少し作業を行う必要があることです。そうしないと、魅力のように機能します。

4

2 に答える 2

4

一度に1行ずつ実行されるINSERTINTOは、mySQLなどの一部のSQLが、単一の挿入コマンドで多数の行をサポートするか、CSVファイルをサーバーにすばやく読み込むことができるLOADDATAステートメントをサポートすることを考えるとかなり遅いです。

参照: https ://dba.stackexchange.com/questions/16809/why-is-load-data-infile-faster-than-normal-insert-statements

于 2012-05-01T18:39:20.793 に答える
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()

あなたのコードは、入力行ごとに commit() を 1 回実行します。それはそれを大幅に遅くします。

于 2012-05-01T18:46:46.207 に答える