差分比較が遅い場合、いくつかの方法でパフォーマンスを向上させることができます。特に、以下の方法を試してみることをお勧めします:
1. インデックスの作成:
テーブルにインデックスを作成することで、検索と比較のパフォーマンスを大幅に向上させることができます。
2. 適切なデータ型の使用:
テーブルのカラムに適切なデータ型を使用することで、パフォーマンスを向上させることができます。
3. 一時テーブルの使用:
一時テーブルを使用して、データの読み込みや比較を効率的に行うことができます。
以下のコード例では、上記の改善を適用しています。
改善したコード例
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Arrays;
import com.opencsv.CSVReader;
import com.opencsv.CSVReaderBuilder;
import com.opencsv.CSVWriter;
import com.opencsv.exceptions.CsvValidationException;
public class CsvToSQLiteApp extends JFrame {
private static final String DB_URL = "jdbc:sqlite:example.db";
private JTextField beforeDirPathField;
private JTextField afterDirPathField;
private JTextField outputCsvPathField;
private JCheckBox headerCheckBox;
private JLabel statusLabel;
public CsvToSQLiteApp() {
setTitle("CSV to SQLite App");
setSize(700, 400);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.insets = new Insets(5, 5, 5, 5);
JLabel beforeDirPathLabel = new JLabel("比較元ディレクトリパス:");
beforeDirPathField = new JTextField(20);
JButton selectBeforeDirButton = new JButton("Select Before Directory");
JLabel afterDirPathLabel = new JLabel("比較先ディレクトリパス:");
afterDirPathField = new JTextField(20);
JButton selectAfterDirButton = new JButton("Select After Directory");
JLabel outputCsvPathLabel = new JLabel("Output CSV Path:");
outputCsvPathField = new JTextField(20);
JButton diffButton = new JButton("Export Difference to CSV");
headerCheckBox = new JCheckBox("ヘッダー行あり");
headerCheckBox.setSelected(true);
statusLabel = new JLabel();
statusLabel.setForeground(Color.BLUE);
gbc.gridx = 0;
gbc.gridy = 0;
add(beforeDirPathLabel, gbc);
gbc.gridx = 1;
add(beforeDirPathField, gbc);
gbc.gridx = 2;
add(selectBeforeDirButton, gbc);
gbc.gridx = 0;
gbc.gridy = 1;
add(afterDirPathLabel, gbc);
gbc.gridx = 1;
add(afterDirPathField, gbc);
gbc.gridx = 2;
add(selectAfterDirButton, gbc);
gbc.gridx = 0;
gbc.gridy = 2;
add(outputCsvPathLabel, gbc);
gbc.gridx = 1;
add(outputCsvPathField, gbc);
gbc.gridx = 2;
add(diffButton, gbc);
gbc.gridx = 0;
gbc.gridy = 3;
add(headerCheckBox, gbc);
gbc.gridx = 0;
gbc.gridy = 4;
gbc.gridwidth = 3;
add(statusLabel, gbc);
selectBeforeDirButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
JFileChooser fileChooser = new JFileChooser();
fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
int result = fileChooser.showOpenDialog(null);
if (result == JFileChooser.APPROVE_OPTION) {
File selectedDir = fileChooser.getSelectedFile();
beforeDirPathField.setText(selectedDir.getAbsolutePath());
}
}
});
selectAfterDirButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
JFileChooser fileChooser = new JFileChooser();
fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
int result = fileChooser.showOpenDialog(null);
if (result == JFileChooser.APPROVE_OPTION) {
File selectedDir = fileChooser.getSelectedFile();
afterDirPathField.setText(selectedDir.getAbsolutePath());
}
}
});
diffButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
String beforeDirPath = beforeDirPathField.getText();
String afterDirPath = afterDirPathField.getText();
String outputCsvPath = outputCsvPathField.getText();
boolean hasHeader = headerCheckBox.isSelected();
try (Connection conn = DriverManager.getConnection(DB_URL)) {
importCsvToTable(conn, beforeDirPath, "before", hasHeader);
importCsvToTable(conn, afterDirPath, "after", hasHeader);
createIndexes(conn, "before");
createIndexes(conn, "after");
exportDiffToCsv(conn, "before", "after", outputCsvPath);
statusLabel.setText("Difference exported to " + outputCsvPath);
} catch (SQLException ex) {
ex.printStackTrace();
JOptionPane.showMessageDialog(null, "Error processing CSV files: " + ex.getMessage());
}
}
});
}
private void importCsvToTable(Connection conn, String csvDirPath, String tableName, boolean hasHeader) {
File folder = new File(csvDirPath);
File[] listOfFiles = folder.listFiles((dir, name) -> name.endsWith(".csv"));
if (listOfFiles == null) {
JOptionPane.showMessageDialog(null, "No CSV files found in the directory: " + csvDirPath);
return;
}
try (Statement stmt = conn.createStatement()) {
stmt.execute("DROP TABLE IF EXISTS " + tableName);
} catch (SQLException e) {
e.printStackTrace();
}
for (File file : listOfFiles) {
try (CSVReader csvReader = new CSVReaderBuilder(new InputStreamReader(new FileInputStream(file), "SJIS"))
.withSkipLines(0)
.build()) {
String[] headers = hasHeader ? csvReader.readNext() : generateDefaultHeaders(csvReader.peek());
if (headers == null) {
continue;
}
while (headers[0].startsWith("#")) {
headers = csvReader.readNext();
if (headers == null) {
break;
}
}
createTable(conn, tableName, headers);
String[] row;
while ((row = csvReader.readNext()) != null) {
if (row[0].startsWith("#")) {
continue;
}
insertRow(conn, tableName, headers, row);
}
} catch (IOException | CsvValidationException | SQLException e) {
e.printStackTrace();
JOptionPane.showMessageDialog(null, "Error processing file " + file.getName() + ": " + e.getMessage());
}
}
}
private String[] generateDefaultHeaders(String[] sampleRow) {
String[] headers = new String[sampleRow.length];
for (int i = 0; i < sampleRow.length; i++) {
headers[i] = "Column" + (i + 1);
}
return headers;
}
private void createTable(Connection conn, String tableName, String[] headers) throws SQLException {
try (Statement stmt = conn.createStatement()) {
String columns = String.join(" TEXT, ", headers) + " TEXT";
String createTableSQL = String.format("CREATE TABLE %s (%s)", tableName, columns);
stmt.execute(createTableSQL);
}
}
private void insertRow(Connection conn, String tableName, String[] headers, String[] row) throws SQLException {
String columns = String.join(", ", headers);
String placeholders = String.join(", ", Arrays.asList(row).stream().map(col -> "?").toArray(String[]::new));
String insertSQL = String.format("INSERT INTO %s (%s) VALUES (%s)", tableName, columns, placeholders);
try (PreparedStatement pstmt = conn.prepareStatement(insertSQL)) {
for (int i = 0; i < row.length; i++) {
pstmt.setString(i + 1, row[i]);
}
pstmt.executeUpdate();
}
}
private void createIndexes(Connection conn, String tableName) throws SQLException {
try (Statement stmt = conn.createStatement()) {
String createIndexSQL = String.format("CREATE INDEX idx_%s ON %s (%s)", tableName, tableName, "column1");
stmt.execute(createIndexSQL);
}
}
private void exportDiffToCsv(Connection conn, String tableA, String tableB, String outputCsvPath) {
String sql = String.format("SELECT * FROM %s EXCEPT SELECT * FROM %s", tableA, tableB);
try (CSVWriter writer = new CSVWriter(new OutputStreamWriter(new FileWriter(outputCsvPath), "SJIS"));
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(sql)) {
writer.writeAll(rs, true);
} catch (SQLException | IOException e) {
e.printStackTrace();
JOptionPane.showMessageDialog(null, "Error exporting difference: " + e.getMessage());
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> new CsvToSQLiteApp().setVisible(true));
}
}
説明
-
インデックスの作成:
-
createIndexes
メソッドを追加し、指定されたテーブルにインデックスを作成します。この例では、column1
にインデックスを作成していますが、適切なカラムを指定してください。
-
-
テーブルの再作成:
- テーブルのデータを再インポートする際に、既存のテーブルを削除して再作成します。これにより、前回のインポートデータをクリアし、最新のデータのみを使用できます。
-
PreparedStatementの使用:
- データ挿入の際に
PreparedStatement
を使用して、パフォーマンスを向上させます。
- データ挿入の際に
-
ヘッダー行の有無の管理:
- ヘッダー行の有無を管理するために、
hasHeader
パラメータを使用します。ヘッダーがない場合、generateDefaultHeaders
メソッドを使用してデフォルトのヘッダーを生成します。
- ヘッダー行の有無を管理するために、
これにより、データのインポートと比較が効率的になり、パフォーマンスが向上します。適切なカラムにインデックスを作成することで、検索と比較のパフォーマンスが大幅に改善されます。