跳到主要内容
最后于 更新

Hive Catalog

通过连接 Hive Metastore,或者兼容 Hive Metatore 的元数据服务,Doris 可以自动获取 Hive 的库表信息,并进行数据查询。

除了 Hive 外,很多其他系统也会使用 Hive Metastore 存储元数据。所以通过 Hive Catalog,我们不仅能访问 Hive 表,也能访问使用 Hive Metastore 作为元数据存储的其他表格式,如 Iceberg、Hudi 等。

适用场景​

场景说明
查询加速利用 Doris 分布式计算引擎,直接访问 Hive 数据进行查询加速。
数据集成读取 Hive 数据并写入到 Doris 内表。或通过 Doris 计算引擎进行 ZeroETL 操作。
数据写回将任意 Doris 支持读取的数据源数据进行加工后,写回到 Hive 表存储。

配置 Catalog​

语法​

CREATE CATALOG [IF NOT EXISTS] catalog_name PROPERTIES (
'type'='hms', -- required
'hive.metastore.type' = '<hive_metastore_type>', -- optional
'hive.version' = '<hive_version>', -- optional
'fs.defaultFS' = '<fs_defaultfs>', -- 写入必填,只读时可选
{MetaStoreProperties},
{StorageProperties},
{HiveProperties},
{CommonProperties}
);
  • <hive_metastore_type>

    指定 Hive Metastore 的类型。

    • hms:标准的 Hive Metastore 服务。

    • glue:使用 Hive Metastore 兼容接口访问 AWS Glue 元数据服务。

    • dlf:使用 Hive Metastore 兼容接口访问阿里云 DLF 元数据服务。

  • <fs_defaultfs>

    当需要通过 Doris 写入数据到这个 Hive Catalog 中表时,此参数为必选项。示例:

    'fs.defaultFS' = 'hdfs://namenode:port'

  • {MetaStoreProperties}

    MetaStoreProperties 部分用于填写 Metastore 元数据服务连接和认证信息。具体可参阅【支持的元数据服务】部分。

  • {StorageProperties}

    StorageProperties 部分用于填写存储系统相关的连接和认证信息。具体可参阅【支持的存储系统】部分。

  • {HiveProperties}

    HiveProperties 部分用于填写和 Hive Catalog 相关的其他参数。

    • get_schema_from_table:默认为 false。默认情况下,Doris 会从 Hive Metastore 中获取表的 Schema 信息。但某些情况下可能出现兼容问题,如错误 Storage schema reading not supported。此时可以将这个参数设置为 true,则会从 Table 对象中直接获取表 Schema。但注意,该方式会导致列的默认值信息被忽略。该参数自 2.1.10 和 3.0.6 版本支持。

    • hive.recursive_directories:在 list 分区目录时,是否递归子目录。该参数自 3.0.2 版本支持。在 4.0 版本之前,该参数默认值为 false,之后的版本,该默认值为 true。某些 Hive 外表的分区路径可能和表结构中的分区信息不匹配,需要将这个参数设为 true 以便获取子目录下的数据文件。

    • hive.ignore_absent_partitions:是否忽略不存在的分区。默认为 true。如果设为 false,当遇到不存在的分区时,查询会报错。该参数自 3.0.2 版本支持。

    • hive.staging_dir:用于设置 Hive 写操作的临时 staging 根目录。写入过程中数据会先写入该目录,写入完成后再移动到最终的 Hive 表目录。该路径可以是相对于 Hive 表根目录的相对路径,也可以是绝对路径。默认值为 /tmp/.doris_staging。某些情况下,写入 Hive 表时会遇到 /tmp 目录和表目录分属不同 namespace,导致无法写入的问题,此时可以通过修改此参数,使用相对路径解决该问题。该参数自 4.0.3 版本开始支持。

    • hive.parquet.time-zone:FileScannerV2 读取 Hive 表时,用于还原旧版 Parquet INT96 时间戳的兼容时区。默认值为空,此时 Doris 保留 INT96 中存储的日期和时间字段,不做时区转换。仅当 Catalog 中的 INT96 文件由写入端按已知时区进行过归一化时,才需要设置此属性。Hudi 表会有意忽略该属性,并保留现有的 SQL 会话时区行为。详情请参阅 Parquet INT96 时间戳兼容性。

  • {CommonProperties}

    CommonProperties 部分用于填写通用属性。请参阅 数据目录概述 中【通用属性】部分。

元数据缓存​

为了提升访问外部数据源的性能,Apache Doris 会缓存 Hive 的元数据,包括表对象、分区名、分区对象、列统计信息、文件列表以及派生的分区裁剪结构。

提示

Doris 4.1.x 之前的版本,元数据缓存主要由 FE 配置项全局控制,详见元数据缓存。 自 Doris 4.1.x 起,Hive Catalog 的外表元数据缓存使用统一的 meta.cache.* 键配置。下文的模块描述当前版本;Doris 4.1.x 和 4.2.x 的模块集合与此不同,见本页的 4.x 版本。

缓存属性配置​

每个缓存模块使用统一的配置键格式:meta.cache.<engine>.<entry>.{enable,ttl-second,capacity,max-weight}。Hive 的 <engine> 为 hive。包含 Iceberg 表的 Hive Metastore Catalog 还会使用 Iceberg Catalog 中描述的 iceberg 模块。

属性示例含义
enabletrue/false是否开启该缓存模块。
ttl-second600、0、-10 表示关闭该模块(立即生效,可用于查看最新数据);-1 表示永不过期;其他正整数表示按访问时间计算的 TTL 秒数。
capacity10000缓存条目数上限。0 表示关闭该模块。
max-weight1GB自 Doris 4.1.4 起支持。可选的模块估算保留内存上限。必须为正数,0 会被拒绝。只有下表标注的模块接受该属性。

生效逻辑: 模块在 enable=true、ttl-second != 0 且 capacity > 0 时生效。FE 总上限、Catalog 上限或模块上限存在时,还会按估算内存控制准入,详见 外表元数据缓存内存管理。

