зачем тратить слишком много времени на вставку строк в таблицу mysql даже после использования многопоточности, когда таблица имеет некоторые отношения - PullRequest
1 голос
/ 14 января 2011

Я хотел вставить 200000 строк в таблицу через соединение JDBC mysql. В моей таблице три столбца DISTRICT1 (Id, Name, country). Я использовал multi-потоки для выполнения операции вставки, и он вставил данные менее чем за 1 минуту. Затем я снова попытался выполнить аналогичную операцию с таблицей DISTRICT2 (Id, Name, country), в данном случае это занимает очень очень долгое время (более 2 часов) для вставки строк (как это происходит с однопоточным). Единственное отличие между таблицами буксировки состоит в том, что в таблице DISTRICT2 есть поле Id , который связан с другими таблицами через отношение внешнего ключа , в то время как DISTRICT1 таблица не имеет такой связи. Также другое отличие состоит в движке mysql, DISTRICT1имеет ENGINE = MyISAM, в то время как ENGINE = INNODB для DISTRICT2 Также он дал java.lang.OutOfMemoryError, когда я использовал PreparedStatement вместо Statement . Имеет ли он какое-то отношение к соединятьпул ионов ?

Пожалуйста, скажите почему это занимает так много времени , когда таблица имеет некоторое отношение? Я использовал один и тот же программный код, чтобы вставить обе таблицы. Я использовал следующий код, чтобы сделатьитак:

public static void main(String[] args) {
  ExecutorService executor = Executors.newFixedThreadPool(10);
  for (int i = 1; i <200001; i=i+10000) {
      Runnable worker = new MyRunnable4District(i);
          executor.execute(worker);
      }
  executor.shutdown();
 }

класс MyRunnable4District показан ниже

public class MyRunnable4District implements Runnable {
 public int size;

 public MyRunnable4District(int n) {
  this.size = n;
 }

 public void run() {
  Connection con = null;
  try {

   Class.forName("com.mysql.jdbc.Driver");
   con = DriverManager.getConnection("jdbc:mysql://localhost/project",
     "root", "root");

   String[] countries = { "ARGENTINA", "US", "UK", "INDIA", "UKRAINE",
     "CHINA" };

   for (int id = size; id < size + 10001; id++) {
    int districtId = id;
    String districtName ="columbia"+id;
    String districtCountry = countries[id % 6];
    String query="INSERT INTO district "+"VALUES ("+districtId+",'"+districtName+"','"+districtCountry+"')";
    //PreparedStatement stmnt =con.prepareStatement(query);
    Statement stmnt =con.createStatement();
    stmnt.executeUpdate(query);
   }

  } catch (ClassNotFoundException e) {
   System.out.println(e.getMessage());
  } catch (SQLException e) {
   System.out.println(e.getMessage());
  } finally {
   try {
    con.close();
    System.out.println("thread number with size "+size+" completed");
   } catch (SQLException e) {
    e.printStackTrace();
   }

  }

 }
}

Ответы [ 2 ]

0 голосов
/ 22 января 2011

Вы должны попробовать многозначные вставки.Например:

INSERT INTO district VALUES (id1,name1,country1),(id2,name2,country2),(id3,name3,country3);

Это может значительно повысить производительность, особенно если вам необходимо это сделать при подключении к удаленному серверу.Помимо уменьшения количества сетевых обращений (или даже вызовов вне процесса на локальном компьютере), сервер должен будет обрабатывать меньше запросов.Кроме того, если оставить автоматическую фиксацию для InnoDB, теперь у вас будет одна транзакция на пакет вместо одной на оператор.

Драйвер JDBC Connector / J сделает это за вас, если для параметра rewriteBatchedStatements задано значение true.Я думаю, что эта функция была добавлена ​​в выпуске драйверов 3.1.x для простых INSERT, таких как ваша.В более поздних версиях rewriteBatchedStatements был улучшен для поддержки более сложных операторов.Найдите на этой странице rewriteBatchedStatements.

Или вы можете переписать свой код, чтобы вручную создать операторы вставки с несколькими значениями.Стоит обратить внимание на максимальный размер пакета.Вы должны убедиться, что оператор вставки остается ниже этого.Итак, либо сделайте max_allowed_packet очень большим при импорте данных, либо разбейте свои партии, когда они приблизятся к max_allowed_packet.

0 голосов
/ 14 января 2011

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

Однако было бы гораздо лучше использовать PreparedStatement и повторно использовать его с другими параметрами.

Кроме того, вы можете рассмотреть возможность использования НАГРУЗКА ДАННЫХ INFILE .

...