暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

OceanBase新特性之外表学习笔记

原创 董小姐 2025-07-18
165

背景

通常,数据库中的表数据,会存放在数据库自身的存储空间中,而外表的数据,则存储在外部存储服务中。外表可以访问数据库外部的文件,并读取文件中的数据。在一般的业务场景中,经常遇到需要利用数据库处理外部数据的情况。这些数据可能来源于应用程序产生,也可能是由其他业务系统产生。没有外表时,只能通过 ETL工具将外部数据库导入到数据库内部的表中,再进行分析处理。而外部表可以直接读取外部数据文件,这样做有几个好处:

  • 可以减少数据的拷贝,节省数据库存储空间。
  • 提高数据的共享,避免数据出现不一致的情况。
  • 删除外表时数据不会被删除。
  • 外表不支持 DML。

外部表相比普通表具有更丰富的功能:

  • 支持多种存储方式:例如数据文件可以放在不同云服务的对象存储服务中。
  • 支持多种存储格式:例如 CSV 等格式。

注意事项:

  • 当外部文件被删除。

外表访问文件列表中的文件将会不存在,这种情况发生时,外表会忽略不存在的文件。

  • 当外部文件被修改。

外表访问外部文件的最新的状态。当外部文件修改与外表查询并发时,可能会产生不符合预期的结果,需要避免在查询外表的同时修改外部文件。

  • 当外部目录下有新增文件。

外表仅会访问文件列表中的文件,如果需要将新增文件添加到外表的文件列表中,需要执行“更新外表文件”操作。

示例

创建外部表法一:存放外部数据文件在对象存储服务中

通过外表读取 OceanBase 日志的小 demo,可快速理解外表的作用。

首先来到 OceanBase 的日志目录,里面有一些以 .log 结尾的文件。

外表的数据文件可以放在不同云服务的对象存储服务中。

然后创建一张外表。

目前 OceanBase 支持 CSV、PARQUET、ORC 这几种常用文件格式。

创建好外表之后,就可以像普通表一样进行查询了~

说明:

上面 demo 中的 SERVER_LOG 只是用来作为 demo 示例,并非正式发布的版本中支持的文件格式。

外表可以像普通表一样,与其他表进行链接、聚合、排序等,外表与普通表的差异如下:

  • 外表的数据存储在外部文件中,普通表的数据存储在数据库中。
  • 外表是只读的,可以在查询语句使用,但不能执行 DML操作。
  • 外表不支持添加约束和创建索引。

通常来说,外表的访问速度会慢于普通表。

创建外部表法二:借助hive表

Hive 中的表

Hive 分区表存储的目录结构:

通过外表读取 Hive 的数据:

性能测试示例

下面对外表进行简单的性能测试,以本地文件场景和 CSS 文件场景为例,测试环境如下:

CPU Intel(R) Xeon(R) CPU E5-2682 v4 @ 2.50GHz

DATA:TPCH 1G 的文本文件,文件格式 CSV,每个表的数据拆成 10 个文件

兼容模式:Oracle(社区版虽然没有 Oracle 模式,但区别不大,领会精神即可)

0B 版本:4.2(朝花夕拾版)

场景 1:本地文件场景

串行扫描

并行扫描

场景 2:OSS 文件

串行扫描

并行扫描

其他复杂 SQL 的场景示例

示例 1

外表可以像普通表一样与其他表进行链接,谓词过滤,聚合,排序等操作。外表可以通过 parallel hint 开启并行查询。下面例子中,customer/orders/lineitem 均为外表

示例 2

外表可以与普通表组合进行查询操作。

下面例子中,temp 是普通表,orders 是外表。

示例3

外表可以实现将外部数据导入普通表的操作。

下面例子中,lineitem import 为普通表,lineitem 为外部表,通过 PDML功能可以将外表 lineitem 数据并行导入普通表 lineitem_import.

外部表的用法

准备外部表数据