缓存模块​

Hive Catalog 包含以下缓存模块,全部接受 max-weight。

模块(<entry>)属性键前缀ENTRY_NAME缓存内容与影响默认 enable / TTL / capacity
tablemeta.cache.hive.table.hive-tableHive Metastore 中的表对象。影响:减少规划阶段访问 Metastore 的次数。true / 86400 秒 / 10000
partition_namesmeta.cache.hive.partition_names.hive-partition-names分区名列表。影响:分区枚举;关闭后可实时看到新分区。true / 86400 秒 / 10000
partitionmeta.cache.hive.partition.hive-partition分区对象,例如 Location 和输入格式。true / 86400 秒 / 100000
column_statsmeta.cache.hive.column_stats.hive-column-statsHive Metastore 中的列统计信息。true / 86400 秒 / 10000
filemeta.cache.hive.file.hive-file文件列表。影响:减少远端 LIST 操作;关闭后可实时看到文件变化。true / 86400 秒 / 10000
partition_viewmeta.cache.hive.partition_view.hive-partition-view由分区名派生的分区裁剪结构。true / 86400 秒 / 1000

Hive 表的列结构由所有外表 Catalog 共享的 default 引擎缓存(meta.cache.default.schema.*)。

旧参数映射与转换​

推荐使用统一键。以下旧 Catalog 属性仍然可用,并按下表映射:

旧属性键统一键说明
schema.cache.ttl-secondmeta.cache.default.schema.ttl-second 和 meta.cache.hive.table.ttl-second表结构缓存和表对象缓存的过期时间
partition.cache.ttl-secondmeta.cache.hive.partition_names.ttl-second分区名列表的过期时间
file.meta.cache.ttl-secondmeta.cache.hive.file.ttl-second文件列表的过期时间

最佳实践​

  • 实时访问最新数据:希望每次查询都看到外部数据源最新的分区或文件变化时,将对应模块的 ttl-second 设为 0。
    -- 关闭文件列表缓存,实时看到文件变化
    ALTER CATALOG hive_ctl SET PROPERTIES ("meta.cache.hive.file.ttl-second" = "0");
    -- 关闭分区名缓存,实时看到新分区
    ALTER CATALOG hive_ctl SET PROPERTIES ("meta.cache.hive.partition_names.ttl-second" = "0");
  • 性能优化:元数据变化不频繁的场景,可适当增大 capacity 和 ttl-second,减少对 Hive Metastore 和文件系统的访问压力。对超大表可用 max-weight 限制文件列表和分区裁剪缓存的内存。
警告

Catalog 属性修改成功后,受影响的元数据缓存会被丢弃,并在下一次访问时按新配置重建。修改 meta.cache.max-weight 或 schema.cache.ttl-second 会丢弃该 Catalog 的全部缓存;修改 meta.cache.<engine>.<entry>.* 只丢弃对应引擎的缓存。正在执行的查询不受影响。

可观测性​

可以通过 information_schema.catalog_meta_cache_statistics 系统表观察缓存指标。ENTRY_NAME 显示上表中列出的名称,default 引擎的行是所有 Catalog 共享的表结构缓存:

SELECT engine_name, entry_name,
effective_enabled, ttl_second, capacity,
estimated_size, hit_rate, max_weight, estimated_weight
FROM information_schema.catalog_meta_cache_statistics
WHERE catalog_name = 'hive_ctl'
ORDER BY engine_name, entry_name;

系统表说明请参阅 catalog_meta_cache_statistics。

支持的 Hive 版本​

支持 Hive 1.x,2.x,3.x,4.x。

其中 Hive 事务表支持 3.x 之后的版本,详情参阅【Hive 事务表】章节。

支持的元数据服务​

注意:不同 Doris 版本所支持的服务类型和参数略有区别,请参考【基础示例】章节。

Hive Catalog 功能支持矩阵​

元数据服务表查询视图查询DDL 操作数据写回
Hive✅✅✅✅
AWS Glue✅✅❌❌
DLF✅✅✅✅

支持的存储系统​

如果需要通过 Doris 创建 Hive 表并写入数据,需要在 Catalog 属性中显式增加 fs.defaultFS 属性。如果创建 Catalog 仅用于查询,则该参数可以省略。

不同 Doris 版本所支持的服务类型和参数略有区别,请参考【基础示例】章节。

支持的数据格式​

Parquet INT96 时间戳兼容性​

Hive 表中的时间戳文件可能由不同引擎生成。是否需要时区转换取决于物理编码和写入端行为。Parquet INT96 本身不包含时区标注,因此 Doris 不会根据 INT96 值推断写入端时区。

Parquet INT96 时间戳​

FileScannerV2 按以下规则处理 Parquet 时间戳:

物理编码默认行为hive.parquet.time-zone 的作用
映射到 DATETIMEV2 的 INT96保留文件中存储的日期和时间字段,SQL 会话时区不会使该值发生偏移。将原始 INT96 值视为 UTC 时刻,再转换到配置的兼容时区,从而还原被旧版写入端归一化过的时间戳。
带时间戳逻辑类型的 INT64遵循 Parquet 逻辑类型语义。不受影响。

例如,假设预期的本地时间戳是 Asia/Shanghai 时区的 2021-01-01 10:11:00:

  • 如果文件直接存储墙上时间字段 10:11:00,请不要设置 hive.parquet.time-zone。即使 SQL 会话使用 Asia/Shanghai,Doris 仍返回 10:11:00。
  • 如果旧版写入端先将该值归一化为 UTC 再写入 INT96,文件中可能存储 02:11:00。将 hive.parquet.time-zone 设置为 Asia/Shanghai 后,Doris 会还原出 10:11:00。

创建 Catalog 时配置兼容时区:

