Как эффективно вставить данные из файла CSV в MYSQL, используя Python? - PullRequest
2 голосов
/ 17 июня 2019

У меня есть входной файл CSV с aprox. 4 миллиона записей. Вставка работает с + 2 часа и до сих пор не закончена. База данных все еще пуста.

Любые предложения о том, как на самом деле вставить значения (используя insert into) и быстрее, например, разбить вставку на куски?

Я довольно новичок в питоне.

  • Пример CSV-файла
43293,cancelled,1,0.0,
1049007,cancelled,1,0.0,
438255,live,1,0.0,classA
1007255,xpto,1,0.0,
  • скрипт Python
def csv_to_DB(xing_csv_input, db_opts):
    print("Inserting csv file {} to database {}".format(xing_csv_input, db_opts['host']))
    conn = pymysql.connect(**db_opts)
    cur = conn.cursor()
    try:
        with open(xing_csv_input, newline='') as csvfile:
            csv_data = csv.reader(csvfile, delimiter=',', quotechar='"')
            for row in csv_data:
                insert_str = "INSERT INTO table_x (ID, desc, desc_version, val, class) VALUES (%s, %s, %s, %s, %s)"
                cur.execute(insert_str, row)
        conn.commit()
    finally:
        conn.close()

UPDATE: Спасибо за все вклады. Как и предполагалось, я попытался счетчик для вставки в пакетах по 100 и меньший набор данных CSV (1000 строк). Проблема в том, что вставлено только 100 записей, хотя счетчик проходит 10 x 100 несколько раз.

изменение кода:

def csv_to_DB(xing_csv_input, db_opts):
   print("Inserting csv file {} to database {}".format(xing_csv_input, db_opts['host']))
   conn = pymysql.connect(**db_opts)
   cur = conn.cursor()
   count = 0
   try:
       with open(xing_csv_input, newline='') as csvfile:
           csv_data = csv.reader(csvfile, delimiter=',', quotechar='"')
           for row in csv_data:
               count += 1
               print(count)
               insert_str = "INSERT INTO table_x (ID, desc, desc_version, val, class) VALUES (%s, %s, %s, %s, %s)"

               if count >= 100:
                  cur.execute(insert_str, row)
                  print("count100")
                  conn.commit()
                  count = 0

               if not row:
                  cur.execute(insert_str, row)
                  conn.commit()
   finally:
       conn.close()

Ответы [ 2 ]

2 голосов
/ 17 июня 2019

Есть много способов оптимизировать эту вставку.Вот несколько идей:

  1. У вас есть цикл for для всего набора данных.Вы можете сделать commit() каждые 100 или около того
  2. Вы можете вставить много строк в одну вставку
  3. Вы можете объединить две строки и сделать многострочную вставку каждый100 строк на вашем CSV
  4. Если python не является обязательным требованием, вы можете сделать это напрямую, используя MySQL, как объяснено здесь .(Если вам нужно сделать это с помощью python, вы все равно можете подготовить этот оператор на python и избежать ручного обхода файла).

Примеры:

для номера 2 в списке,код будет иметь следующую структуру:

def csv_to_DB(xing_csv_input, db_opts):
    print("Inserting csv file {} to database {}".format(xing_csv_input, db_opts['host']))
    conn = pymysql.connect(**db_opts)
    cur = conn.cursor()
    try:
        with open(xing_csv_input, newline='') as csvfile:
            csv_data = csv.reader(csvfile, delimiter=',', quotechar='"')
            to_insert = []
            insert_str = "INSERT INTO table_x (ID, desc, desc_version, val, class) VALUES "
            template = '(%s, %s, %s, %s, %s)'
            count = 0
            for row in csv_data:
                count += 1
                to_insert.append(tuple(row))
                if count % 100 == 0:
                    query = insert_str + '\n'.join([template % r for r in to_insert])
                    cur.execute(query)
                    to_insert = []
                    conn.commit()
            query = insert_str + '\n'.join(template % to_insert)
            cur.execute(query)
            conn.commit()
    finally:
        conn.close()
0 голосов
/ 17 июня 2019

Здесь. Попробуйте этот фрагмент и дайте мне знать, если он работал, используя executemany().

with open(xing_csv_input, newline='') as csvfile:
    csv_data = tuple(csv.reader(csvfile, delimiter=',', quotechar='"'))
    csv_data = (row for row in csv_data)
    query = "INSERT INTO table_x (ID, desc, desc_version, val, class) VALUES (%s, %s, %s, %s, %s)"
    try:
        cur.executemany(query, csv_data)
        conn.commit()
    except:
        conn.rollback()
...