如何将 SQLite 数据库的大小限制增加到 140TB?
How to increase the size limit of a SQLite database to 140TB?
我正在 Java 中写入 SQLite 数据库。几天来一切顺利,然后突然一切都崩溃了,我得到了以下堆栈跟踪:
org.sqlite.SQLiteException: [SQLITE_FULL] Insertion failed because database is full (database or disk is full)
at org.sqlite.core.DB.newSQLException(DB.java:909)
at org.sqlite.core.DB.newSQLException(DB.java:921)
at org.sqlite.core.DB.throwex(DB.java:886)
at org.sqlite.core.DB.executeBatch(DB.java:774)
at org.sqlite.core.CorePreparedStatement.executeBatch(CorePreparedStatement.java:79)
at co.happy.GroupByWriteFile.run(GroupByWriteFile.java:51)
at java.lang.Thread.run(Thread.java:748)
磁盘未满。这是 df -h
:
的输出
root@host:/output# df -h
Filesystem Size Used Avail Use% Mounted on
udev 32G 0 32G 0% /dev
tmpfs 6.3G 8.7M 6.3G 1% /run
/dev/xvda1 7.7G 1.9G 5.9G 24% /
tmpfs 32G 0 32G 0% /dev/shm
tmpfs 5.0M 0 5.0M 0% /run/lock
tmpfs 32G 0 32G 0% /sys/fs/cgroup
tmpfs 6.3G 0 6.3G 0% /run/user/1000
/dev/xvdb1 2.0T 572G 1.3T 31% /input
/dev/xvdc1 2.9T 1.1T 1.8T 37% /output
这是 /output 的内容(包含数据库):
root@host:/output# ls -lrth
total 1.1T
drwx------ 2 root root 16K Aug 31 23:39 lost+found
-rw-r--r-- 1 root root 1.0T Sep 2 05:12 groupby.db
我已经在多台服务器上 运行 尝试过代码,但我总是得到同样的结果。数据库中的一个 table 中可能有大约 10 亿行,另一个中大约有 2 亿行。根据 SQLite's Limit page,我离 "The theoretical maximum number of rows in a table is 2^64," 很远,最大数据库大小是 "the maximum size of a database file is 2147483646 pages. At the maximum page size of 65536 bytes, this translates into a maximum database size of approximately 1.4e+14 bytes (140 terabytes...)",我也离它很远。
阅读以上内容,我的解释是,如果我将 page_size 增加到 65536,那么我将能够达到 140TB 的最大值。但是,我还了解到这会对性能产生严重影响。这是达到 140TB 的正确方法吗?如果不是,将大小限制增加到 140TB 的步骤是什么?如果全部,它如何影响性能?
编辑
添加查询:
PreparedStatement ps = null;
PreparedStatement ps2 = null;
int i = 0;
try {
ps = conn.prepareStatement("REPLACE INTO groupByKeys VALUES (?, ?)");
ps2 = conn.prepareStatement("INSERT INTO groupByVals VALUES (?, ?)");
} catch (SQLException e) {
e.printStackTrace();
}
while (true) {
try {
DedupeInstruction d = writeQueue.take();
ps.setString(1, d.getOutFile());
if (d.isHasCustom()) {
ps.setInt(2, 1);
} else {
ps.setInt(2, 0);
}
ps2.setString(1, d.getOutFile());
ps2.setString(2, d.getLine());
ps.addBatch();
ps2.addBatch();
if (i % 1000 == 0) {
ps.executeBatch();
ps2.executeBatch();
}
} catch (InterruptedException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
}
增加最大数据库大小的唯一方法是增加页面大小。
对于大型数据库,使页面大小尽可能大是一种改进,因为这样可以减少每页的开销。
即使是普通的数据库,页面大小也应该至少和文件系统使用的块大小一样大,现在是4 KB。 (最近的 SQLite 版本会自动执行此操作,但您的数据库的页面大小为 512 字节。)
您应该在创建数据库之前设置页面大小,之后执行 PRAGMA page_size. For an existing database, you'd have to run VACUUM,这不是您想要处理大量数据的事情。
请注意,REPLACE 总是删除旧行(如果存在);如果其中大部分实际上并未更改行,则可以通过使用两个语句来避免很多 I/O。
我正在 Java 中写入 SQLite 数据库。几天来一切顺利,然后突然一切都崩溃了,我得到了以下堆栈跟踪:
org.sqlite.SQLiteException: [SQLITE_FULL] Insertion failed because database is full (database or disk is full)
at org.sqlite.core.DB.newSQLException(DB.java:909)
at org.sqlite.core.DB.newSQLException(DB.java:921)
at org.sqlite.core.DB.throwex(DB.java:886)
at org.sqlite.core.DB.executeBatch(DB.java:774)
at org.sqlite.core.CorePreparedStatement.executeBatch(CorePreparedStatement.java:79)
at co.happy.GroupByWriteFile.run(GroupByWriteFile.java:51)
at java.lang.Thread.run(Thread.java:748)
磁盘未满。这是 df -h
:
root@host:/output# df -h
Filesystem Size Used Avail Use% Mounted on
udev 32G 0 32G 0% /dev
tmpfs 6.3G 8.7M 6.3G 1% /run
/dev/xvda1 7.7G 1.9G 5.9G 24% /
tmpfs 32G 0 32G 0% /dev/shm
tmpfs 5.0M 0 5.0M 0% /run/lock
tmpfs 32G 0 32G 0% /sys/fs/cgroup
tmpfs 6.3G 0 6.3G 0% /run/user/1000
/dev/xvdb1 2.0T 572G 1.3T 31% /input
/dev/xvdc1 2.9T 1.1T 1.8T 37% /output
这是 /output 的内容(包含数据库):
root@host:/output# ls -lrth
total 1.1T
drwx------ 2 root root 16K Aug 31 23:39 lost+found
-rw-r--r-- 1 root root 1.0T Sep 2 05:12 groupby.db
我已经在多台服务器上 运行 尝试过代码,但我总是得到同样的结果。数据库中的一个 table 中可能有大约 10 亿行,另一个中大约有 2 亿行。根据 SQLite's Limit page,我离 "The theoretical maximum number of rows in a table is 2^64," 很远,最大数据库大小是 "the maximum size of a database file is 2147483646 pages. At the maximum page size of 65536 bytes, this translates into a maximum database size of approximately 1.4e+14 bytes (140 terabytes...)",我也离它很远。
阅读以上内容,我的解释是,如果我将 page_size 增加到 65536,那么我将能够达到 140TB 的最大值。但是,我还了解到这会对性能产生严重影响。这是达到 140TB 的正确方法吗?如果不是,将大小限制增加到 140TB 的步骤是什么?如果全部,它如何影响性能?
编辑
添加查询:
PreparedStatement ps = null;
PreparedStatement ps2 = null;
int i = 0;
try {
ps = conn.prepareStatement("REPLACE INTO groupByKeys VALUES (?, ?)");
ps2 = conn.prepareStatement("INSERT INTO groupByVals VALUES (?, ?)");
} catch (SQLException e) {
e.printStackTrace();
}
while (true) {
try {
DedupeInstruction d = writeQueue.take();
ps.setString(1, d.getOutFile());
if (d.isHasCustom()) {
ps.setInt(2, 1);
} else {
ps.setInt(2, 0);
}
ps2.setString(1, d.getOutFile());
ps2.setString(2, d.getLine());
ps.addBatch();
ps2.addBatch();
if (i % 1000 == 0) {
ps.executeBatch();
ps2.executeBatch();
}
} catch (InterruptedException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
}
增加最大数据库大小的唯一方法是增加页面大小。
对于大型数据库,使页面大小尽可能大是一种改进,因为这样可以减少每页的开销。
即使是普通的数据库,页面大小也应该至少和文件系统使用的块大小一样大,现在是4 KB。 (最近的 SQLite 版本会自动执行此操作,但您的数据库的页面大小为 512 字节。)
您应该在创建数据库之前设置页面大小,之后执行 PRAGMA page_size. For an existing database, you'd have to run VACUUM,这不是您想要处理大量数据的事情。
请注意,REPLACE 总是删除旧行(如果存在);如果其中大部分实际上并未更改行,则可以通过使用两个语句来避免很多 I/O。