CREATE CATALOG hive_legacy_int96 PROPERTIES (
'type' = 'hms',
'hive.metastore.uris' = 'thrift://127.0.0.1:9083',
'hive.parquet.time-zone' = 'Asia/Shanghai'
);

该值可以是 Asia/Shanghai 等 IANA 时区名称,也可以是 -12:00 到 +14:00 范围内的 UTC 偏移。非法值会导致 Catalog 创建失败。

警告

hive.parquet.time-zone 作用于该 Catalog 中所有 Hive 表内映射到 DATETIMEV2 的 INT96 时间戳列。该属性不影响同一 Hive Metastore 中的 Iceberg 表,因为 Iceberg 定义了自己的时间戳语义。Hudi 也会有意忽略该属性:原生 base file 扫描和 JNI merge-on-read 扫描都保留变更前的行为,使用 SQL 会话时区解释时间戳。Parquet 元数据无法可靠地告诉 Doris 某个 INT96 写入端使用了哪种约定。不要仅为了匹配 SQL 会话时区而设置此属性。如果同一个 Hive Metastore 中的 Hive 表包含使用不同约定写入的 INT96 文件,应尽量通过不同 Catalog 分别访问。

读取 Parquet 文件的文件表值函数也接受同名属性。该兼容转换仅影响 FileScannerV2 对 Parquet INT96 的解码。FileScannerV1 有意保持不变,可能返回不同结果;切换到 FileScannerV1 不是本次变更的兼容方案。Parquet INT64 逻辑时间戳不受影响。INT96 列映射到 TIMESTAMPTZ 时,Doris 会忽略该属性并保留 UTC 时刻;该值的显示仍遵循 TIMESTAMPTZ 和会话时区语义。

迁移建议​

  • Doris 默认写入带逻辑类型的 Parquet INT64 时间戳。仅当 Hive 2、Hive 3 等旧版读取端要求 INT96 时,才设置 enable_int96_timestamps = true。
  • 升级到采用此 FileScannerV2 行为的版本前,请先检查现有 Hive 表。包含由旧版写入端归一化过的 INT96 文件时,升级后返回的墙上时间可能发生变化。请比对有代表性的已知值,并在需要转换时将 hive.parquet.time-zone 设置为写入端时区。Hudi 保留现有的会话时区行为,因此不需要针对本次变更执行迁移。
  • 设置 hive.parquet.time-zone 前,请检查有代表性的文件并与已知时间戳值进行比对。不必要的配置反而会产生原本希望消除的时间偏移。
  • 对使用不同 INT96 写入约定的文件,使用不同 Catalog 分别访问,或将文件重写为统一的 INT64 编码。
  • Doris 通过 enable_int96_timestamps = true 显式导出 INT96 时,会使用导出会话时区归一化时间戳。通过 FileScannerV2 读回该文件时,请将 hive.parquet.time-zone 设置为相同的导出会话时区。详情请参阅数据导出概述。

列类型映射​

Hive TypeDoris TypeComment
booleanboolean
tinyinttinyint
smallintsmallint
intint
bigintbigint
datedate
timestampdatetime(6)固定映射到精度为 6 的 datetime
floatfloat
doubledouble
decimal(P, S)decimal(P, S)如果未指定精度,默认为 decimal(9, 0)
char(N)char(N)
varchar(N)varchar(N)
stringstring
binarystring/varbinary由 properties 中 enable.mapping.varbinary (4.0.2 后开始支持) 属性控制。默认为 false, 则映射到 string; 为 true 时,则映射到 varbinary 类型。
timestamp with local time zonedatetime/timestamptz由 properties 中 enable.mapping.timestamp_tz (4.0.3 后开始支持) 属性控制,默认为 false, 则映射到 datetime; 为 true 时,则映射到 timestamptz 类型
arrayarray
mapmap
structstruct
otherunsupported

基础示例​

Hive Metastore​

3.1+ 版本

访问未开启 Kerberos 认证的 HMS 和 HDFS 服务

CREATE CATALOG hive_hms_hdfs_test_catalog PROPERTIES (
'type' = 'hms',
'hive.metastore.uris' = 'thrift://127.0.0.1:9383',
'fs.defaultFS' = 'hdfs://127.0.0.1:8520',
'hadoop.username' = 'doris'
);

访问开启 Kerberos 认证的 HMS 和 HDFS 服务

CREATE CATALOG hive_hms_hdfs_kerberos_test_catalog PROPERTIES (
'type' = 'hms',
'hive.metastore.uris' = 'thrift://127.0.0.1:9583',
'hive.metastore.client.principal' = 'hive/presto-master.docker.cluster@LABS.TERADATA.COM',
'hive.metastore.client.keytab' = '/keytabs/hive-presto-master.keytab',
'hive.metastore.service.principal' = 'hive/hadoop-master@LABS.TERADATA.COM',
'hive.metastore.sasl.enabled' = 'true',
'hive.metastore.authentication.type' = 'kerberos',
'fs.defaultFS' = 'hdfs://127.0.0.1:8520',
'hadoop.security.auth_to_local' = 'RULE:[2:\$1@\$0](.*@LABS.TERADATA.COM)s/@.*//
RULE:[2:\$1@\$0](.*@OTHERLABS.TERADATA.COM)s/@.*//
RULE:[2:\$1@\$0](.*@OTHERREALM.COM)s/@.*//
DEFAULT',
'hadoop.security.authentication' = 'kerberos',
'hadoop.kerberos.principal' = 'hive/presto-master.docker.cluster@LABS.TERADATA.COM',
'hadoop.kerberos.keytab' = '/keytabs/hive-presto-master.keytab'
);
2.1 & 3.0 版本

访问未开启 Kerberos 认证的 HMS

CREATE CATALOG hive_hms_hdfs_test_catalog PROPERTIES (
'type' = 'hms',
'hive.metastore.uris' = 'thrift://127.0.0.1:9383',
'hadoop.username' = 'doris',
'fs.defaultFS' = 'hdfs://127.0.0.1:8320'
);

