MySQL Inserting большие наборы данных из файла с Java

Мне все равно, насколько мощным является язык программирования, если его синтаксис не интуитивен, и я не могу отложить его на некоторое время и вернуться к нему без особых усилий, чтобы обновить детали. Я бы предпочел, чтобы сам язык был интуитивно понятным, чем загадочным, но мощным для создания DSL. Компьютерный язык - это пользовательский интерфейс для ME, и я хочу, чтобы он был разработан для интуитивно понятной простоты использования, как и любой другой пользовательский интерфейс.

6
задан Derek Organ 30 June 2009 в 22:22
поделиться

12 ответов

Советы по быстрой вставке:

  • Используйте синтаксис LOAD DATA INFILE , чтобы MySQL проанализировал его и вставил, даже если вам придется его искажать и загружать после манипуляции.
  • Используйте этот синтаксис вставки:

    вставить в таблицу (col1, col2) значения (val1, val2), (val3, val4), ...

  • Удалить все ключи / индексы перед вставкой.

  • Сделайте это на самой быстрой машине, которая у вас есть (в основном с точки зрения ввода-вывода, но ОЗУ и ЦП также имеют значение). И сервер БД, и клиент вставки, помните, что вы будете платить вдвое больше стоимости ввода-вывода (одно чтение, второе вставка)
14
ответ дан 8 December 2019 в 04:31
поделиться

Вы ОБЯЗАТЕЛЬНО отключили автоматические фиксации в драйвере JDBC?

Это типичный убийца производительности для клиентов JDBC.

2
ответ дан 8 December 2019 в 04:31
поделиться

Я бы, вероятно, выбрал большое количество, например, 10 тыс. Строк, и загрузил такое количество строк из CSV, обработал данные и выполнил пакетное обновление, а затем повторил бы, пока вы не пройдете через весь csv. В зависимости от обработки / количества данных 1,8 млн строк не должны занимать 10 часов, скорее 1-2 часа, в зависимости от вашего оборудования.

edit: упс, упущена довольно важная часть, у вашего мошенника должна быть установлена ​​автоматическая фиксация значение false, код, из которого я скопировал это, делал это как часть метода GetConnection ().

    Connection con = GetConnection();
con.setAutoCommit(false);
            try{
                PreparedStatement ps = con.prepareStatement("INSERT INTO table(col1, col2) VALUES(?, ?)");
                try{
                    for(Data d : massagedData){
                        ps.setString(1, d.whatever());
                                        ps.setString(2, d.whatever2());
                                            ps.addBatch();
                    }
                    ps.executeBatch();
                }finally{
                    ps.close();
                }
            }finally{
                con.close();
            }
4
ответ дан 8 December 2019 в 04:31
поделиться

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

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

Если вам нужно манипулировать данными, я все равно рекомендую манипулировать в памяти , переписывая его в плоский файл и отправляя его в базу данных с помощью LOAD DATA, я думаю, это должно быть более эффективным.

1
ответ дан 8 December 2019 в 04:31
поделиться

В зависимости от того, что именно вам нужно сделать с данными перед их вставкой, ваши лучшие варианты с точки зрения скорости:

  • Разберите файл в java / сделайте то, что вам нужно с данными / запишите «обработанные» данные в новый файл CSV / используйте для этого «загрузить данные в файл».
  • Если ваши манипуляции с данными являются условными (например, вам нужно проверить наличие записи и сделать разные вещи в зависимости от того, является ли это вставкой или обновлением и т.д.), тогда (1) может быть невозможно. В таком случае лучше всего выполнять пакетную вставку / обновление.
    Поэкспериментируйте, чтобы найти наиболее подходящий для вас размер партии (можно начать с 500–1000). В зависимости от механизма хранения, который вы используете для своей таблицы, вам может потребоваться разделить это на несколько транзакций - наличие одной строки размером 1,8 млн не творит чудеса с производительностью.
  • 1
    ответ дан 8 December 2019 в 04:31
    поделиться

    Другая идея: используете ли вы PreparedStatement для вставки данных с помощью JDBC?

    1
    ответ дан 8 December 2019 в 04:31
    поделиться

    Самая большая проблема с производительностью, скорее всего, связана не с java, а с mysql, в частности с любыми индексами, ограничениями и внешними ключами в таблице, в которую вы вставляете. Прежде чем приступить к вставкам, убедитесь, что вы их отключили. Повторное включение их в конце займет значительное время, но это намного эффективнее, чем оценка их базой данных после каждого оператора.

    Вы также можете столкнуться с проблемами производительности mysql из-за размера вашей транзакции. Ваш журнал транзакций станет очень большим с таким количеством вставок, поэтому выполнение фиксации после X вставок (скажем, 10 000–100 000) также поможет ускорить вставку.

    На уровне jdbc убедитесь, что вы используете addBatch ( ) и executeBatch () в вашем PreparedStatement, а не в обычном executeUpdate ().

    1
    ответ дан 8 December 2019 в 04:31
    поделиться

    Разве не было бы быстрее, если бы вы использовали LOAD DATA INFILE вместо вставки каждой строки?

    0
    ответ дан 8 December 2019 в 04:31
    поделиться

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

    Если ваша таблица имеет индексы, обычно быстрее их отбросить, а затем добавить обратно после импорта.

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

    Но в целом,

    0
    ответ дан 8 December 2019 в 04:31
    поделиться

    Я бы запустил три потока ...

    1) Читает входной файл и помещает каждую строку в очередь преобразования 2) Извлекает из очереди, преобразует данные и помещает в очередь БД 3) Извлекает из очереди db и вставляет данные

    Таким образом, вы можете читать данные с диска, пока потоки db ждут завершения своего ввода-вывода, и наоборот

    0
    ответ дан 8 December 2019 в 04:31
    поделиться

    Это интересное чтение: http://dev.mysql.com/doc/refman/5.1/en/insert-speed.html

    0
    ответ дан 8 December 2019 в 04:31
    поделиться

    Вы можете улучшить производительность групповой INSERT из MySQL / Java, используя возможность пакетной обработки в его JDBC-драйвере Connector J.

    MySQL «неправильно» обрабатывает пакеты (см. Ссылку на мою статью внизу), но он может переписывать INSERT, чтобы использовать необычный синтаксис MySQL, например вы можете указать драйверу переписать два INSERT:

    INSERT INTO (val1, val2) VALUES ('val1', 'val2'); 
    INSERT INTO (val1, val2) VALUES ('val3', 'val4');
    

    как один оператор:

    INSERT INTO (val1, val2) VALUES ('val1', 'val2'), ('val3','val4'); 
    

    (Обратите внимание, что я не говорю , что вам нужно переписать свой SQL таким образом; драйвер делает это, когда может)

    Мы сделали это для собственного исследования объемных вставок: разница была на порядок. Используется с явными транзакциями, как упоминалось другими, и в целом вы увидите большое улучшение.

    Соответствующее значение свойства драйвера:

    jdbc:mysql:///<dbname>?rewriteBatchedStatements=true
    

    См .: Десятикратное увеличение производительности для пакетных вставок с MySQL Connector / J уже в пути

    1
    ответ дан 8 December 2019 в 04:31
    поделиться
    Другие вопросы по тегам:

    Похожие вопросы: