Trino/Presto 查询优化实战:联邦查询配置与湖仓加速 SQL 改写
给出 Hive/MySQL 连接器完整配置、CBO 统计信息收集与 JOIN 重排序 SQL、嵌套子查询改 CTE 示例,附 TPC-DS 1TB 性能基线
联邦查询连接器配置
Trino 的核心价值在于一条 SQL 跨多个异构数据源查询,无需数据搬迁。以下是 Hive 和 MySQL 两个最常用连接器的生产级配置:
Hive 连接器配置
connector.name=hive
hive.config.resources=/etc/hadoop/core-site.xml,/etc/hadoop/hdfs-site.xml
hive.metastore.uri=thrift://hive-metastore:9083
hive.allow-drop-table=false
hive.allow-rename-table=false
hive.parquet-optimized-reader.enabled=true
hive.parquet.use-column-names=true
hive.orc.use-column-names=true
hive.metastore-load-pool-size=20
hive.max-partitions-per-scan=1000000关键参数说明:
hive.parquet-optimized-reader.enabled启用 Parquet 向量化读取,减少反序列化开销,在列式存储上可提升 2~3 倍读取性能。hive.max-partitions-per-scan限制单次扫描的最大分区数,默认 100 万。如果表的分区粒度过细(如按小时分区),需调大此值,否则查询会被截断。- 生产环境建议关闭
allow-drop-table和allow-rename-table,防止 Ad-hoc 查询误操作修改源端元数据。
MySQL 连接器配置
connector.name=mysql
connection-url=jdbc:mysql://mysql-host:3306/production
connection-user=trino_reader
connection-password=${MYSQL_PASSWORD}
mysql.jdbc-compatibility=true
mysql.max-rows-per-fetch=10000MySQL 作为维度表数据源时,mysql.max-rows-per-fetch 控制每次 fetch 的行数,适当调大可减少 JDBC 往返次数,但会增加 Trino Worker 的内存压力。
CBO 统计信息收集与 JOIN 重排序
Trino 使用基于成本的优化器(CBO)决定 JOIN 顺序和算法。CBO 的效果完全依赖统计信息的质量——没有统计信息的 CBO 退化为规则优化器,JOIN 顺序可能完全错误。
收集统计信息:
-- 对核心表执行 ANALYZE,收集列统计信息
ANALYZE hive.sales_schema.lineitem;
ANALYZE hive.sales_schema.orders;
ANALYZE hive.dim_schema.customer;
-- 检查统计信息是否生效
SELECT * FROM system.table_stats
WHERE table_schema = 'sales_schema';CBO 启用与验证:
-- 确保 CBO 已启用(默认启用)
SET SESSION enable_dynamic_filtering = true;
-- 查看查询计划,确认 JOIN 顺序是否由 CBO 决定
EXPLAIN SELECT ...
FROM lineitem l
JOIN orders o ON l.orderkey = o.orderkey
JOIN customer c ON o.custkey = c.custkey
WHERE c.nation = 'CHINA' AND l.quantity > 100;在未收集统计信息时,CBO 可能将 1 亿行的 lineorder 表作为驱动表与小表 JOIN;收集后,优化器会自动选择小表(如 nation、region)作为驱动表,通过 Broadcast Join 将小表广播到各 Worker,查询耗时可降低一个数量级。
数据服务 DataAPI
可视化生成、统一管控 API,构建 OneService 数据共享服务的数据服务平台
嵌套子查询改 CTE 改写
复杂查询中的多层嵌套子查询不仅可读性差,还会导致 Trino 的查询计划器产生大量临时计划节点,影响优化效果。改写为 CTE(Common Table Expression)可以让优化器更清晰地理解查询语义。
改写前(嵌套子查询):
SELECT region, total_amount
FROM (
SELECT c.region, SUM(o.amount) AS total_amount
FROM (
SELECT orderkey, custkey, amount
FROM orders
WHERE orderdate >= DATE '2024-01-01'
) o
JOIN (
SELECT custkey, name, region
FROM customer
WHERE region IN ('华北', '华东')
) c ON o.custkey = c.custkey
GROUP BY c.region
) sub
WHERE total_amount > 1000000;改写后(CTE):
WITH recent_orders AS (
SELECT orderkey, custkey, amount
FROM orders
WHERE orderdate >= DATE '2024-01-01'
),
target_customers AS (
SELECT custkey, name, region
FROM customer
WHERE region IN ('华北', '华东')
),
aggregated AS (
SELECT tc.region, SUM(ro.amount) AS total_amount
FROM recent_orders ro
JOIN target_customers tc ON ro.custkey = tc.custkey
GROUP BY tc.region
)
SELECT region, total_amount
FROM aggregated
WHERE total_amount > 1000000;CTE 改写的好处是:每个 CTE 独立优化,过滤条件更早执行;同时 CTE 可以被 Trino 识别为独立 Stage,实现更细粒度的并行调度。
资源组隔离
多租户环境下的核心挑战是避免大查询饿死小查询。Trino 通过资源队列(Resource Group)实现查询隔离:
{
"rootGroups": [
{
"name": "adhoc",
"maxWorkers": 30,
"maxQueued": 100,
"schedulingPolicy": "weighted_fair",
"subGroups": [
{
"name": "analyst",
"maxWorkers": 15,
"maxQueued": 50
},
{
"name": "etl",
"maxWorkers": 15,
"maxQueued": 20
}
]
},
{
"name": "bi_reports",
"maxWorkers": 20,
"maxQueued": 50
}
]
}weighted_fair 策略确保在资源紧张时,各子组按权重分配 Worker,防止单一组占用全部计算资源。生产环境建议为 BI 报表、Ad-hoc 探索和 ETL 三类负载分别建立资源组,并通过 query.max-concurrent-queries 控制每组的最大并发数。
经营分析
围绕目标、预算、执行、异常与归因,构建经营分析、过程监控、问题定位与决策闭环。
TPC-DS 1TB 性能基线
在标准硬件配置(10 节点 Worker,每节点 64 核 / 256GB 内存)下,Trino 查询 TPC-DS 1TB 基准测试的典型表现:
- 99 条查询中约 85% 在 30 秒内返回,P50 约 8 秒,P99 约 120 秒。
- 最慢的几条查询(如 Query 23、Query 67)涉及多层嵌套子查询和大规模排序,改写为 CTE 后可提升 30%~50%。
- 启用 CBO 并收集统计信息后,整体查询耗时可再降低 15%~20%。
持续优化与运维建议
建立查询基线后,需要系统化的优化和监控机制:
慢查询分析流程: 定期从 system.runtime.queries 表提取慢查询,用 EXPLAIN ANALYZE 分析每个 Stage 的执行耗时和数据交换量。如果某个 Stage 处理的行数远超预期,通常意味着过滤条件下推未生效或统计信息过期。Trino 的查询计划中会明确标注 estimated 和 actual 行数,两者偏差过大时需要重新执行 ANALYZE 更新统计信息。
存储层优化: 数据格式对查询性能影响巨大。Parquet 配合 Zstd 压缩通常是读取速度和压缩率的最佳平衡。分区策略应覆盖高频过滤条件,按日期分区是最常见的选择。对于频繁查询的热数据,可利用 Alluxio 或 JindoFS 等缓存层将数据缓存到计算节点本地,减少远端存储的网络开销。
内存与并发调优: JVM 堆内存设为节点物理内存的 70%~80%,query.max-memory-per-node 设为堆内存的 30%~50%,为 JVM GC 和非查询操作预留空间。memory.heap-headroom-per-node 设为堆内存的 20%~30%。并发控制通过 query.max-concurrent-queries 和资源组实现,避免过多并发查询导致频繁 Spill 到磁盘,反而降低整体吞吐。
连接器层面的微调: 确保谓词下推和投影下推已启用,让 Trino 在读取阶段就过滤掉不需要的行和列。对于 Hive 连接器,Split 大小建议在 128MB~256MB 之间,过小增加调度开销,过大导致单个 Task 执行时间过长。对于 MySQL 维度表,如果数据量小于 1GB,可启用 join.pushdown.enabled 将 JOIN 下推到 MySQL 执行。
建立基线与告警: 为每类查询模式(BI 报表、Ad-hoc 探索、ETL 批处理)分别建立性能基线,监控 P50 和 P99 延迟趋势。当延迟持续上升时,优先排查统计信息是否过期、数据量是否增长、集群资源是否充足三个方向。综合运用以上优化手段,在标准 10 节点集群上,大多数分析查询可将延迟控制在亚秒到秒级,满足交互式 BI 和数据探索的需求。