访问开启 Kerberos 认证的 HMS

CREATE CATALOG test_two_hive_kerberos PROPERTIES (
'type' = 'hms',
'hive.metastore.uris' = 'thrift://127.0.0.1:9583',
'hive.metastore.sasl.enabled' = 'true',
'hive.metastore.kerberos.principal' = 'hive/hadoop-master@LABS.TERADATA.COM',
'fs.defaultFS' = 'hdfs://127.0.0.1:8520',
'hadoop.kerberos.min.seconds.before.relogin' = '5',
'hadoop.security.authentication' = 'kerberos',
'hadoop.kerberos.principal' = 'hive/presto-master.docker.cluster@LABS.TERADATA.COM',
'hadoop.kerberos.keytab' = '/keytabs/hive-presto-master.keytab',
'hadoop.security.auth_to_local' = 'RULE:[2:\$1@\$0](.*@LABS.TERADATA.COM)s/@.*//
RULE:[2:\$1@\$0](.*@OTHERLABS.TERADATA.COM)s/@.*//
RULE:[2:\$1@\$0](.*@OTHERREALM.COM)s/@.*//
DEFAULT'
);

AWS Glue​

3.1+ 版本

AWS Glue 和 S3 存储服务共用一套认证信息。

CREATE CATALOG hive_glue_on_s3_catalog PROPERTIES (
'type' = 'hms',
'hive.metastore.type' = 'glue',
'glue.region' = 'ap-east-1',
'glue.endpoint' = 'https://glue.ap-east-1.amazonaws.com',
'glue.access_key' = '<ak>',
'glue.secret_key' = '<sk>'
);

Glue 服务的认证信息和 S3 的认证信息不一致时,可以通过以下方式单独指定 S3 的认证信息。

CREATE CATALOG hive_glue_on_s3_catalog PROPERTIES (
'type' = 'hms',
'hive.metastore.type' = 'glue',
'glue.region' = 'ap-east-1',
'glue.endpoint' = 'https://glue.ap-east-1.amazonaws.com',
'glue.access_key' = '<ak>',
'glue.secret_key' = '<sk>',
's3.region' = 'ap-east-1',
's3.endpoint' = 'https://s3.ap-east-1.amazonaws.com/',
's3.access_key' = '<ak>',
's3.secret_key' = '<sk>'
);

使用 IAM Assumed Role 的方式获取 S3 访问凭证 (3.1.2+ 支持)

CREATE CATALOG `glue_hive_iamrole` PROPERTIES ( 
'type' = 'hms',
'hive.metastore.type' = 'glue',
'glue.region' = 'us-east-1',
'glue.endpoint' = 'https://glue.us-east-1.amazonaws.com',
'glue.role_arn' = '<role_arn>'
);
2.1 & 3.0 版本

非 EC2 环境下,需要使用 aws configure 配置 Credentials 信息,同时在~/.aws 目录下生成 credentials 文件。

或者显示的在创建 catalog 参数中新增凭据提供方式 "aws.catalog.credentials.provider.factory.class"="com.amazonaws.glue.catalog.credentials.ConfigurationAWSCredentialsProviderFactory"

create catalog hive_glue PROPERTIES(
'type' = 'hms',
'hive.metastore.type' = 'glue',
'glue.endpoint' = 'https://glue.ap-northeast-1.amazonaws.com',
'glue.region' = 'ap-northeast-1',
'glue.access_key' = '<ak>',
'glue.secret_key' = '<sk>'
);

Aliyun DLF​

3.1+ 版本
CREATE CATALOG hive_dlf_oss_test_catalog PROPERTIES (
'type' = 'hms',
'hive.metastore.type' = 'dlf',
'dlf.uid' = '203225413946383283',
'dlf.catalog_id' = 'p2_regression_case',
'dlf.endpoint' = 'dlf.cn-beijing.aliyuncs.com',
'dlf.region' = 'cn-beijing',
'dlf.access_key' = '<ak>',
'dlf.secret_key' = '<sk>'
);
2.1 & 3.0 版本
CREATE CATALOG hive_dlf_oss_test_catalog PROPERTIES (
'type' = 'hms',
'hive.metastore.type' = 'dlf',
'dlf.uid' = '203225413946383283',
'dlf.catalog.id' = 'p2_regression_case',
'dlf.endpoint' = 'dlf.cn-beijing.aliyuncs.com',
'dlf.region' = 'cn-beijing',
'dlf.access_key' = '<ak>',
'dlf.secret_key' = '<sk>'
);

查询操作​

基础查询​

配置好 Catalog 后,可以通过以下方式查询 Catalog 中的表数据:

-- 1. switch to catalog, use database and query
SWITCH hive_ctl;
USE hive_db;
SELECT * FROM hive_tbl LIMIT 10;

-- 2. use hive database directly
USE hive_ctl.hive_db;
SELECT * FROM hive_tbl LIMIT 10;

-- 3. use full qualified name to query
SELECT * FROM hive_ctl.hive_db.hive_tbl LIMIT 10;

查询 Hive 分区​

可以通过下面两种方式查询 Hive 分区信息。

  • SHOW PARTITIONS FROM [catalog.][db.]hive_table

    该语句可以列出指定 Hive 表的所有分区以及分区值信息。

    SHOW PARTITIONS FROM hive_table;

    +--------------------------------+
    | Partition |
    +--------------------------------+
    | pt1=2024-10-10/pt2=beijing |
    | pt1=2024-10-10/pt2=shanghai |
    | pt1=2024-10-11/pt2=beijing |
    | pt1=2024-10-11/pt2=shanghai |
    | pt1=2024-10-12/pt2=nanjing |
    +--------------------------------+
  • 使用 table$partitions 元数据表

    自 2.1.7 和 3.0.3 版本开始,用户可以通过 table$partitions 元数据表查询 Hive 分区信息。table$partitions 本质上是一个关系表,每个分区列为一列,所以可以使用在任意 SELECT 语句中。

    SELECT * FROM hive_table$partitions;

    +------------+-------------+
    | pt1 | pt2 |
    +------------+-------------+
    | 2024-10-10 | beijing |
    | 2024-10-10 | shanghai |
    | 2024-10-12 | nanjing |
    | 2024-10-11 | beijing |
    | 2024-10-11 | shanghai |
    +------------+-------------+
