寻求可存于对象存储、支持SQL查询的单表文件格式解决方案
解决方案:用对象存储替代MySQL存储单表并支持SQL查询
核心需求
- 将用户上传的CSV转换为可存储在S3等对象存储的单表格式
- 支持直接对存储的文件执行SQL查询,生成BI报表
- 解决MySQL中表数量过多的运维压力
推荐文件格式
优先选择列式存储格式,相比原始CSV有更高的压缩率和查询性能,支持谓词下推(仅读取符合条件的数据块):
- Parquet:跨生态兼容性极强(Spark、Trino、DuckDB、Athena等均支持),压缩效率优异,是BI场景的首选格式
- ORC:Hadoop生态原生格式,针对查询性能做了深度优化,适合大规模数据场景
- 不推荐直接存储CSV:查询时需全量扫描数据,大表场景下性能极差
支持直接查询的SQL引擎&实现方案
根据应用规模和部署需求选择对应方案:
1. 轻量级嵌入式方案:DuckDB
适合单节点应用,无需额外部署服务,可直接嵌入Java/Java应用中,支持直接读取S3上的Parquet/ORC文件。示例代码贴近你的需求:
import org.duckdb.DuckDBConnection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.Statement; public class S3TableQuery { public static void main(String[] args) throws Exception { // 加载DuckDB驱动 Class.forName("org.duckdb.DuckDBDriver"); // 建立DuckDB连接 DuckDBConnection conn = (DuckDBConnection) DriverManager.getConnection("jdbc:duckdb:"); // 加载S3访问扩展(首次运行需安装) conn.execute("INSTALL 'httpfs';"); conn.execute("LOAD 'httpfs';"); // 配置S3凭证(私有存储需要,公开存储可跳过) conn.execute("SET s3_access_key_id='YOUR_ACCESS_KEY';"); conn.execute("SET s3_secret_access_key='YOUR_SECRET_KEY';"); Statement stmt = conn.createStatement(); // 直接查询S3上的Parquet表文件 ResultSet rs = stmt.executeQuery("SELECT c1, c2 FROM read_parquet('s3://xxx/bbb/t1.parquet') WHERE c3=8;"); // 处理查询结果 while (rs.next()) { System.out.printf("c1: %s, c2: %s%n", rs.getString("c1"), rs.getString("c2")); } // 关闭资源 rs.close(); stmt.close(); conn.close(); } }
2. 托管式分布式查询:AWS Athena
基于Trino(原Presto)的完全托管服务,无需部署维护,直接查询S3上的Parquet/ORC/CSV文件,按查询的数据量付费,适合大规模BI报表场景。
只需在Athena中创建外部表关联S3路径,即可用SQL查询:
CREATE EXTERNAL TABLE t1 ( c1 STRING, c2 INT, c3 INT ) STORED AS PARQUET LOCATION 's3://xxx/bbb/t1.parquet'; -- 执行查询 SELECT c1, c2 FROM t1 WHERE c3=8;
3. 自建分布式查询:Trino(原Presto)
如果需要私有部署,Trino是高性能分布式SQL引擎,支持连接S3等对象存储,查询Parquet/ORC等格式,适合多用户、大规模数据查询场景。
CSV转换为列式存储的流程
用户上传CSV后,将其转换为Parquet/ORC存储到S3,示例用Spark实现:
import org.apache.spark.sql.SparkSession; public class CsvToParquetConverter { public static void main(String[] args) { SparkSession spark = SparkSession.builder() .appName("CsvToParquet") .getOrCreate(); // 读取上传的CSV文件(假设已存到临时路径) spark.read() .option("header", "true") .option("inferSchema", "true") .csv("/tmp/uploaded_user.csv") // 写入S3为Parquet格式 .write() .mode("overwrite") .parquet("s3://xxx/bbb/t1.parquet"); spark.stop(); } }
选型建议
- 小体量应用、需要嵌入到现有系统:选DuckDB + Parquet
- 云原生、无需维护基础设施:选AWS Athena + Parquet
- 大规模分布式查询、私有部署需求:选Trino + ORC/Parquet
内容的提问来源于stack exchange,提问作者Julian Zhang
相关产品推荐
相关产品推荐

