2014-05-14 4 views
1

Доброе утро, у меня есть запрос, который вам понадобится, чтобы импортировать 14 миллионов записей, содержащих информацию о клиентах компании.Как оптимизировать импорт данных из плоского файла в BD PostgreSQL?

Плоский файл. Txt весит 2,8 ГБ, я разработал java-программу, которая читает плоский файл по строкам, обрабатывает информацию и помещает ее в объект, который, в свою очередь, вставлен в таблицу в базе данных PostgreSQL, тема заключается в том, что я сделал что 100000 записей вставлены в течение 112 минут, но проблема в том, что я вставляю детали.

public static void main(String[] args) { 

    // PROCESSING 100,000 records in 112 minutes 
  // PROCESSING 1,000,000 records in 770 minutes = 18.66 hours 

    loadData(0L, 0L, 100000L); 
} 

/** 
* Load the number of records Depending on the input parameters. 
* @param counterInitial - Initial counter, type long. 
* @param loadInitial - Initial load, type long. 
* @param loadLimit - Load limit, type long. 
*/ 
private static void loadData(long counterInitial, long loadInitial, long loadLimit){ 
    Session session = HibernateUtil.getSessionFactory().openSession(); 
    try{ 
     FileInputStream fstream = new FileInputStream("C:\\sppadron.txt"); 
     DataInputStream entrada = new DataInputStream(fstream); 
     BufferedReader buffer = new BufferedReader(new InputStreamReader(entrada)); 
     String strLinea; 
     while ((strLinea = buffer.readLine()) != null){ 
      if(counterInitial > loadInitial){ 
       if(counterInitial > loadLimit){ 
        break; 
       } 
       Sppadron spadron= new Sppadron(); 
       spadron.setSpId(counterInitial);     
       spadron.setSpNle(strLinea.substring(0, 9).trim()); 
       spadron.setSpLib(strLinea.substring(9, 16).trim()); 
       spadron.setSpDep(strLinea.substring(16, 19).trim()); 
       spadron.setSpPrv(strLinea.substring(19, 22).trim()); 
       spadron.setSpDst(strLinea.substring(22, 25).trim()); 
       spadron.setSpApp(strLinea.substring(25, 66).trim()); 
       spadron.setSpApm(strLinea.substring(66, 107).trim()); 
       spadron.setSpNom(strLinea.substring(107, 143).trim());     
       String cadenaGriSecDoc = strLinea.substring(143, strLinea.length()).trim();      
       String[] tokensVal = cadenaGriSecDoc.split("\\s+"); 
       if(tokensVal.length == 5){ 
       spadron.setSpNac(tokensVal[0]); 
       spadron.setSpSex(tokensVal[1]); 
       spadron.setSpGri(tokensVal[2]); 
        spadron.setSpSec(tokensVal[3]); 
        spadron.setSpDoc(tokensVal[4]); 
       }else{ 
       spadron.setSpNac(tokensVal[0]); 
       spadron.setSpSex(tokensVal[1]); 
       spadron.setSpGri(tokensVal[2]); 
        spadron.setSpSec(null); 
        spadron.setSpDoc(tokensVal[3]); 
       } 
       try{ 
        session.getTransaction().begin(); 
        session.save(spadron); // Insert 
        session.getTransaction().commit(); 
       } catch (Exception e) { 
        session.getTransaction().rollback(); 
        e.printStackTrace(); 
       } 
      } 
      counterInitial++; 
     } 
     entrada.close(); 
    } catch (Exception e) { 
     e.printStackTrace(); 
    }finally{ 
     session.close(); 
    } 
} 

Основной вопрос, если они проверяют мой код, когда я вставляю первые миллион записей, параметры будут выглядеть следующим образом: loadData (0L, 0L, 1000000L);

Вопрос заключается в том, что при вставке следующих записей в этом случае будет будет следующий миллион записей: loadData (0L, 1000000L, 2000000L); Что вызовет его прокрутку первых 100 миллиардов записей, а затем, когда счетчик в значении 1000001 в последнее время начнет вставлять следующие записи, кто-то может дать мне более оптимальное предложение вставьте записи, зная, что необходимо обрабатывать информацию, как показано в предыдущем показанном коде.

+2

Вы совершаете каждую вставку. Это * будет ужасно медленным. Вы должны только зафиксировать в конце. Или остановите использование Hibernate для этого, он не предназначен для массовой загрузки. Наиболее эффективным решением является использование 'copy' через API' CopyManager'. Или, по крайней мере, использовать простой JDBC и пакетный пакет. –

ответ

0

См. How to speed up insertion performance in PostgreSQL.

Первое, что вам нужно сделать, это обход Hibernate. ORM удобны, но для этого удобства вы платите за скорость, особенно при массовых операциях.

Вы можете группировать свои вставки в транзакции разумного размера и использовать многозначные insert s, используя JDBC PreparedStatement.

Лично, я бы use PgJDBC's support for the COPY protocol, чтобы делать вставки более непосредственно. Разверните объект Hibernate Session, чтобы получить базовые java.sql.Connection, get the PGconnection interface for it, getCopyAPI(), чтобы получить CopyManager и использовать copyIn для подачи ваших данных в БД.

Поскольку ваши данные не в форме CSV, а в форме поля фиксированной ширины, вам нужно будет начать поток, который считывает ваши данные из файла, преобразует каждую дату в форму CSV, подходящую для PostgreSQL и записывает его в буфер, который copyIn может потреблять с принятым Reader. Это звучит более сложно, чем есть, и есть много примеров реализаций Java/Consumer Threading с использованием интерфейсов java.io.Reader и java.io.Writer.

Возможно, вы можете написать фильтр для Reader, который обертывает основной читатель файла и преобразует каждую строку. Это было бы намного проще, чем потоки производителей/потребителей. Сначала исследуйте это как предпочтительный вариант.

Смежные вопросы