Java lê uma grande quantidade de dados do oracle e os grava em um arquivo
Contexto : O projeto precisa ler os campos da tabela do Oracle e unir os campos com espaçadores especificados e enviar para txt. O volume de dados de cada tabela é de cerca de 2.000 W, pois você só precisa ler todos os dados de um campo especificado em uma tabela, e não precisa considerar a otimização da consulta, apenas otimizar a escala de leitura da tabela.
Versão oracle 11G
Ideia um:
Use a instrução oracle para paginar a tabela de dados. O que deve ser observado aqui é a eficiência de rowid e rownum, e a ordem por não é usada
SELECT t.*
FROM a t, (SELECT ROWNUM rn, c.*
FROM (SELECT ROWID k
FROM a
ORDER BY ID) c) b
WHERE t.ROWID = b.k AND b.rn BETWEEN 10001 AND 20000;
Há um artigo comparativo, você pode dar uma olhada em http://www.itpub.net/thread-1603830-1-1.html
Essa ideia também não é adequada para minhas necessidades. A leitura de paginação encurta o tempo de consulta, mas para dezenas de milhões de tabelas grandes, quanto mais tarde a paginação demora, a melhoria geral da eficiência não é muito. .
Idéia 2:
Ao gravar dados, eu uso vários threads para melhorar a eficiência da gravação.Testes provaram que meu gargalo de eficiência está na leitura de dados, não na gravação de dados.
Idéia três:
Use ResultSet para ler o conjunto de resultados em lotes. No início, não esperava que ResultSet suportasse diretamente a leitura em lote. Demorou muito nas duas primeiras ideias.
Primeiro, explique
o uso comum de ResultSet antes de colar o código : clique para visualizar
A maioria dos artigos explica métodos comuns e configurações de parâmetros. O setFetchSize () e setMaxRows () de ResultSet estão ausentes e poucas pessoas mencionam
简单来说
setFetchSize() :是设置ResultSet每次向数据库取的行数
例如:rs.setFetchSize(100),ResultSet每次向数据库读取100条数据,
之后下一百条数据的读取是在ResultSet内部完成的,不需要手动去进行调用或定位数据从哪行开始。
setMaxRows() :是设置Resultset最多返回的行数,不需要读取全部数据,只要特定行数的数据,可以选择此方法。
A análise em um artigo não é
ruim : JDBC leitura de otimização de dados setFetchSize
JDBC leitura de otimização de dados - tamanho de busca
Além disso, se definido
stmt = destCon.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_READ_ONLY);
Pode relatar este erro
这时需要把
ResultSet.TYPE_SCROLL_SENSITIVE
改为
ResultSet.TYPE_SCROLL_INSENSITIVE,
Cole meu código abaixo
public static void main(String[] args) throws SQLException, ClassNotFoundException, IOException {
String selsql;
Connection destCon = null;
Statement stmt = null;
BufferedWriter output = null;
long rowCount = 0L;
int colCounts = 0;
ResultSet res = null;
long flen = 0L;
selsql = "select RANDOM_STRING from myTestTable";
destCon = getConnection();
int fileCount = 1;
EtlRuler etlRuler = new EtlRuler();
etlRuler.setLocal_path("E:\\web_project\\");
etlRuler.setFile_name("test010.txt");
String filePath = etlRuler.getLocal_path() + etlRuler.getFile_name().replace("${NUM}", "00" + fileCount);
etlRuler.getDataPath().add(filePath);
File file = new File(etlRuler.getDataPath().get(fileCount - 1));
if (!file.exists()) {
file.createNewFile();
}
StringBuilder line = new StringBuilder();
output = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file, false), StandardCharsets.UTF_8));
stmt = destCon.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_READ_ONLY);
res = stmt.executeQuery(selsql);
res.setFetchSize(2000);
if (res == null || !res.next()) {
System.out.println("数据文件sql无数据!");
// throw new Exception("数据文件sql无数据!");
}
assert res != null;
res.previous();
// 获取字段元信息
ResultSetMetaData rsmd1 = res.getMetaData();
colCounts = rsmd1.getColumnCount();
int j = 0;
String str = "";
while (res.next()) {
//System.out.println("开始读取数据" + rowCount++);
// 打印进度
rowCount++;
if (rowCount % 2000 == 0) {
Date date = new Date();
//20w条数据的时候写入一下,之后清空StringBuilder,重新添加数据
System.out.println("执行时间:" + date);
System.out.println(rowCount + " ----rows proceed");
// output.write(line.toString());
// output.flush();
// line.delete(0, line.length());
}
for (int i = 1; i <= colCounts; i++) {
//line.append(res.getString(i)).append("\n");
str = res.getString(i)+"\n";
}
output.write(str);
output.flush();
str = "";
//System.out.println("开始写入数据");
if (file.length() > (1024 * 500)) {
if (etlRuler.getFile_name().contains("${NUM}")) {
//output.write(line.toString());
//output.flush();
//line.delete(0,line.length());
fileCount++;
System.out.println("创建新文件");
String newfilePath = etlRuler.getLocal_path() + etlRuler.getFile_name().replace("${NUM}", "00" + fileCount);
etlRuler.getDataPath().add(newfilePath);
file = new File(etlRuler.getDataPath().get(fileCount - 1));
if (!file.exists()) {
file.createNewFile();
}
output = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file, false),
StandardCharsets.UTF_8));
}
}
}
//System.out.println("开始写入数据");
output.write(line.toString());
output.flush();
output.close();
flen = file.length();
System.out.println("文件大小:" + flen);
}
public static Connection getConnection() throws ClassNotFoundException, SQLException {
Class.forName("oracle.jdbc.driver.OracleDriver");
Connection con = null;
con = DriverManager.getConnection(
"jdbc:oracle:thin:@" + ip + ":" + port + ":" + sid, user,
password); //设置数据库连接字符串
return con;
}