版本行为变更(4.1.4)

自 4.1.4 版本起,Hive 目录式分区中的默认分区标记 __HIVE_DEFAULT_PARTITION__ 会被解析为真正的 NULL 值,而不再编码为字符串 \N。同时,分区路径中真实存储的字符串 \N 会被原样保留为数据。

4.1.4 之前这两种情况无法区分,查询结果中都会显示为 \N。升级后,WHERE <partition_col> IS NULL 才能正确匹配 Hive 默认分区。

查询 Hive 事务表​

Hive Transactional 表是 Hive 中支持 ACID 语义的表。详情可见 Hive Transactions。

  • Hive Transactional 表支持情况

    表类型在 Hive 中支持的操作Hive 表属性支持的 Hive 版本
    Full-ACID Transactional Table支持 Insert, Update, Delete 操作'transactional'='true'4.x,3.x,2.x,其中 2.x 需要在 Hive 中执行完 Major Compaction 才可以读取。
    Insert-Only Transactional Table只支持 Insert 操作'transactional'='true','transactional_properties'='insert_only'4.x,3.x,2.x 在创建 catalog 的时候需要指定 hive.version。
  • 当前限制

    目前不支持 Original Files 的场景。当一个表转换成 Transactional 表之后,后续新写的数据文件会使用 Hive Transactional 表的 Schema,但是已经存在的数据文件是不会转化成 Transactional 表的 Schema,这样的文件称为 Original Files。

查询 Hive View​

支持查询 Hive View。但注意有以下限制:

  • Hive View 的定义语句(HiveQL)必须是 Doris 支持的 SQL 语句。否则会出现解析错误。

  • 部分 HiveQL 支持的函数可能和 Doris 支持的函数同名,但行为不一致,这可能导致最终结果和使用 Hive 查询的结果不一致。如果用户遇到此类问题,可以向社区反馈。

相关参数​

  • Session 变量

    参数名称描述默认值版本
    hive_parquet_use_column_namestrueDoris 在读取 Hive 表 Parquet 数据类型时,默认会根据 Hive 表的列名从 Parquet 文件中找同名的列来读取数据。当该变量为 false 时,Doris 会根据 Hive 表中的列顺序从 Parquet 文件中读取数据,与列名无关。类似于 Hive 中的 parquet.column.index.access 变量。该参数只适用于顶层列名,对 Struct 内部无效。2.1.6+, 3.0.3+
    hive_orc_use_column_namestrue与 hive_parquet_use_column_names 类似,针对的是 Hive 表 ORC 数据类型。类似于 Hive 中的 orc.force.positional.evolution 变量。2.1.6+, 3.0.3+

写入操作​

可以通过 INSERT 语句将数据写入到 Hive 表中。支持写入到由 Doris 创建的 Hive 表,或者 Hive 中已存在的且格式支持的表。

对于分区表,会根据数据,自动写入到对应分区,或者创建新的分区。目前不支持指定分区写入。

INSERT INTO​

INSERT 操作会将数据以追加的方式写入到目标表中。

INSERT INTO hive_tbl VALUES (val1, val2, val3, val4);
INSERT INTO hive_ctl.hive_db.hive_tbl SELECT col1, col2 FROM internal.db1.tbl1;

INSERT INTO hive_tbl(col1, col2) VALUES (val1, val2);
INSERT INTO hive_tbl(col1, col2, partition_col1, partition_col2) VALUES (1, 2, "beijing", "2023-12-12");

自 4.2.0 版本,支持写入数据到静态分区,或者静态分区和动态分区混合使用:

-- Full Static Partition
INSERT INTO hive_tbl PARTITION (partition_col1='2026-07-30', partition_col2='beijing')
VALUES (val1, val2);
INSERT INTO hive_tbl PARTITION (partition_col1='2026-07-30', partition_col2='beijing')
SELECT col1, col2 FROM source_table;

-- Hybrid Partition Mode: "partition_col1" is static, "partition_col2" comes from SELECT dynamically
INSERT INTO hive_tbl PARTITION (partition_col1='2026-07-30')
VALUES (val1, val2, partition_val2);
INSERT INTO hive_tbl PARTITION (partition_col1='2026-07-30')
SELECT col1, col2, partition_col2 FROM source_table;

INSERT OVERWRITE​

INSERT OVERWRITE 会使用新的数据完全覆盖原有表中的数据。

INSERT OVERWRITE TABLE VALUES(val1, val2, val3, val4);
INSERT OVERWRITE TABLE hive_ctl.hive_db.hive_tbl(col1, col2) SELECT col1, col2 FROM internal.db1.tbl1;

自 4.2.0 版本,支持写入数据到静态分区,或者静态分区和动态分区混合使用:

-- Full Static Partition
INSERT OVERWRITE TABLE hive_tbl PARTITION (partition_col1='2026-07-30', partition_col2='beijing')
VALUES (val1, val2);
INSERT OVERWRITE TABLE hive_tbl PARTITION (partition_col1='2026-07-30', partition_col2='beijing')
SELECT col1, col2 FROM source_table;

-- Hybrid Partition Mode: "partition_col1" is static, "partition_col2" comes from SELECT dynamically
INSERT OVERWRITE TABLE hive_tbl PARTITION (partition_col1='2026-07-30')
VALUES (val1, val2, partition_val2);
INSERT OVERWRITE TABLE hive_tbl PARTITION (partition_col1='2026-07-30')
SELECT col1, col2, partition_col2 FROM source_table;

