Ускорить обработку массива и базы данных

Есть большой файл с данными радаров. Формат каждой строки такой

0,47.323057,42.214830,1,60,1,7

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

while ((line = reader.readLine()) != null) {
   try {
        _count_2++;
        line_array = line.split(",");
        contentValues.put(SpeedCamBase.IDX, line_array[0]);
        contentValues.put(SpeedCamBase.Longitude, line_array[1]);
        contentValues.put(SpeedCamBase.Latitude, line_array[2]);
        contentValues.put(SpeedCamBase.Type, line_array[3]);
        contentValues.put(SpeedCamBase.Speed, line_array[4]);
        contentValues.put(SpeedCamBase.Dir_type, line_array[5]);
        contentValues.put(SpeedCamBase.Direction, line_array[6]);
        database_speedcam.insert(SpeedCamBase.TABLE_SETTING, null, contentValues);
   } catch (OutOfMemoryError e) {
   }
}

Таких строк может быть до 200000. И обработка занимает долгое время. Как можно ускорить обработку данных?

Если использовать потоки, то как сделать синхронизацию?


Ответы (2 шт):

Автор решения: Alex Rudenko

Если используется mySQL, то вместо построчного чтения и обработки файла данных можно отправить LOAD DATA запрос при условии, что этот файл находится на машине, где запущен сервер БД:

Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/myDB", "root", "pswd");
String dataFilename = "C:\tmp\speedcam_data.csv";
Statement stmt = conn.createStatement();
String sql = "LOAD DATA INFILE '" + dataFilename + "' \n"
           + "   REPLACE \n" // заменить данные
           + "   INTO TABLE speedcam \n" 
           + "   COLUMNS TERMINATED by ',' \n" 
 //        + "   IGNORE 1 LINES" // если файл содержит строку-заголовок, раскомментировать
;
stmt.execute(sql);

Если оператор LOAD DATA не поддерживается, то можно применить PreparedStatement c обработкой пакетов (batch), при этом следует отключить авто-коммит conn.setAutoCommit(false);

Также для mySQL есть дополнительная опция ?rewriteBatchedStatements=true, которую можно добавить в строку соединения с БД.

private static final String INSERT_SQL = "INSERT INTO speedcam "
    + "(idx, longitude, latitude, `type`, speed, dir_type, direction) "
    + "VALUES (?, ?, ?, ?, ?, ?, ?)";
private static final int BATCH_SIZE = 50;

public void loadData(String dataFilename) throws IOException, SQLException {
    try (
        Connection conn = DriverManager.getConnection(
           "jdbc:mysql://localhost:3306/myDB?rewriteBatchedStatements=true", 
           "root", "pswd"
        );
        PreparedStatement stmt = conn.prepareStatement(INSERT_SQL);
        BufferedReader br = new BufferedReader(new FileReader(dataFilename));
    ) {
        String line;
        int count = 0;
        boolean autoCommit = conn.getAutoCommit();
        if (autoCommit) {
            conn.setAutoCommit(false);
        }

        // 0,47.323057,42.214830,1,60,1,7
        while ((line = br.readLine()) != null) {
            String[] cols = line.split(",");
            stmt.setInteger(1, Integer.parseInt(cols[0]));    // id
            stmt.setDouble (2, Double.parseDouble(cols[1]));  // lat
            stmt.setDouble (3, Double.parseDouble(cols[2]));  // lng
            stmt.setInteger(4, Integer.parseInt(cols[3]));    // type
            stmt.setInteger(5, Integer.parseInt(cols[4]));    // speed
            stmt.setInteger(6, Integer.parseInt(cols[5]));    // dir_type
            stmt.setInteger(7, Integer.parseInt(cols[6]));    // direction
            
            stmt.addBatch();
            count++;
            
            if (count == BATCH_SIZE) {
                stmt.executeBatch();
                count = 0;
            }
        }
        if (count > 0) {
            stmt.executeBatch();
        }
        conn.commit();

        if (autoCommit) {
            // восстановить авто-коммит
            conn.setAutoCommit(true);
        }
    }
}
→ Ссылка
Автор решения: Arty Morris

база MySQL Проблема решена, скорость обработки увеличилась раз в 10.

dbSpeedCam = new SpeedCamBase(mContext);
database_speedcam = dbSpeedCam.getWritableDatabase();
contentValues = new ContentValues();
database_speedcam.beginTransaction(); <-- пишем эту строчку
/// 
while ((line = reader.readLine()) != null) {
try {
    _count_2++;
    line_array = line.split(",");
    contentValues.put(SpeedCamBase.KEY_ID, _count_2);
    contentValues.put(SpeedCamBase.IDX, line_array[0]);
    contentValues.put(SpeedCamBase.Longitude, line_array[1]);
    contentValues.put(SpeedCamBase.Latitude, line_array[2]);
    contentValues.put(SpeedCamBase.Type, line_array[3]);
    contentValues.put(SpeedCamBase.Speed, line_array[4]);
    contentValues.put(SpeedCamBase.Dir_type, line_array[5]);
    contentValues.put(SpeedCamBase.Direction, line_array[6]);
    database_speedcam.insert(SpeedCamBase.TABLE_SETTING, null, contentValues);
} catch (OutOfMemoryError e) {
 }
}
///
database_speedcam.setTransactionSuccessful(); <-- пишем эту строчку
database_speedcam.endTransaction(); <-- пишем эту строчку
→ Ссылка