Delta外表(XIHE SQL)
AnalyticDB for MySQL的XIHE引擎支持通过外部表(EXTERNAL TABLE)方式查询OSS上已有的Apache Delta Lake表。注册外部表后,您可以使用标准SQL查询Delta表的最新快照数据,并利用分区裁剪和列裁剪优化查询性能。本文介绍通过XIHE SQL查询Delta表的方法。
XIHE引擎当前仅支持查询已有Delta Lake表,不支持通过XIHE SQL写入Delta表。如需对Delta表执行写入操作,请使用Spark SQL引擎,详见读写Delta外表。
支持能力概览
能力 | 支持状态 |
查询已有Delta表 | 支持 |
Delta reader v1 / v3表 | 支持 |
Parquet数据文件 | 支持 |
列裁剪 | 支持 |
复杂类型读取(ARRAY / MAP) | 支持 |
分区表读取 | 支持 |
分区裁剪 | 支持 |
Delta log统计信息 | 支持 |
Deletion Vector读取 | 支持 |
JOIN / 聚合 / 排序 | 支持 |
INSERT / UPDATE / DELETE / MERGE | 不支持 |
前提条件
集群的产品系列为企业版、基础版或湖仓版。
集群的内核版本为3.2.8及以上版本。
已创建外部数据库。创建方法请参见CREATE EXTERNAL DATABASE。
OSS上已存在由Spark、Flink或Databricks等引擎创建的Delta表目录(包含
_delta_log)。
建表
语法
CREATE EXTERNAL TABLE [IF NOT EXISTS] <db>.<table> (
<col1> <type1>,
<col2> <type2>,
...
)
STORED AS DELTA
LOCATION '<delta_table_location>';子句 | 必填 | 说明 |
| 是 | 声明外部表格式为Delta Lake。 |
| 是 | Delta表根目录的OSS路径(包含 |
当LOCATION指向的目录下已经存在非空_delta_log时,外表注册后会从_delta_log读取真实Schema和文件列表。DDL中的字段建议与底层Delta Schema保持一致,便于元数据展示和问题排查;最终查询Schema以_delta_log为准,类型不匹配可能导致查询失败。注册成功后,可使用DESCRIBE查看实际读取到的Delta Schema。
建表示例
-- 创建外部数据库
CREATE EXTERNAL DATABASE IF NOT EXISTS ext_delta_db;
-- 注册Delta外部表
CREATE EXTERNAL TABLE ext_delta_db.delta_orders (
order_id BIGINT,
user_id BIGINT,
order_status STRING,
total_price DECIMAL(18, 2),
order_date DATE
)
STORED AS DELTA
LOCATION 'oss://<YOUR-BUCKET>/warehouse/delta_orders/';其他DDL操作
-- 查看列结构
DESCRIBE ext_delta_db.delta_orders;
-- 删除外部表
DROP TABLE IF EXISTS ext_delta_db.delta_orders;DROP TABLE仅删除AnalyticDB中的外部表定义,不删除OSS上的Delta表目录和数据文件。
查询数据
基本查询
查询时默认读取最新快照(Snapshot),保证一次查询中数据一致性。
-- 查询全表
SELECT * FROM ext_delta_db.delta_orders LIMIT 10;
-- 聚合查询
SELECT order_status, COUNT(*) AS order_count, SUM(total_price) AS total
FROM ext_delta_db.delta_orders
GROUP BY order_status;
-- 条件过滤
SELECT order_id, order_status, total_price
FROM ext_delta_db.delta_orders
WHERE order_status IN ('PAID', 'SHIPPED') AND total_price >= 100
ORDER BY total_price DESC;分区裁剪
Delta表的分区信息来自_delta_log中的元数据和AddFile记录。对分区列添加过滤条件时,引擎基于Delta log中的partition values自动裁剪不相关的分区,减少需要扫描的数据文件:
-- 单值过滤
SELECT * FROM ext_delta_db.delta_orders
WHERE order_date = DATE '2026-06-11';
-- 范围过滤
SELECT order_date, COUNT(*) AS cnt, SUM(total_price) AS total
FROM ext_delta_db.delta_orders
WHERE order_date >= DATE '2026-06-01' AND order_date < DATE '2026-07-01'
GROUP BY order_date;注册外部表时不需要在DDL中声明PARTITIONED BY,分区信息自动从_delta_log读取。
当前分区裁剪主要覆盖布尔、整数、浮点、字符串、二进制、日期和时间戳等常见分区列类型。Decimal分区列可以读取,但作为过滤条件时不建议依赖分区裁剪。
列裁剪与谓词下推
读取Parquet文件时,引擎只请求查询需要的列;对于结构化字段,符合条件的子字段也可以进入Parquet读取路径。查询规划时会保留未完全下推的普通列过滤条件,由执行引擎继续过滤结果。
-- 仅读取order_id和total_price两列
SELECT order_id, total_price
FROM ext_delta_db.delta_orders
WHERE total_price BETWEEN 100 AND 500;统计信息
当Delta log中包含文件级统计信息时,Delta外表可以读取numRecords、min/max、nullCount等信息,用于优化器的行数和列统计估算。
如果Delta log中没有统计信息,或者文件数量超过统计扫描限制,统计信息可能退化为未知或基于文件大小估算。该能力影响执行计划选择,不改变查询结果语义。
JOIN与聚合
Delta外表可以参与标准XIHE SQL查询,包括JOIN、聚合、排序和窗口函数。JOIN策略由XIHE查询优化器决定。
-- Delta外表与其他表JOIN
SELECT o.order_id, o.total_price, u.user_name
FROM ext_delta_db.delta_orders o
JOIN dim_db.users u ON o.user_id = u.user_id
WHERE o.order_date = DATE '2026-06-11';支持的数据类型
Delta类型 | 查询侧类型 | 说明 |
BOOLEAN |
| 布尔类型 |
BYTE / SHORT / INTEGER / LONG |
| 整数类型 |
FLOAT / DOUBLE |
| 浮点类型 |
DECIMAL |
| 定点数 |
STRING |
| 字符串类型 |
BINARY |
| 二进制 |
DATE |
| 日期 |
TIMESTAMP / TIMESTAMP_NTZ |
| 时间戳。TIMESTAMP_NTZ(无时区)按 |
ARRAY |
| 数组 |
MAP |
| 映射 |
使用限制
Delta外表以查询已有Delta表为主,表结构、分区和快照由
_delta_log维护。当前仅支持查询已有Delta表,不支持通过XIHE SQL执行
INSERT、UPDATE、DELETE和MERGE操作。仅支持底层数据格式为Parquet的Delta表,非Parquet格式不支持。
支持读取启用了Deletion Vector的Delta表,查询时自动应用删除标记。
LOCATION必须指向Delta表根目录(包含_delta_log的目录),不能指向_delta_log目录本身或分区子目录。外部表DDL中的字段建议与底层Delta Schema保持一致。最终查询Schema以
_delta_log为准,类型不匹配可能导致查询失败。DROP TABLE仅删除AnalyticDB中的外部表定义,不删除OSS上的Delta表目录和数据文件。ALTER TABLE仅修改AnalyticDB中的外部表定义,不影响底层Delta Schema。查询Schema始终以_delta_log为准。如需变更Delta Schema,请在上游生产链路中完成。Decimal类型的分区列可以读取,但作为过滤条件时分区裁剪效果可能有限。
当前不支持通过外表DDL创建新的Delta分区表;已有分区表可以读取和分区裁剪。
复杂类型(ARRAY、MAP)可以读取;复杂类型上的复杂过滤条件通常由执行引擎完成过滤。
如果Delta log Schema与底层Parquet文件Schema不一致,查询阶段可能报Schema mismatch错误。
分区值来自Delta log的字符串表示,分区列类型不符合预期时可能在分区值转换阶段报错。