Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/402.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java SQLite插入会随着时间的推移缓慢爬行_Java_Performance_Sqlite_Jdbc_Database Performance - Fatal编程技术网

Java SQLite插入会随着时间的推移缓慢爬行

Java SQLite插入会随着时间的推移缓慢爬行,java,performance,sqlite,jdbc,database-performance,Java,Performance,Sqlite,Jdbc,Database Performance,我正在使用下面的程序将非常大的.csv文件(约250万行)中的值插入到SQLite数据库中。它开始非常快,但随着时间的推移开始变慢,最后无限期地挂在90万行左右。我的直觉是,它在某种程度上消耗内存,但不完全是内存泄漏,因为它从不抛出OutOfMemoryException或类似的异常。明确地说,该程序从未失败或崩溃。它只是变得越来越慢,直到停止前进。我的笔记本电脑上的所有其他进程也会受到影响,最终甚至需要10秒钟才能注册鼠标移动 我对数据库不是很有经验,所以我在执行INSERT语句时很可能会做一

我正在使用下面的程序将非常大的.csv文件(约250万行)中的值插入到SQLite数据库中。它开始非常快,但随着时间的推移开始变慢,最后无限期地挂在90万行左右。我的直觉是,它在某种程度上消耗内存,但不完全是内存泄漏,因为它从不抛出
OutOfMemoryException
或类似的异常。明确地说,该程序从未失败或崩溃。它只是变得越来越慢,直到停止前进。我的笔记本电脑上的所有其他进程也会受到影响,最终甚至需要10秒钟才能注册鼠标移动

我对数据库不是很有经验,所以我在执行
INSERT
语句时很可能会做一些愚蠢的事情。我最近做的修改是使用
PreparedStatement.addBatch()
PreparedStatement.executeBatch()
,尽管阅读了文档,但我仍然不清楚是否正确使用了它们。如果有区别的话,我将使用sqlite-jdbc-3.7.2.jar

public class Database{

        public static void main(String[] args){
            Connection c = connect("db.db");
//            createTable(c);
            addCSVToDatabase(c, "test-10000.csv");
//            print(c);
            disconnect(c);
        }

        public static void createTable(Connection c) {
            Statement stmt;
            String sql = "CREATE TABLE results("
                    + "ID            INTEGER    NOT NULL    PRIMARY KEY AUTOINCREMENT, "
                    + "TITLE         TEXT       NOT NULL, "
                    + "URL           TEXT       NOT NULL    UNIQUE, "
                    + "BEAN  BLOB"
                    + ");"; 
            System.out.println("QUERY: " + sql);
            try {
                stmt = c.createStatement();
                stmt.executeUpdate(sql);
            } catch (SQLException e) { e.printStackTrace();}
        }

        public static void addCSVToDatabase(Connection c, String csvFile){

            BufferedReader reader = null;
            int x = 0;
            DBEntryBean b;
            String[] vals;
            ByteArrayOutputStream baos = null;
            ObjectOutputStream oos = null;
            PreparedStatement pstmt = null;
            String sql = "INSERT OR IGNORE INTO results("
                    + "TITLE, "
                    + "URL, "
                    + "BEAN"
                    + ") VALUES(?, ?, ?);";
            try{
                pstmt = c.prepareStatement(sql);
                reader = new BufferedReader(new InputStreamReader(new FileInputStream(csvFile), "UTF-8"));
                c.setAutoCommit(false);

                for(String line; (line = reader.readLine()) != null;){

                    vals = line.split("\\|"); // Each line is of the form: "title|URL|...|...|..."
                    b = new DBEntryBean();
                    b.setTitle(vals[0]);
                    b.setURL(vals[1]);

                    pstmt.setString(Constants.DB_COL_TITLE, b.getTitle());      
                    pstmt.setString(Constants.DB_COL_URL, b.getURL());  

                    // Store the DBEntryBean in the table so I can retrieve it, rather than construct a new one every time I need it.
                    baos = new ByteArrayOutputStream();
                    oos = new ObjectOutputStream(baos);
                    oos.writeObject(b);
                    pstmt.setBytes(Constants.DB_COL_BEAN, baos.toByteArray());
                    pstmt.addBatch();
                    pstmt.executeBatch(); 
                    System.out.println("Line: " + x++);
                }
            } catch (Exception e){ e.printStackTrace(); 
            } finally{
                try{ 
                    if(pstmt != null){ pstmt.close(); }
                    c.setAutoCommit(true);
                } catch (SQLException e) { e.printStackTrace(); }
            }
        }