INSERT OVERWRITE 的语义与 Hive 一致,有如下行为:

  • 当目的表是分区表,而源表为空表时,操作不会产生任何影响。目的表数据无变化。

  • 当目的表是非分区表,而源表是空表是,目的表会被清空。

  • 自 4.2.0 版本开始,支持指定分区写入,以及指定分区和动态分区混合使用。但是即便指定了静态分区,如果查询内容为空,则指定的分区也不会被清理。

CTAS​

可以通过 CTAS(CREATE TABLE AS SELECT) 语句创建 Hive 表并写入数据:

CREATE TABLE hive_ctas ENGINE=hive AS SELECT * FROM other_table;

CTAS 支持指定文件格式、分区方式等信息,如:

CREATE TABLE hive_ctas ENGINE=hive
PARTITION BY LIST (pt1, pt2) ()
AS SELECT col1,pt1,pt2 FROM part_ctas_src WHERE col1>0;

CREATE TABLE hive_ctl.hive_db.hive_ctas (col1,col2,pt1) ENGINE=hive
PARTITION BY LIST (pt1) ()
PROPERTIES (
"file_format"="parquet",
"compression"="zstd"
)
AS SELECT col1,pt1 as col2,pt2 as pt1 FROM test_ctas.part_ctas_src WHERE col1>0;

相关参数​

  • BE 配置

    参数名称描述默认值
    hive_sink_max_file_size最大的数据文件大小。当写入数据量超过该大小后会关闭当前文件,滚动产生一个新文件继续写入。1GB
    table_sink_partition_write_max_partition_nums_per_writerBE 节点上每个 Instance 最大写入的分区数目。128
    table_sink_non_partition_write_scaling_data_processed_threshold非分区表开始 scaling-write 的数据量阈值。每增加 table_sink_non_partition_write_scaling_data_processed_threshold 数据就会发送给一个新的 writer(instance) 进行写入。scaling-write 机制主要是为了根据数据量来使用不同数目的 writer(instance) 来进行写入,会随着数据量的增加而增大写入的 writer(instance) 数目,从而提高并发写入的吞吐。当数据量比较少的时候也会节省资源,并且尽可能地减少产生的文件数目。25MB
    table_sink_partition_write_min_data_processed_rebalance_threshold分区表开始触发重平衡的最少数据量阈值。如果 当前累积的数据量 - 自从上次触发重平衡或者最开始累积的数据量 >= table_sink_partition_write_min_data_processed_rebalance_threshold,就开始触发重平衡机制。如果发现最终生成的文件大小差异过大,可以调小改阈值来增加均衡度。当然过小的阈值会导致重平衡的成本增加,可能会影响性能。25MB
    table_sink_partition_write_min_partition_data_processed_rebalance_threshold分区表开始进行重平衡时的最少的分区数据量阈值。如果 当前分区的数据量 >= 阈值 * 当前分区已经分配的 task 数目,就开始对该分区进行重平衡。如果发现最终生成的文件大小差异过大,可以调小改阈值来增加均衡度。当然过小的阈值会导致重平衡的成本增加,可能会影响性能。15MB

库表管理​

用户可以通过 Doris 在 Hive Metastore 中创建、删除库表。注意,Doris 只是调用 Hive Metastore 的 API 进行相应操作,Doris 本身的元数据并不存储和持久化任何 Hive 的元数据。

创建和删除库​

可以通过 SWITCH 语句切换到对应的 Catalog 下,执行 CREATE DATABASE 语句:

SWITCH hive_ctl;
CREATE DATABASE [IF NOT EXISTS] hive_db;

也可以使用全限定名创建,或指定 location,如:

CREATE DATABASE [IF NOT EXISTS] hive_ctl.hive_db;

CREATE DATABASE [IF NOT EXISTS] hive_ctl.hive_db
PROPERTIES ('location'='hdfs://172.21.16.47:4007/path/to/db/');

之后可以通过 SHOW CREATE DATABASE 命令可以查看 Database 的 Location 信息:

mysql> SHOW CREATE DATABASE hive_db;
+----------+---------------------------------------------------------------------------------------------+
| Database | Create Database |
+----------+---------------------------------------------------------------------------------------------+
| hive_db | CREATE DATABASE hive_db LOCATION 'hdfs://172.21.16.47:4007/usr/hive/warehouse/hive_db.db' |
+----------+---------------------------------------------------------------------------------------------+

删除

DROP DATABASE [IF EXISTS] hive_ctl.hive_db;
警告

对于 Hive Database,必须先删除这个 Database 下的所有表后,才能删除 Database,否则会报错。这个操作会同步删除 Hive 中对应的 Database。

