Java - многопоточность для повышения производительности при вставке данных в db

Я создаю индексную таблицу (инвертированный файл) для таблицы в MYSQL. Это работает так: он извлекает все слова из файла и сохраняет их в хэш-наборе, а затем вставляет слова одно за другим в мою таблицу базы данных.

Он работает отлично, и я знаю, что для создания индексной таблицы перевернутому файлу требуется некоторое время. Я пытаюсь оптимизировать время индексации таблицы и рассматриваю возможность использования многопоточности. Ускорит ли это производительность?

Однако я не слишком уверен, как интегрировать его с моей текущей программой, поскольку я новичок в многопоточности.

Код:

public static void main(String[] args) throws Exception {

        StopWatch stopwatch = new StopWatch();
        stopwatch.start();



        File folder = new File("D:\\PDF1");
        File[] listOfFiles = folder.listFiles();

        for (File file : listOfFiles) {
            if (file.isFile()) {
                HashSet<String> uniqueWords = new HashSet<>();
                String path = "D:\\PDF1\\" + file.getName();
                try (PDDocument document = PDDocument.load(new File(path))) {

                    if (!document.isEncrypted()) {

                        PDFTextStripper tStripper = new PDFTextStripper();
                        String pdfFileInText = tStripper.getText(document);
                        String lines[] = pdfFileInText.split("\\r?\\n");
                        for (String line : lines) {
                            String[] words = line.split(" ");

                            for (String word : words) {
                                uniqueWords.add(word)
                                ;

                            }

                        }
                        // System.out.println(uniqueWords);

                    }
                } catch (IOException e) {
                    System.err.println("Exception while trying to read pdf document - " + e);
                }
                Object[] words = uniqueWords.toArray();



                MysqlAccessIndex connection = new MysqlAccessIndex();

                for(int i = 1 ; i <= words.length - 1 ; i++ ) {

                    connection.readDataBase(path, words[i].toString());

                }

                System.out.println("Completed");

            }
        }

Подключение к MySQL:

public class MysqlAccessIndex {
    public Connection connect = null;
    public Statement statement = null;
    public PreparedStatement preparedStatement = null;
    public ResultSet resultSet = null;

    public void connect() throws Exception {
        // This will load the MySQL driver, each DB has its own driver
        Class.forName("com.mysql.jdbc.Driver");
        // Setup the connection with the DB
        connect = DriverManager
                .getConnection("jdbc:mysql://126.32.3.20/fulltext_ltat?"
                        + "user=root&password=root");

        // Statements allow to issue SQL queries to the database
        statement = connect.createStatement();
        System.out.print("Connected");

    }
    public MysqlAccessIndex() throws Exception {

        connect();
    }


    public void readDataBase(String path,String word) throws Exception {
        try {

            // Result set get the result of the SQL query


            // This will load the MySQL driver, each DB has its own driver
            Class.forName("com.mysql.jdbc.Driver");
            // Setup the connection with the DB
            connect = DriverManager
                    .getConnection("jdbc:mysql://126.32.3.20/fulltext_ltat?"
                            + "user=root&password=root");

            // Statements allow to issue SQL queries to the database
            statement = connect.createStatement();
            System.out.print("Connected");
            // Result set get the result of the SQL query

            preparedStatement = connect
                    .prepareStatement("insert IGNORE into  fulltext_ltat.indextable values (default,?, ?) ");

            preparedStatement.setString(  1, path);
            preparedStatement.setString(2, word);
            preparedStatement.executeUpdate();
            // resultSet = statement
            //.executeQuery("select * from fulltext_ltat.index_detail");



            //  writeResultSet(resultSet);
        } catch (Exception e) {
            throw e;
        } finally {
            close();
        }

    }

Буду признателен за любые указатели.

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

Tim Biegeleisen 26.10.2018 04:49

@TimBiegeleisen Не разбиваясь на более мелкие части, поможет ли создание нескольких потоков для запуска моего основного метода?

Daredevil 26.10.2018 04:51

Будет ли это Работа или помощь? Не тот же вопрос.

Tim Biegeleisen 26.10.2018 04:52

В вашем коде readDataBase, который находится внутри цикла, вы подключаетесь каждый раз - это будет невероятно медленно, - рассмотрите возможность использования DBCP.

Scary Wombat 26.10.2018 04:55

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

sorifiend 26.10.2018 04:56

@ScaryWombat Значит, DBCP будет лучшим вариантом по сравнению с многопоточностью?

Daredevil 26.10.2018 05:07

Я бы использовал DBCP в добавление для предложений в ответе @zwitserloot, особенно использование транзакций и фиксацию после 100 строк, начните с этого, и я думаю, что вам, возможно, больше ничего не нужно.

Scary Wombat 26.10.2018 05:32
0
7
572
1

Ответы 1

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

Вместо этого попробуйте следующее:

[1] при массовом добавлении данных используйте примитивы массового добавления данных, которые предлагает ваш механизм БД. Я понятия не имею, поддерживает ли это mysql и как это сделать из java. В postgres, например, вы должны использовать COPY вместо INSERT.

[2] особенно если вы не можете использовать COPY или подобное, отключите все индексы (удалите их), затем сделайте все свои вставки, затем добавьте индексы, это быстрее, чем сначала создавать индексы, а затем вставлять.

[3] Используйте транзакции и фиксируйте транзакцию каждые ~ 100 вставок или около того. Это быстрее, чем фиксация после каждой вставки, а также в большинстве случаев быстрее, чем фиксация после сотен тысяч.

[4] начать раньше. В вашем примере кода вы можете сразу начать вставку вместо того, чтобы сначала вставлять все данные в хэш-набор, а затем добавлять их позже.

[5] не делайте заранее подготовленных заявлений; повторно использовать тот же самый.

[6] вы делаете заявление дважды и ничего не делаете с ним. Не надо; вы тратите ресурсы.

[7] подготовленные заявления должны быть закрыты. Вы их не закрываете. Это, вероятно, значительно замедлит процесс. Не делайте так много (достаточно одного) и закрывайте их, когда закончите. Найдите «ARM», это java-конструкция, которая упрощает правильное закрытие ресурсов. Ему уже больше 10 лет.

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

Daredevil 26.10.2018 05:14

Не могли бы вы пояснить пункт 5? Я не понимаю, где я повторно использовал подготовленное заявление. 4: Я использовал hashset, потому что я хочу хранить в нем уникальные слова, а hashset не позволяет дублировать, поэтому, когда я вставляю в базу данных, повторяющихся слов не бывает.

Daredevil 26.10.2018 05:18

@Daredevil Вы НЕ повторно используете свое подготовленное заявление. Тебе следует начать это делать.

rzwitserloot 26.10.2018 05:22

Как мне использовать его повторно?

Daredevil 26.10.2018 05:23

@Daredevil, вы можете снова вызвать .setString (1, path) на нем (так что сделайте подготовленное заявление вне цикла) и продолжайте вызывать .executeUpdate () на нем.

rzwitserloot 26.10.2018 05:25

Но если я вынесу .setString за пределы цикла, таблица не обновится, куда вы хотите поместить его в таком случае?

Daredevil 26.10.2018 05:29

ARM в качестве поискового запроса высоко вряд ли вернет что-нибудь полезное. Попробуйте-с-ресурсами - лучший вариант.

chrylis -cautiouslyoptimistic- 26.10.2018 05:57

@chrylis К сожалению, потому что мне приходится повторять цикл каждый раз, когда я вставляю новое слово в таблицу, это проблема производительности, если используются большие файлы

Daredevil 26.10.2018 06:06

Другие вопросы по теме