        private static Connection connect(String path) {

            String url = "jdbc:sqlite:" + path;
            Connection conn = null;
            try {
                Class.forName("org.sqlite.JDBC");
                conn = DriverManager.getConnection(url);
            } catch (Exception e) { e.printStackTrace(); }
            return conn;
        }

        private static void disconnect(Connection c) {
            try{ if(c != null){ c.close(); }
            } catch(SQLException e){ e.printStackTrace(); }
        }

        private static void print(Connection c){
            Statement stmt = null;
            String sql = "SELECT * FROM results;";
            ResultSet rs = null;
            try {
                stmt = c.createStatement();
                rs = stmt.executeQuery(sql);
                while(rs.next()){
                    System.out.println(rs.getString("TITLE"));
                }
            } catch(Exception e){ e.printStackTrace(); }
        }


    }

尝试删除
setAutoCommit
调用,并仅在批处理了相当多的插入时执行
executeBatch
。另外,不要在每次插入时打印到控制台。例如:

publicstaticvoid addcsvtodabase(连接c,字符串csvFile){
BufferedReader reader=null;
int批=0;
int-total=0;
菜豆b;
字符串[]VAL;
ByteArrayOutputStream baos=null;
ObjectOutputStream oos=null;
PreparedStatement pstmt=null;
String sql=“在结果中插入或忽略(”
+“头衔,”
+“URL,”
+“豆子”
+)值(?,?);”;
试一试{
pstmt=c.prepareStatement(sql);
reader=新的BufferedReader(新的InputStreamReader(新的文件InputStream(csvFile),“UTF-8”);
for(字符串行;(line=reader.readLine())!=null;){
VAL=行分割(“\\\\”);
b=新的DBEntryBean();
b、 setTitle(VAL[0]);
b、 setURL(VAL[1]);
bas=新的ByteArrayOutputStream();
oos=新对象输出流(BAS);
oos.writeObject(b);
pstmt.setString(Constants.DB_COL_TITLE,b.getTitle());
pstmt.setString(Constants.DB_COL_URL,b.getURL());
pstmt.setBytes(Constants.DB_COL_BEAN,baos.toByteArray());
pstmt.addBatch();
++批次;
++总数;
如果(批次==10000){
pstmt.executeBatch();
系统输出打印项次(“总计:+总计);
批次=0;
}
}
如果(批次>0){
pstmt.executeBatch();
系统输出打印项次(“总计:+总计);
}
}catch(异常e){e.printStackTrace();
}最后{
试试{
如果(pstmt!=null){pstmt.close();}
}catch(SQLException e){e.printStackTrace();}
}
}

如果性能仍然很糟糕,我建议您一次更改一件事情,看看是否可以隔离问题。例如,删除
URL
列上的
UNIQUE
索引,查看它总是插入时的性能。或者删除BLOB的插入,等等。

添加一个。@ElliottFrisch谢谢,这听起来很有希望。关于我应该多长时间执行一次循环中的
VACUUM
语句,您有什么建议吗?我建议尝试执行10k插入,看看这是否会改善情况。不要将所有插入都放在一个批次中。正如您的回答中所述,批处理应保持相对较小的大小。此外,使用
executeBatch
,切换
设置自动提交
并不重要,因为没有
提交
,因此应将其删除。