Какой самый эффективный способ вставить тысячи записей в таблицу (MySQL, Python, Django) - PullRequest
11 голосов
/ 12 мая 2009

У меня есть таблица базы данных с уникальным строковым полем и парой целочисленных полей. Строковое поле обычно длиной 10-100 символов.

Раз в минуту или около того у меня следующий сценарий: я получаю список из 2-10 тысяч кортежей, соответствующих структуре записей таблицы, например,

[("hello", 3, 4), ("cat", 5, 3), ...]

Мне нужно вставить все эти кортежи в таблицу (предположим, я проверил, что ни одна из этих строк не появилась в базе данных). Для пояснения, я использую InnoDB, и у меня есть автоинкрементный первичный ключ для этой таблицы, строка не PK.

Мой код в настоящее время выполняет итерацию по этому списку, для каждого кортежа создается объект модуля Python с соответствующими значениями и вызывается ".save ()", что-то вроде этого:

@transaction.commit_on_success
def save_data_elements(input_list):
    for (s, i1, i2) in input_list:
        entry = DataElement(string=s, number1=i1, number2=i2)
        entry.save()

Этот код в настоящее время является одним из узких мест производительности в моей системе, поэтому я ищу способы его оптимизации.

Например, я могу сгенерировать коды SQL, каждый из которых содержит команду INSERT для 100 кортежей («жестко запрограммированных» в SQL), и выполнить ее, но я не знаю, улучшит ли это что-нибудь.

Есть ли у вас предложения по оптимизации такого процесса?

Спасибо

Ответы [ 8 ]

12 голосов
/ 12 мая 2009

В частности, для MySQL самый быстрый способ загрузки данных - это LOAD DATA INFILE , поэтому, если вы сможете преобразовать данные в ожидаемый формат, это, вероятно, будет самый быстрый способ получить их в стол.

11 голосов
/ 12 мая 2009

Вы можете записать строки в файл в формате "field1", "field2", .. и затем использовать LOAD DATA для загрузки их

data = '\n'.join(','.join('"%s"' % field for field in row) for row in data)
f= open('data.txt', 'w')
f.write(data)
f.close()

Затем выполните это:

LOAD DATA INFILE 'data.txt' INTO TABLE db2.my_table;

Ссылка

4 голосов
/ 12 мая 2009

Если вы можете сделать ручное заявление INSERT, то я бы так и сделал. Один оператор INSERT с несколькими предложениями значений намного быстрее, чем множество отдельных операторов INSERT.

4 голосов
/ 12 мая 2009

Если вы не LOAD DATA INFILE, как упоминают некоторые другие предложения, вы можете сделать две вещи, чтобы ускорить вставку:

  1. Использовать подготовленные операторы - это сокращает накладные расходы на синтаксический анализ SQL для каждой вставки
  2. Выполните все ваши вставки в одной транзакции - для этого потребуется использовать механизм БД, поддерживающий транзакции (например, InnoDB)
2 голосов
/ 12 мая 2009

Независимо от метода вставки, вы захотите использовать механизм InnoDB для максимального параллелизма чтения / записи. MyISAM блокирует всю таблицу на время вставки, тогда как InnoDB (в большинстве случаев) блокирует только затронутые строки, позволяя инструкциям SELECT продолжаться.

1 голос
/ 12 мая 2009

Я не знаю точных деталей, но вы можете использовать представление данных в стиле json и использовать его как фиксаторы или что-то в этом роде. Я видел нечто похожее на Django Video Workshop Дугласа Наполеоне. Смотрите видео по адресу http://www.linux -magazine.com / online / news / django_video_workshop . и http://www.linux -magazine.com / online / features / django_reloaded_workshop_part_1 . Надеюсь, это поможет.

Надеюсь, ты справишься. Я только начал изучать джанго, поэтому я могу просто указать вам ресурсы.

1 голос
/ 12 мая 2009

Это не связано с фактической загрузкой данных в БД, но ...

Если вы предоставляете пользователю тип сообщения «Данные загружаются ... Загрузка будет выполнена в ближайшее время», вы можете асинхронно запускать INSERT или LOAD DATA в другом потоке.

Просто что-то еще, чтобы рассмотреть.

1 голос
/ 12 мая 2009

в каком формате вы получаете? если это файл, вы можете выполнить некоторую массовую загрузку: http://www.classes.cs.uchicago.edu/archive/2005/fall/23500-1/mysql-load.html

...