一次性 SELECT * 載入百萬筆資料會導致 JVM Heap 爆炸 (OOM)。解決方案:分頁游標 + 流式寫入,記憶體佔用恆定。
public class LargeDataExporter {
private static final int PAGE_SIZE = 5000; // 根據記憶體調整
private static final String EXPORT_DIR = "/data/export/";
public void exportByIdCursor(Connection conn, long startId, String outputFile) throws SQLException, IOException {
String sql = "SELECT id, title, create_time FROM t_test WHERE id > ? ORDER BY id ASC LIMIT ?";
try (PreparedStatement ps = conn.prepareStatement(sql);
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(
new FileOutputStream(outputFile), StandardCharsets.UTF_8))) {
long lastId = startId;
int totalExported = 0;
boolean hasMore = true;
while (hasMore) {
ps.setLong(1, lastId);
ps.setInt(2, PAGE_SIZE);
try (ResultSet rs = ps.executeQuery()) {
hasMore = false;
while (rs.next()) {
hasMore = true;
lastId = rs.getLong("id");
String line = String.format("%d\t%d\t%s\t%d%n",
++totalExported, lastId,
rs.getString("title"),
rs.getLong("create_time"));
writer.write(line);
}
}
// 定期 flush 確保資料落盤
if (totalExported % 50000 == 0) writer.flush();
}
writer.flush();
System.out.printf("匯出完成:共 %d 筆,最後 ID=%d%n", totalExported, lastId);
}
}
public void exportByTimeWindow(Connection conn, long startTimeMillis, String outputFile) throws SQLException, IOException {
String sql = "SELECT id, title, create_time FROM t_test WHERE create_time > ? ORDER BY create_time ASC LIMIT ?";
try (PreparedStatement ps = conn.prepareStatement(sql);
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(
new FileOutputStream(outputFile), StandardCharsets.UTF_8))) {
long cursorTime = startTimeMillis;
int totalExported = 0;
boolean hasMore = true;
while (hasMore) {
ps.setLong(1, cursorTime);
ps.setInt(2, PAGE_SIZE);
try (ResultSet rs = ps.executeQuery()) {
hasMore = false;
while (rs.next()) {
hasMore = true;
cursorTime = rs.getLong("create_time");
String line = String.format("%d\t%d\t%s\t%d%n",
++totalExported,
rs.getLong("id"),
rs.getString("title"),
cursorTime);
writer.write(line);
}
}
}
writer.flush();
}
}
}
OFFSET 深分頁效能劣化,利用索引鍵 (id 或 create_time) 定位| 資料庫 | 工具/指令 | 特點 |
|---|---|---|
| MySQL | SELECT ... INTO OUTFILE | 伺服器端直接寫檔,最快,需 FILE 權限 |
| PostgreSQL | COPY (SELECT ...) TO STDOUT | 串流輸出,支援 CSV/二進制格式 |
| Oracle | SQL*Plus / Data Pump | 企業級並行匯出 |
| SQL Server | bcp utility | 高效能大量複製 |