欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 新闻 > 焦点 > 后台数据报表导出数据量过大问题

后台数据报表导出数据量过大问题

2025/3/10 22:58:53 来源:https://blog.csdn.net/FLGBgo/article/details/145932166  浏览:    关键词:后台数据报表导出数据量过大问题

现状分析

之前在mysql业务库,导出报表会出现各种表相互关联,导致夯死的情况

改进使用ClickHouse做宽表

后面使用binlog监听,洗数据洗成一张宽表,存放在ck中,但是发现超过一定数量级100w也会很卡慢,但是比mysql强的是可以出来。

如何导出300w 、500w 1000w数据量级

查看了CK有个特性,执行流式数据处理,可以使用这个特性来处理

方案 1:分批查询

如果你当前的做法是 一次性查询 100W 条数据,那就容易导致 CK 查询压力大、内存占用高。可以 分批查询,用 流式处理(如 LIMIT … OFFSET 或游标)优化导出。

SELECT * FROM my_table WHERE 条件 ORDER BY id LIMIT 10000 OFFSET 0;
SELECT * FROM my_table WHERE 条件 ORDER BY id LIMIT 10000 OFFSET 10000;
...
# 使用 游标方式 进行分页,例如:
SELECT * FROM my_table WHERE 条件 AND id > last_id ORDER BY id LIMIT 10000;

这种方案比较繁琐,效果也不好

方案 2:ClickHouse 外部表流式查询

ClickHouse 提供 流式查询 + CSV 导出,这样数据 不会全部加载到内存,而是边查边写,提高效率。

clickhouse-client --user username --password password  --query="SELECT page_name,page_path FROM table WHERE type='visit'" --format CSV > export11.csv

📌 优势

不会占用太多内存(不像 SELECT * 一次性取 100W 数据)。
查询结果可以直接写入文件,减少网络传输压力。

测试结果 百万级数据秒级生成

方案 3:异步任务 + 预生成文件

(适合超大量数据)
如果查询仍然 导致性能下降,可以考虑 后台异步处理,生成 CSV 文件后再让用户下载:

思路
用户提交导出请求后,后端 异步任务 开始查询并生成文件(存储到 OSS 或本地)。
任务完成后,给用户 返回下载链接,前端再下载文件。

实现
📌 Step 1: 后端异步查询并存 CSV

clickhouse-client --user username --password password --query="SELECT * FROM my_table WHERE 条件" --format CSV > /tmp/export_$(date +%s).csv

📌 Step 2: 文件存储到对象存储(如 MinIO / OSS)

aws s3 cp /tmp/export.csv s3://my-bucket/

📌 Step 3: 前端定期轮询下载链接 后端提供一个 API,比如:

{"status": "done","download_url": "https://oss.example.com/export_123.csv"
}

前端轮询这个 API,一旦任务完成,就给用户提供下载按钮。

CK原生命令集成到Java

和ck部署在同一个服务器上(不推荐)

import org.springframework.web.bind.annotation.*;
import java.io.*;@RestController
@RequestMapping("/clickhouse")
public class ClickHouseController {@GetMapping("/export")public String exportData() {String query = "SELECT * FROM my_table WHERE 条件";String exportFile = "/tmp/export.csv";  // 保存到临时目录String command = String.format("clickhouse-client --query=\"%s\" --format CSV > %s", query, exportFile);ProcessBuilder processBuilder = new ProcessBuilder("/bin/bash", "-c", command);try {Process process = processBuilder.start();int exitCode = process.waitFor();if (exitCode == 0) {return "✅ ClickHouse 数据导出成功:" + exportFile;} else {return "❌ ClickHouse 导出失败";}} catch (IOException | InterruptedException e) {return "⚠️ 发生异常:" + e.getMessage();}}
}

远程 SSH 连接到 ClickHouse 服务器

import com.jcraft.jsch.*;import java.io.*;public class RemoteClickHouseExecutor {private static final String SSH_HOST = "clickhouse_server_ip"; // 远程 ClickHouse 服务器 IPprivate static final String SSH_USER = "root";  // SSH 用户private static final String SSH_PASSWORD = "your_password"; // SSH 密码private static final String CLICKHOUSE_QUERY = "SELECT * FROM my_table WHERE 条件";private static final String EXPORT_FILE = "/tmp/export.csv";  // 远程服务器上的文件路径public static void main(String[] args) {try {JSch jsch = new JSch();Session session = jsch.getSession(SSH_USER, SSH_HOST, 22);session.setPassword(SSH_PASSWORD);session.setConfig("StrictHostKeyChecking", "no");session.connect();// 远程执行 ClickHouse 查询String command = "clickhouse-client --query=\"" + CLICKHOUSE_QUERY + "\" --format CSV > " + EXPORT_FILE;ChannelExec channel = (ChannelExec) session.openChannel("exec");channel.setCommand(command);channel.setInputStream(null);channel.setErrStream(System.err);InputStream inputStream = channel.getInputStream();channel.connect();// 读取命令执行结果BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));String line;while ((line = reader.readLine()) != null) {System.out.println(line);}channel.disconnect();session.disconnect();System.out.println("✅ ClickHouse 远程数据导出完成:" + EXPORT_FILE);} catch (Exception e) {e.printStackTrace();}}
}

ClickHouse JDBC 连接远程 ClickHouse

添加 ClickHouse JDBC 依赖

<dependency><groupId>ru.yandex.clickhouse</groupId><artifactId>clickhouse-jdbc</artifactId><version>0.3.2</version>
</dependency>

JDBC 查询 ClickHouse 并导出 CSV

import ru.yandex.clickhouse.ClickHouseDataSource;import java.io.*;
import java.sql.*;public class ClickHouseJdbcExport {private static final String CLICKHOUSE_URL = "jdbc:clickhouse://clickhouse_server_ip:8123/default";private static final String CLICKHOUSE_USER = "default";private static final String CLICKHOUSE_PASSWORD = "";public static void main(String[] args) {String query = "SELECT * FROM my_table WHERE 条件";String exportFile = "export.csv";try (Connection connection = new ClickHouseDataSource(CLICKHOUSE_URL).getConnection(CLICKHOUSE_USER, CLICKHOUSE_PASSWORD);Statement stmt = connection.createStatement();ResultSet rs = stmt.executeQuery(query);BufferedWriter writer = new BufferedWriter(new FileWriter(exportFile))) {ResultSetMetaData metaData = rs.getMetaData();int columnCount = metaData.getColumnCount();// 写入 CSV 头部for (int i = 1; i <= columnCount; i++) {writer.write(metaData.getColumnName(i));if (i < columnCount) writer.write(",");}writer.newLine();// 写入数据while (rs.next()) {for (int i = 1; i <= columnCount; i++) {writer.write(rs.getString(i));if (i < columnCount) writer.write(",");}writer.newLine();}System.out.println("✅ ClickHouse 数据已导出:" + exportFile);} catch (Exception e) {e.printStackTrace();}}
}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词