在阿里云的对象存储 OSS 中存放了 TPCH 1G 的数据,其中 lineitem 的表的数据分成了 10 个文件放在 mydata/tpch 1g data/lineitem 中。

创建外表

外表的用法和普通表非常相似,比普通表多了 LOCATION 和 FORMAT 属性。其中 LOCATION 用于指定数据文件所在位置,FORMAT 指定数据文件的格式。

如果文件中的列顺序和表中的列顺序不一致,可以通过通过 metadataSfilecolN 伪列进行对应。

查看外表的文件

外表创建时,会将 LOCATION 下的文件列表保存在一个文件列表中,外表扫描时只会访问这个列表下的外部文件。通过以下语句可以查看外表的文件列表:

当外部数据文件有变化时,可以执行以下语句更新外表的文件列表。

如果文件被删除且未更新文件列表,外表查询时会自动忽略这个文件。

查询外表

外表查询时,通过外表的驱动层直接读取外部文件,并按照文件格式进行解析,转换成 OceanBase 内部的数据类型后返回数据行。

附:外表文件格式

CSV

Parquet /ORC

嵌套数据类型的 Schema

Parquet 是一个由 Google Dremel 格式启发而来的列存格式,在大数据领域通常作为存储格式,被iceberg 等湖、各种查询引擎能够合理的使用。

Parquet schema模型能比较简洁处理嵌会和重复。嵌会关系用“属性组”(groups)表示,重复属性用"重复度"(repeated field)表示。一个属性的"重复度"可以有几种定义:

  • required:刚好出现一次
  • optional:出现0或1次
  • repeated:出现0或多次

Parquet 存储数据的例子:

假如有 schema 是:

country_tab 记录包含 continent、countny、name三个属性,其中country是一个属性组,包含 city、population两个属性。city是一个repeated 字段,因此可以有多个值,从而表达了数组。

存储下面一行数据:

其中,city 是个数组,数组中元素可以是任意个,假设 population 可能是未知的,可以被设置为NULL,其他属性都是不能为 NULL 的。

Parquet 认为以上 schema 有4列(仅存储叶子结点)

假如有 2 行数据,因为一行中的数据可以 repeat,也可以为 nul,如何区分一个 column chunk 中的数据到底是属于哪一行的?

通过数据上定义的 defination level 和 repetitive level.

类似地,Maps,List or Sets 都可以用重复和属性组(groups+repeated field)表达出来。

相比之下,ORC 使用一个单独的 bitmap 来存储节点是否存在,比较容易理解。

1. Struet 只记录 Struet 本身的 PRESENT。

2. List = Present Stream + Length Stream.

3.Map = Map 等价于一种很奇怪的 List 和 List 表现一样,但后面有一组 Key 一组 Value。

4.Union 分成 PRESENT+Tag,后面接不同种类的 Stream。

课堂实操

准备工作

创建存放外部数据目录

mkdir -p /home/admin/external_table_files
cd /home/admin/external_table_files

创建存放外部数据数据

cat data1.csv
1,"lin",98
2,"hei",90
3,"ali",95

通过本地 Unix Socket 连接集群的 MySQL 租户

在 OBserver 节点上,通过本地 Unix Socket 连接集群的 MySQL 租户。

obclient -S /home/admin/oceanbase/observer/run/sql.sock -utest@sys  -Dtestdb -A

通过本地 Unix Socket 连接 OceanBase 数据库的具体操作及说明,可参见 secure_file_priv

配置数据库可以访问的路径

SET GLOBAL secure_file_priv = "/home/admin/external_table_files/";

注意:命令执行成功后,需要重启会话后,修改才能生效。

重新连接数据库

使用 test 用户登录

exit
obclient -h127.0.0.1 -utest@sys -P2881 -Dtestdb -A

--参数说明
testdb 数据库已预建完成,不需要手动创建。
test 用户拥有管理权限,已预授权。