创建和删除表​

  • 创建

    Doris 支持在 Hive 中创建分区或非分区表。

    -- Create unpartitioned hive table
    CREATE TABLE unpartitioned_table (
    `col1` BOOLEAN COMMENT 'col1',
    `col2` INT COMMENT 'col2',
    `col3` BIGINT COMMENT 'col3',
    `col4` CHAR(10) COMMENT 'col4',
    `col5` FLOAT COMMENT 'col5',
    `col6` DOUBLE COMMENT 'col6',
    `col7` DECIMAL(9,4) COMMENT 'col7',
    `col8` VARCHAR(11) COMMENT 'col8',
    `col9` STRING COMMENT 'col9'
    ) ENGINE=hive
    PROPERTIES (
    'file_format'='parquet'
    );

    -- Create partitioned hive table
    -- The partition columns must be in table's column definition list
    CREATE TABLE partition_table (
    `col1` BOOLEAN COMMENT 'col1',
    `col2` INT COMMENT 'col2',
    `col3` BIGINT COMMENT 'col3',
    `col4` DECIMAL(2,1) COMMENT 'col4',
    `pt1` VARCHAR COMMENT 'pt1',
    `pt2` VARCHAR COMMENT 'pt2'
    ) ENGINE=hive
    PARTITION BY LIST (pt1, pt2) ()
    PROPERTIES (
    'file_format'='orc',
    'compression'='zlib'
    );

    -- Create text format table(Since 2.1.7 & 3.0.3)
    CREATE TABLE text_table (
    `id` INT,
    `name` STRING
    ) PROPERTIES (
    'file_format'='text',
    'compression'='gzip',
    'field.delim'='\t',
    'line.delim'='\n',
    'collection.delim'=';',
    'mapkey.delim'=':',
    'serialization.null.format'='\\N',
    'escape.delim'='\\'
    );

    创建后,可以通过 SHOW CREATE TABLE 命令查看 Hive 的建表语句。

    注意,不同于 Hive 中的建表语句。在 Doris 中创建 Hive 分区表时,分区列也必须写到 Table 的 Schema 中。同时,分区列必须在所有 Schema 的最后,且顺序保持一致。

    提示

    对于某些默认开启 ACID 事务特性的 Hive 集群,使用 Doris 建表后,表属性 transactional 会为 true。而 Doris 只支持部分 Hive 事务表的特性,因此可能会导致 Doris 创建的 Hive,Doris 本身无法读取的问题。因此,需要在建表的属性中,显式增加:"transactional" = "false",来创建非事务的 Hive 表:

    CREATE TABLE non_acid_table(
    `col1` BOOLEAN COMMENT 'col1',
    `col2` INT COMMENT 'col2',
    `col3` BIGINT COMMENT 'col3'
    ) ENGINE=hive
    PROPERTIES (
    'transactional'='false',
    );
  • 删除

    可以通过 DROP TABLE 语句删除一个 Hive 表。当前删除表后,会同时删除数据,包括分区数据。

  • 列类型映射

    参考【列类型映射】部分。需要额外注意一下限制:

    • 列类型只能为默认的 Nullable,不支持 NOT NULL。
    • Hive 3.0 支持设置默认值。如果需要设置默认值,则需要在 Catalog 属性中显示的添加 "hive.version" = "3.0.0"。
    • 插入数据后,如果类型不能够兼容,例如 'abc' 插入到数值类型,则会转为 null 值插入。
  • 分区

    Hive 中的分区类型对应 Doris 中的 List 分区。因此,在 Doris 中 创建 Hive 分区表,需使用 List 分区的建表语句,但无需显式的枚举各个分区。在写入数据时,Doris 会根据数据的值,自动创建对应的 Hive 分区。支持创建单列或多列分区表。

  • 文件格式

    • ORC(默认)

    • Parquet

      注意,DATETIME 类型写入到 Parquet 文件时,物理类型使用的是 INT96 而非 INT64。目的是兼容 Hive 4.0 版本之前的逻辑。

    • Text(自 2.1.7 和 3.0.3 版本开始支持)

    • Text 格式还支持以下表属性:

      • field.delim:列分隔符。默认 \1。

      • line.delim:行分隔符。默认 \n。

      • collection.delim:复杂类型中各元素之间的分隔符。默认 \2。

      • mapkey.delim:Map 类型的键值分割符。默认 \3

      • serialization.null.format:NULL 值的存储格式。默认 \N。

      • escape.delim:转移字符。默认 \。

  • 压缩格式

    • Parquet:snappy(默认)、zstd、plain。(Plain 就是不采用压缩)

    • ORC:snappy、zlib(默认)、zstd、plain。(Plain 就是不采用压缩)

    • Text:gzip、defalte、bzip2、zstd、lz4、lzo、snappy、plain(默认)。(Plain 就是不采用压缩)

  • 存储介质

    • HDFS

    • 对象存储

订阅 Hive Metastore 事件​

通过让 FE 节点定时读取 HMS 的 Notification Event 来感知 Hive 表元数据的实时变更情况,以提高元数据的时效性。目前支持处理如下 Event:

事件事件行为和对应的动作
CREATE DATABASE在对应数据目录下创建数据库。
DROP DATABASE在对应数据目录下删除数据库。
ALTER DATABASE此事件的影响主要有更改数据库的属性信息,注释及默认存储位置等,这些改变不影响 Doris 对外部数据目录的查询操作,因此目前会忽略此 Event。
CREATE TABLE在对应数据库下创建表。
DROP TABLE在对应数据库下删除表,并失效表的缓存。
ALTER TABLE如果是重命名,先删除旧名字的表,再用新名字创建表,否则失效该表的缓存。
ADD PARTITION在对应表缓存的分区列表里添加分区。
DROP PARTITION在对应表缓存的分区列表里删除分区,并失效该分区的缓存。
ALTER PARTITION如果是重命名,先删除旧名字的分区,再用新名字创建分区,否则失效该分区的缓存。
提示
  1. 当导入数据导致文件变更,分区表会触发 ALTER PARTITION 时间,非分区表会触发 ALTER TABLE 事件。

  2. 如果绕过 HMS 直接操作文件系统的话,HMS 不会生成对应事件,因此 Doris 也无法感知元数据变化。

该特性在 fe.conf 中有如下相关参数:

  1. enable_hms_events_incremental_sync: 是否开启元数据自动增量同步功能,默认关闭。

  2. hms_events_polling_interval_ms: 读取 event 的间隔时间,默认值为 10000,单位:毫秒。

  3. hms_events_batch_size_per_rpc: 每次读取 event 的最大数量,默认值为 500。

如果想使用该特性 (华为云 MRS 除外),需要更改 HMS 的 hive-site.xml 并重启 HMS 和 HiveServer2:

<property>
<name>hive.metastore.event.db.notification.api.auth</name>
<value>false</value>
</property>
<property>
<name>hive.metastore.dml.events</name>
<value>true</value>
</property>
<property>
<name>hive.metastore.transactional.event.listeners</name>
<value>org.apache.hive.hcatalog.listener.DbNotificationListener</value>
</property>

华为云 MRS 需要更改 hivemetastore-site.xml 并重启 HMS 和 HiveServer2:

