Java-多线程以提高将数据插入数据库的性能
我正在MYSQL中的一个表上构建一个索引表(倒排文件)。它的工作方式是从一个文件中提取所有单词,并将它们存储到一个hashset中,然后将这些单词逐个插入到我的数据库表中 它工作得很好,我知道倒排文件确实需要一些时间来建立索引表。我正在尝试优化表的索引时间,并且正在考虑使用多线程。它会加速性能吗 但是,我不太确定如何将它与我当前的程序集成,因为我是多线程新手 代码:Java-多线程以提高将数据插入数据库的性能,java,mysql,Java,Mysql,我正在MYSQL中的一个表上构建一个索引表(倒排文件)。它的工作方式是从一个文件中提取所有单词,并将它们存储到一个hashset中,然后将这些单词逐个插入到我的数据库表中 它工作得很好,我知道倒排文件确实需要一些时间来建立索引表。我正在尝试优化表的索引时间,并且正在考虑使用多线程。它会加速性能吗 但是,我不太确定如何将它与我当前的程序集成,因为我是多线程新手 代码: 如果有任何提示,我将不胜感激。不,将数据推入具有多个线程的数据库通常不会加快任何速度 相反,请尝试以下操作: [1] 批量添加数据
如果有任何提示,我将不胜感激。不,将数据推入具有多个线程的数据库通常不会加快任何速度 相反,请尝试以下操作: [1] 批量添加数据时,请使用DB引擎提供的批量添加数据原语。我不知道mysql是否支持这一点,以及如何从java实现这一点。例如,在postgres中,您将使用COPY而不是INSERT [2] 特别是如果您不能使用复制或类似功能,请关闭所有索引(删除它们),然后执行所有插入操作,然后添加索引,这比先创建索引然后插入要快 [3] 使用事务,并每隔大约100次插入提交事务。在大多数情况下,这比每次插入后提交要快,也比几十万次后提交要快 [4] 早点开始。在示例代码中,您可以立即开始插入,而不是先将所有数据填充到哈希集中,然后再添加 [5] 不要老是做事先准备好的陈述;重复使用同一个 [6] 你做了两次陈述,却什么也不做。不要;你在浪费资源
[7] 准备好的报表需要关闭。你不能关闭它们。这可能会大大降低速度。不要制造太多(只有一个应该这样做),当你完成后关闭它们。搜索“ARM”,这是一种java构造,可以方便地正确关闭资源。现在它已经有10多年的历史了。不,用多个线程将数据推入数据库通常不会加快任何速度 相反,请尝试以下操作: [1] 批量添加数据时,请使用DB引擎提供的批量添加数据原语。我不知道mysql是否支持这一点,以及如何从java实现这一点。例如,在postgres中,您将使用COPY而不是INSERT [2] 特别是如果您不能使用复制或类似功能,请关闭所有索引(删除它们),然后执行所有插入操作,然后添加索引,这比先创建索引然后插入要快 [3] 使用事务,并每隔大约100次插入提交事务。在大多数情况下,这比每次插入后提交要快,也比几十万次后提交要快 [4] 早点开始。在示例代码中,您可以立即开始插入,而不是先将所有数据填充到哈希集中,然后再添加 [5] 不要老是做事先准备好的陈述;重复使用同一个 [6] 你做了两次陈述,却什么也不做。不要;你在浪费资源
[7] 准备好的报表需要关闭。你不能关闭它们。这可能会大大降低速度。不要制造太多(只有一个应该这样做),当你完成后关闭它们。搜索“ARM”,这是一种java构造,可以方便地正确关闭资源。现在它已经有10多年的历史了。如果您的Java程序可以分成更小的部分,每个部分都可以独立于其他部分运行,那么它可能会从多线程中受益。是这样吗?@TimBiegeleisen在不分成小块的情况下,创建几个线程来运行我的主方法会有帮助吗?它会起作用还是会有帮助?不是同一个问题。在你的代码<代码> Read Dabase/COD>中,你每次都在连接——这将是非常缓慢的,-考虑使用一个DCPONUN提示:你可以马上开始往单词中添加单词,你不需要等待文本解析器完成,只需把单词传递给另一个线程,并且在另一个线程上保持一个恒定的DB连接。如果您的Java程序可以分成更小的部分,每个部分都可以独立于over运行,那么它可能会从多线程中受益。是这样吗?@TimBiegeleisen在不分成小块的情况下,创建几个线程来运行我的主方法会有帮助吗?它会起作用还是会有帮助?不是同一个问题。在你的代码<代码> Read Dabase/COD>中,你每次都在连接——这将是非常缓慢的,-考虑使用一个DCPONUN提示:你可以马上开始往单词中添加单词,你不需要等待文本解析器完成,只需把单词传递给另一个线程,并在另一个线程上保持恒定的DB连接。基于您的第1点,我尝试了大容量插入,但对性能没有多大帮助。您能否澄清第5点?我不明白我在哪里重复使用了我准备好的声明。4:我使用hashset是因为我想在其中存储唯一的单词,hashset不允许重复,所以当我插入数据库时,没有重复的单词。@Daredevil您没有重用preparedstatement。你应该开始这样做。我应该如何重用它?@Daredevil你可以再次调用它的.setString(1,path)(因此,在循环之外生成preparedstatement),然后继续调用它的.executeUpdate()。基于你的第1点,我尝试了批量插入,但对性能没有多大帮助。你能澄清第5点吗?我不明白我在哪里重复使用了我准备好的声明。4:我使用hashset是因为我想在其中存储唯一的单词,hashset不允许重复,所以当我插入数据库时,没有重复的单词。@Daredevil您没有重用preparedstatement。你应该开始这样做。我应该如何重用它?@Daredevil你可以再次调用它上的.setString(1,path)(所以,让
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");
}
}
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();
}
}