创建外表

CREATE EXTERNAL TABLE ext_t1(id int, name char(10),score int)
                LOCATION = '/home/admin/external_table_files/'
                FORMAT = (
                TYPE = 'CSV'
                FIELD_DELIMITER = ','
                FIELD_OPTIONALLY_ENCLOSED_BY ='"'
                )
                PATTERN = 'data1.csv';

查询外表

场景1:普通查询

select * from  ext_t1;

输出如下:

obclient [testdb]> select * from  ext_t1;
+------+------+-------+
| id   | name | score |
+------+------+-------+
|    1 | lin  |    98 |
|    2 | hei  |    90 |
|    3 | ali  |    95 |
+------+------+-------+
3 rows in set (0.004 sec)

问题处理

问题描述:创建外部表后查询提示ERROR 9731 (HY000): insufficient privileges to do direct path access

obclient [testdb]> select * from  ext_t1;
ERROR 9731 (HY000): insufficient privileges to do direct path access

问题原因:配置数据库可以访问的路径后未重启库

解决办法:退出重新登录后查询正常。

场景2:外表之间进行组合查询

外表可以通过 parallel hint 开启并行查询

创建存放外部数据文件

创建 data2.csv 文件用于存放外部数据。

cd /home/admin/external_table_files
cat data2.csv
1,"aaa",100
2,"bbb",80
3,"ccc",90
4,"aaa",60
5,"bbb",39
6,"ccc",75
7,"aaa",90
8,"bbb",100
9,"bbb",50

连接数据库

obclient -h127.0.0.1 -utest@sys -P2881 -Dtestdb -A

创建外表 ext_t2

CREATE EXTERNAL TABLE ext_t2(id int, name varchar(10),score int)
                    LOCATION = '/home/admin/external_table_files/'
                    FORMAT = (
                    TYPE = 'CSV'
                    FIELD_DELIMITER = ','
                    FIELD_OPTIONALLY_ENCLOSED_BY ='"'
                    )
                    PATTERN = 'data2.csv';

ext_t1ext_t2 关联查询

SELECT /*+ parallel(10) */
            ext_t2.id,ext_t2.name,ext_t2.score
            FROM ext_t1,
                ext_t2
            WHERE ext_t2.name = 'aaa'
            AND ext_t2.id= ext_t1.id
            AND ext_t2.score >90
            ORDER BY ext_t2.score DESC, ext_t2.id;

输出如下:

+------+------+-------+
| id   | name | score |
+------+------+-------+
|    1 | aaa  |   100 |
+------+------+-------+
1 row in set (0.077 sec)

通过外表将外部数据导入普通表

ext_t3 为普通表,ext_t1 为外部表,通过 PDML 功能可以将外表 ext_t1 数据并行导入普通表 ext_t3

创建普通表 ext_t3

CREATE TABLE ext_t3(id int, name char(10),score int);

外表数据插入 ext_t3 中

INSERT /*+ enable_parallel_dml parallel(10) */ INTO ext_t3
SELECT * FROM ext_t1;

场景1:查询 ext_t3 数据

select * from ext_t3;

输出如下:

obclient [testdb]> select * from ext_t3;
+------+------+-------+
| id   | name | score |
+------+------+-------+
|    3 | ali  |    95 |
|    2 | hei  |    90 |
|    1 | lin  |    98 |
+------+------+-------+
3 rows in set (0.004 sec)

场景2:外表与普通表组合进行查询

ext_t3 是普通表,ext_t1 是外表。

SELECT ext_t3.* from ext_t3, ext_t1 WHERE ext_t3.id = ext_t1.id limit 2;

输出结果如下:

+------+------+-------+
| id   | name | score |
+------+------+-------+
|    1 | lin  |    98 |
|    2 | hei  |    90 |
+------+------+-------+
2 rows in set (0.005 sec)

课件链接:https://open.oceanbase.com/course/detail/12027

「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论