<property>
<name>metastore.transactional.event.listeners</name>
<value>org.apache.hive.hcatalog.listener.DbNotificationListener</value>
</property>

附录​

事务机制​

对 Hive 的写入操作会被放在一个单独的事务里,在事务提交前,数据对外不可见。只有当提交该事务后,表的相关操作才对其他人可见。

事务能保证操作的原子性,事务内的所有操作,要么全部成功,要么全部失败。

事务不能完全保证操作的隔离性,只能尽力而为,通过分离文件系统操作和 对 Hive Metastore 的元数据操作来尽量减少不一致的时间窗口。

比如在一个事务中,需要修改 Hive 表的多个分区。假设这个任务分成两批进行操作,在第一批操作已经完成、第二批操作还未完成时,第一批分区已经对外可见,外部可以读取到第一批分区,但读不到第二批分区。

在事务提交过程中出现任何异常,都会直接回退该事务,包括对 HDFS 文件的修改、以及对 Hive Metastore 元数据的修改,不需要用户做其他处理。

并发写入机制​

当前 Apache Doris 支持使用多个插入语句进行并发写入。不过需要注意的是,用户需要控制并发写入不产生可能冲突的情况。

因为普通非事务 Hive 表缺少完备的事务机制。通过上文介绍的 Apache Doris 事务机制我们知道目前 Apache Doris 中的实现只能是尽力而为地减少可能不一致的时间窗口,而无法保证真正的 ACID。因此在 Apache Doris 中进行并发写入 Hive 表可能会导致数据一致性问题。

  1. INSERT 并发操作

  2. INSERT 为数据追加操作,在并发执行 INSERT 时,不会产生冲突,操作会产生预期的结果。

  3. INSERT OVERWRITE 并发操作

  4. 如果使用 INSERT OVERWRITE 对同一表或分区并发写入,可能会导致数据丢失或损坏,结果可能是不确定的。

  5. 一般有以下几种解决方案:

    • 对于分区表,可以将数据写入不同的分区,并发操作不同分区不会产生冲突。

    • 对于非分区表,可以同时执行 INSERT,而不使用 INSERT OVERWRITE,这样不会产生冲突的问题。

    • 对于可能产生冲突的操作,需要用户在业务侧控制同一时间只有一个写入在进行。

HDFS 文件操作​

在 HDFS 上的 Hive 表数据通常会先写入到临时目录,然后通过 rename 等文件系统操作进行最终的文件提交。这里我们详细介绍不同数据操作中,HDFS 上文件的具体操作。

数据的临时目录格式为:/tmp/.doris_staging/<username>/<uuid>

写入的数据文件名称格式为:<query-id>_<uuid>-<index>.<compress-type>.<file-type>

下面举例说明各种情况下的文件操作。

  1. 非分区表

    • Append(追加写入)

      • 目标表目录:hdfs://ns/usr/hive/warehouse/example.db/table1

      • 临时文件:hdfs://ns/tmp/.doris_staging/root/f02247cb662846038baae272af5eeb05/b35fdbcea3a4e39-86d1f36987ef1492_7e3985bf-9de9-4fc7-b84e-adf11aa08756-0.orc

      • 提交阶段会把所有临时文件移动到目标表目录下。

    • Overwrite(覆盖写)

      • 目标表目录:hdfs://ns/usr/hive/warehouse/example.db/table1

      • 临时文件:hdfs://ns/tmp/.doris_staging/root/f02247cb662846038baae272af5eeb05/b35fdbcea3a4e39-86d1f36987ef1492_7e3985bf-9de9-4fc7-b84e-adf11aa08756-0.orc

      • 提交阶段:

      1. 目标表目录重命名为目标表临时目录:hdfs://ns/usr/hive/warehouse/example.db/_temp_b35fdbcea3a4e39-86d1f36987ef1492_table1

      2. 临时目录重命名为目标表目录。

      3. 删除目标表临时目录。

  2. 分区表

    • Add(添加到新分区)

      • 目标表目录:hdfs://ns/usr/hive/warehouse/example.db/table2/part_col=2024-01-01

      • 临时文件:hdfs://ns/tmp/.doris_staging/root/a7eac7505d7a42fdb06cb9ef1ea3e912/par1=a/d678a74d232345e0-b659e2fb58e86ffd_549ad677-ee75-4fa1-b8a6-3e821e1dae61-0.orc

      • 提交阶段,会将临时目录重命名为目标表目录

    • Append(写入数据到已存在的分区)

      • 目标表目录:hdfs://ns/usr/hive/warehouse/example.db/table2/part_col=2024-01-01

      • 临时文件:hdfs://ns/tmp/.doris_staging/root/a7eac7505d7a42fdb06cb9ef1ea3e912/par1=a/d678a74d232345e0-b659e2fb58e86ffd_549ad677-ee75-4fa1-b8a6-3e821e1dae61-0.orc

      • 提交阶段,会将临时目录下的文件,移动到目标表目录下。

    • Overwrite(覆盖已有分区)

      • 目标表目录:hdfs://ns/usr/hive/warehouse/example.db/table2/part_col=2024-01-01

      • 临时文件:hdfs://ns/tmp/.doris_staging/root/a7eac7505d7a42fdb06cb9ef1ea3e912/par1=a/d678a74d232345e0-b659e2fb58e86ffd_549ad677-ee75-4fa1-b8a6-3e821e1dae61-0.orc

      • 提交阶段:

      1. 目标表分区目录重命名为目标表临时分区目录:hdfs://ns/usr/hive/warehouse/example.db/table2/_temp_d678a74d232345e0-b659e2fb58e86ffd_part_col=2024-01-01

      2. 临时分区目录重命名为目标表分区目录。

      3. 删除目标表临时分区目。

版本更新记录​

Doris 版本功能支持
2.1.6支持 Hive 表数据写回
3.0.4支持 JsonSerDe 格式的 Hive 表。支持 Hive4 的事务表。