通过外表导入OSS数据

更新时间:

AnalyticDB for MySQL支持通过外表导入外部数据。本文介绍如何通过外表将OSS的数据导入AnalyticDB for MySQL集群。

前提条件

  • AnalyticDB for MySQL集群与OSS存储空间位于同一地域。具体操作,请参见开通OSS服务

  • 已将数据文件上传至OSS目录中。

  • AnalyticDB for MySQL数仓版已开启ENI访问。

    重要
    • 登录云原生数据仓库AnalyticDB MySQL控制台,在集群信息页面的网络信息区域,打开ENI网络开关。

    • 开启和关闭ENI网络会导致数据库连接中断大约2分钟,无法读写。请谨慎评估影响后再开启或关闭ENI网络。

数据准备

本文示例将数据文件person.csv上传至OSS中的testBucketName/adb/dt=2023-06-15目录,数据行分隔符为换行符,列分隔符为英文逗号(,)。person.csv中的示例数据如下:

1,james,10,2023-06-15
2,bond,20,2023-06-15
3,jack,30,2023-06-15
4,lucy,40,2023-06-15       

操作步骤

企业版、基础版及湖仓版

  1. 进入SQL开发编辑器。

    1. 登录云原生数据仓库AnalyticDB MySQL控制台,在左上角选择集群所在地域。在左侧导航栏,单击集群列表,然后单击目标集群ID。

    2. 在左侧导航栏,单击作业开发 > SQL开发

  2. 导入数据。

    数据导入方式分为常规导入(默认)和弹性导入。常规导入在计算节点中读取源数据,然后在存储节点中构建索引,消耗计算资源和存储资源。弹性导入在Serverless Spark Job中读取源数据和构建索引,消耗Job型资源组的资源。仅内核版本3.1.10.0及以上且已创建Job型资源组的企业版、基础版及湖仓版集群支持弹性导入数据。更多内容,请参见数据导入方式介绍

    常规导入

    1. 创建外部数据库。

      CREATE EXTERNAL DATABASE adb_external_db;
    2. 创建外表。使用CREATE EXTERNAL TABLE语句在外部数据库adb_external_db中创建OSS外表。本文以adb_external_db.person为例。

      说明

      AnalyticDB for MySQL外表的字段名称、字段数量、字段顺序、字段类型需要与和OSS文件相同。

      创建OSS非分区外表

      CREATE EXTERNAL TABLE adb_external_db.person
      (
       id INT,
       name VARCHAR(1023),
       age INT,
       dt VARCHAR(1023)
      )
      ROW FORMAT DELIMITED FIELDS TERMINATED BY  ','
      STORED AS TEXTFILE
      LOCATION  'oss://testBucketName/adb/dt=2023-06-15/';

      创建OSS分区外表

      创建OSS分区外表,并添加分区,才能查询出OSS分区外表的数据。

      1. 创建OSS分区外表。

        CREATE EXTERNAL TABLE adb_external_db.person
        (
         id INT,
         name VARCHAR(1023) ,
         age INT
        )
        PARTITIONED BY (dt STRING)
        ROW FORMAT DELIMITED FIELDS TERMINATED BY  ','
        STORED AS TEXTFILE
        LOCATION  'oss://testBucketName/adb/';
      2. 添加分区。您可以通过ALTER TABLE ADD PARTITION手动添加分区,也可以通过MSCK REPAIR TABLE自动识别并添加分区。

        ALTER TABLE adb_external_db.person ADD PARTITION (dt='2023-06-15') LOCATION 'oss://testBucketName/adb/dt=2023-06-15/';
        说明

      OSS外表的语法说明,请参见CREATE EXTERNAL TABLE

    3. 查询数据。

      数据表创建成功后,您可以在AnalyticDB for MySQL中通过SELECT语句查询OSS的数据。

      SELECT * FROM adb_external_db.person;

      返回结果如下:

      +------+-------+------+-----------+
      | id   | name  | age  | dt        |
      +------+-------+------+-----------+
      |    1 | james |   10 |2023-06-15 |
      |    2 | bond  |   20 |2023-06-15 |
      |    3 | jack  |   30 |2023-06-15 |
      |    4 | lucy  |   40 |2023-06-15 |
      +------+-------+------+-----------+
    4. AnalyticDB for MySQL中创建数据库。如果有已创建的数据库,可以忽略本步骤。示例如下:

      CREATE DATABASE adb_demo; 
    5. AnalyticDB for MySQL中创建表用于存储从OSS中导入的数据。示例如下:

      说明

      创建的内表和步骤b中创建的外表的字段名称、字段数量、字段顺序、字段类型必须相同。

      CREATE TABLE IF NOT EXISTS adb_demo.adb_import_test(
          id INT,
          name VARCHAR(1023),
          age INT,
          dt VARCHAR(1023)
      )
      DISTRIBUTED BY HASH(id);
    6. 向表中导入数据。

      • 方法一:使用INSERT INTO语句导入数据,当主键重复时会自动忽略当前写入数据,数据不做更新,作用等同于INSERT IGNORE INTO,更多信息,请参见INSERT INTO。示例如下:

        INSERT INTO adb_demo.adb_import_test SELECT * FROM adb_external_db.person;
      • 方法二:使用INSERT OVERWRITE INTO语句同步导入数据,会覆盖表中原有的数据。示例如下:

        INSERT OVERWRITE INTO adb_demo.adb_import_test SELECT * FROM adb_external_db.person;
      • 方法三:使用INSERT OVERWRITE INTO语句异步导入数据,更多信息,请参见异步写入。示例如下:

        SUBMIT JOB INSERT OVERWRITE adb_demo.adb_import_test SELECT * FROM adb_external_db.person;

    弹性导入

    1. 创建数据库。如果有已创建的数据库,可以忽略本步骤。示例如下:

      CREATE DATABASE adb_demo; 
    2. 创建外表。

      说明
      • AnalyticDB for MySQL外表的字段名称、字段数量、字段顺序、字段类型需要与和OSS文件相同。

      • 弹性导入仅支持CREATE TABLE语句创建外表。

      CREATE TABLE oss_import_test_external_table
      (
        id INT(1023),
        name VARCHAR(1023),
        age INT,
        dt VARCHAR(1023)
      )
      ENGINE='OSS'
      TABLE_PROPERTIES='{
          "endpoint":"oss-cn-hangzhou-internal.aliyuncs.com",
          "url":"oss://testBucketName/adb/dt=2023-06-15/person.csv",
          "accessid":"accesskey_id",
          "accesskey":"accesskey_secret",
          "delimiter":","
      }';
      重要

      创建外表时,CSV、Parquet、ORC格式的外表支持设置的TABLE_PROPERTIES参数不同:

      • CSV格式:仅支持设置endpointurlaccessidaccesskeyformatdelimiternull_valuepartition_column参数。

      • Parquet格式:仅支持设置endpointurlaccessidaccesskeyformatpartition_column参数。

      • ORC格式:仅支持设置endpointurlaccessidaccesskeyformatpartition_column参数。

      外表支持设置的参数及参数说明,请参见OSS非分区外表OSS分区外表

    3. 查询数据。

      数据表创建成功后,您可以在AnalyticDB for MySQL中通过SELECT语句查询OSS的数据。

      SELECT * FROM oss_import_test_external_table;

      返回结果如下:

      +------+-------+------+-----------+
      | id   | name  | age  | dt        |
      +------+-------+------+-----------+
      |    1 | james |   10 |2023-06-15 |
      |    2 | bond  |   20 |2023-06-15 |
      |    3 | jack  |   30 |2023-06-15 |
      |    4 | lucy  |   40 |2023-06-15 |
      +------+-------+------+-----------+
      4 rows in set (0.35 sec)
    4. AnalyticDB for MySQL中创建表用于存储从OSS中导入的数据。示例如下:

      说明

      创建的内表和步骤b中创建的外表的字段名称、字段数量、字段顺序、字段类型必须相同。

      CREATE TABLE adb_import_test
      (
        id INT,
        name VARCHAR(1023),
        age INT,
        dt VARCHAR(1023)
      )
      DISTRIBUTED BY HASH(id);
    5. 导入数据。

      重要

      弹性导入仅支持通过INSERT OVERWRITE INTO语句导入数据。

      • 方法一:执行INSERT OVERWRITE INTO弹性导入数据,会覆盖表中原有的数据。示例如下:

        /+*elastic_load=true, elastic_load_configs=[adb.load.resource.group.name=resource_group]*/
        INSERT OVERWRITE INTO adb_demo.adb_import_test SELECT * FROM adb_demo.oss_import_test_external_table;
      • 方法二:异步执行INSERT OVERWRITE INTO弹性导入数据。通常使用SUBMIT JOB提交异步任务,由后台调度。

        /*+elastic_load=true, elastic_load_configs=[adb.load.resource.group.name=resource_group]*/
        SUBMIT JOB INSERT OVERWRITE INTO adb_demo.adb_import_test SELECT * FROM adb_demo.oss_import_test_external_table;
        重要

        异步提交弹性导入任务时,不支持设置优先级队列。

        返回结果如下:

        +---------------------------------------+
        | job_id                                |
        +---------------------------------------+
        | 202308151719510210170190**********    |

      使用SUBMIT JOB提交异步任务后,返回结果仅表示异步任务提交成功。您可以通过job_id终止异步任务或查询异步任务状态,判断任务是否执行成功。具体操作,请参见异步提交导入任务

      Hint参数说明:

      • elastic_load:是否使用弹性导入方式。取值:truefalse(默认值)。

      • elastic_load_configs:弹性导入方式支持配置的参数。参数需使用方括号([ ])括起来,且多个参数之间以竖线(|)分隔,支持配置的参数如下表所示:

        参数

        是否必填

        说明

        adb.load.resource.group.name

        执行弹性导入任务的Job资源组名称。

        adb.load.job.max.acu

        单个弹性导入任务最多使用的资源。单位为ACU,最小值为5 ACU。默认值为集群Shard个数+1。

        执行如下语句可查询集群Shard个数:

        SELECT count(1) FROM information_schema.kepler_meta_shards;

        spark.driver.resourceSpec

        Spark driver的资源规格。默认值为small。取值范围,请参见Spark应用配置参数说明的型号列。

        spark.executor.resourceSpec

        Spark executor资源规格。默认值为large。取值范围,请参见Spark应用配置参数说明的型号列。

        spark.adb.executorDiskSize

        Spark executor的磁盘容量,取值范围为(0,100],单位为GiB,默认值为10 Gi。更多信息,请参见指定DriverExecutor资源

    6. (可选)查看已提交的导入任务是否为弹性导入任务。

      SELECT job_name, (job_type = 3) AS is_elastic_load FROM INFORMATION_SCHEMA.kepler_meta_async_jobs where job_name = "2023081818010602101701907303151******";

      返回结果如下:

      +---------------------------------------+------------------+
      | job_name                              | is_elastic_load  |
      +---------------------------------------+------------------+
      | 20230815171951021017019072*********** |       1          |
      +---------------------------------------+------------------+

      is_elastic_load的返回值为1,表示已提交的导入任务是弹性导入任务;若为0,则表示已提交的导入任务是常规导入任务。

数仓版

  1. 连接集群,创建数据库。

    CREATE DATABASE adb_demo;
  2. 创建外表。使用CREATE TABLE语法创建CSV、ParquetORC格式的OSS外表。具体语法,请参见OSS外表语法

    本文示例以CSV格式非分区外表为例。

    CREATE TABLE IF NOT EXISTS oss_import_test_external_table
    (
        id INT,
        name VARCHAR(1023),
        age INT,
        dt VARCHAR(1023) 
    )
    ENGINE='OSS'
    TABLE_PROPERTIES='{
        "endpoint":"oss-cn-hangzhou-internal.aliyuncs.com",
        "url":"oss://testBucketname/adb/dt=2023-06-15/person.csv",
        "accessid":"accesskey_id",
        "accesskey":"accesskey_secret",
        "delimiter":",",
        "skip_header_line_count":0,
        "charset":"utf-8"
    }'; 
  3. 查询oss_import_test_external_table外表数据。

    说明

    对于CSV格式、ParquetORC格式数据文件,数据量越大,通过外表查询的性能损耗越大。如果您需要进一步提升查询效率,建议您按照后续步骤(4~5)将OSS外表数据导入AnalyticDB for MySQL后再做查询。

    SELECT * FROM oss_import_test_external_table;
  4. AnalyticDB for MySQL中创建表,用于存储从OSS外表导入的数据。

    CREATE TABLE IF NOT EXISTS adb_oss_import_test
    (
       id INT,
       name VARCHAR(1023),
       age INT,
       dt VARCHAR(1023) 
    )
    DISTRIBUTED BY HASH(id);
  5. 执行INSERT语句将OSS外表数据导入AnalyticDB for MySQL

    重要

    使用INSERT INTOINSERT OVERWRITE SELECT导入数据时,默认是同步执行流程。如果数据量较大,达到几百GB,客户端到AnalyticDB for MySQL服务端的连接需要保持较长时间。在此期间,可能会因为网络因素导致连接中断,进而导致数据导入失败。因此,如果您的数据量较大时,推荐使用SUBMIT JOB INSERT OVERWRITE SELECT异步执行导入。

    • 方式一:执行INSERT INTO导入数据,当主键重复时会自动忽略当前写入数据,不进行更新覆盖,作用等同于INSERT IGNORE INTO,详情请参见INSERT INTO。示例如下:

      INSERT INTO adb_oss_import_test
      SELECT * FROM oss_import_test_external_table;
    • 方式二:执行INSERT OVERWRITE导入数据,会覆盖表中原有的数据。示例如下:

      INSERT OVERWRITE adb_oss_import_test
      SELECT * FROM oss_import_test_external_table;
    • 方式三:异步执行INSERT OVERWRITE导入数据。 通常使用SUBMIT JOB提交异步任务,由后台调度,可以在写入任务前增加Hint(/*+ direct_batch_load=true*/)加速写入任务。详情请参见异步写入。示例如下:

      SUBMIT JOB INSERT OVERWRITE adb_oss_import_test
      SELECT * FROM oss_import_test_external_table;

      返回结果如下:

      +---------------------------------------+
      | job_id                                |
      +---------------------------------------+
      | 2020112122202917203100908203303****** |

      关于异步提交任务详情,请参见异步提交导入任务

OSS外表语法

企业版、基础版及湖仓版

企业版、基础版及湖仓版OSS外表的语法及相关说明,请参见OSS外表

数仓版

OSS非分区外表

CREATE TABLE [IF NOT EXISTS] table_name
(column_name column_type[, …])
ENGINE='OSS'
TABLE_PROPERTIES='{
    "endpoint":"endpoint",
    "url":"OSS_LOCATION",
    "accessid":"accesskey_id",
    "accesskey":"accesskey_secret",
    "format":"csv|orc|parquet|text
    "delimiter|field_delimiter":";",
    "skip_header_line_count":1,
    "charset":"utf-8"
}';

外表类型

参数

是否必填

说明

CSV格式、Parquet格式和ORC格式外表

ENGINE='OSS'

表引擎,固定填写为OSS。

endpoint

OSSEndPoint(地域节点)。 目前仅支持AnalyticDB for MySQL通过VPC网络访问OSS。

说明

您可登录OSS控制台,单击目标Bucket,在Bucket概览页面查看EndPoint(地域节点)

url

指定OSS文件或目录所在的路径。

  • OSS文件需填写绝对路径。例如:oss://testBucketname/adb/oss_import_test_data.csv

  • 目录路径以正斜线(/)结尾。例如:oss://testBucketname/adb/

    说明

    若指定为目录路径,成功创建外表后,外表中的数据为该文件夹下的所有数据。

  • 路径末尾支持通配符*,用于匹配该路径下所有符合该模式的文件或文件夹。例如:oss://testBucketname/adb/list_file_with_prefix/test*

    说明

    该模糊查询示例将匹配到满足前缀条件的所有文件和文件夹,例如:oss://testBucketname/adb/list_file_with_prefix/testfile1

    oss://testBucketname/adb/list_file_with_prefix/test1/file2

accessid

阿里云账号或者具备OSS管理权限的RAM用户的AccessKey ID。

如何获取AccessKey ID,请参见账号与权限

accesskey

阿里云账号或者具备OSS管理权限的RAM用户的AccessKey Secret。

如何获取AccessKey Secret,请参见账号与权限

format

条件必填

数据文件的格式。

  • 创建Parquet外表时,需显式设置为parquet

  • 创建ORC外表时,需显式设置为orc

  • 创建Text外表时,需显式设置为text

  • 不指定该参数时,文件格式默认为csv

CSV格式和Text格式外表

delimiter|field_delimiter

定义数据文件的列分隔符。

  • 文件类型为csv时,该参数名填写为delimiter

  • 文件类型为text时,该参数名填写为field_delimiter

CSV格式外表

null_value

定义CSV数据文件的NULL值。默认将空值定义为NULL,即"null_value": ""

重要

仅内核版本为3.1.4.2及以上的集群支持配置该参数。

ossnull

选择CSV数据文件中NULL值的对应规则。取值如下:

  • 1(默认值):表示EMPTY_SEPARATORS,即仅将空值定义为NULL

    示例:a,"",,c --> "a","",NULL,"c"

  • 2:表示EMPTY_QUOTES,即仅将""定义为NULL

    示例:a,"",,c --> "a",NULL,"","c"

  • 3:表示BOTH,即同时将空值和""定义为NULL

    示例:a,"",,c --> "a",NULL,NULL,"c"

  • 4:表示NEITHER,即空值和""均不定义为NULL

    示例:a,"",,c --> "a","","","c"

说明

上述各示例的前提为"null_value": ""

skip_header_line_count

定义导入数据时需要在开头跳过的行数。CSV文件第一行为表头,若设置该参数为1,导入数据时可自动跳过第一行的表头。

默认取值为0,即不跳过。

oss_ignore_quote_and_escape

是否忽略字段值中的引号和转义。默认取值为false,即不忽略字段值中的引号和转义。

重要

仅内核版本为3.1.4.2及以上的集群支持配置该参数。

charset

OSS外表字符集,取值说明:

  • utf-8(默认值)

  • gbk

重要

仅内核版本为3.1.10.4及以上的集群支持配置该参数。

说明
  • 外表创建语句中的列名需与ParquetORC文件中该列的名称完全相同(可忽略大小写),且列的顺序需要一致。

  • 创建外表时,可以仅选择ParquetORC文件中的部分列作为外表中的列,未被选择的列不会被导入。

  • 如果创建外表创建语句中出现了ParquetORC文件中不存在的列,针对该列的查询结果均会返回NULL。

AnalyticDB for MySQL支持通过OSSCSV格式的外表读写Hive TEXT文件。建表语句如下:

CREATE TABLE adb_csv_hive_format_oss (
  a tinyint,
  b smallint,
  c int,
  d bigint,
  e boolean,
  f float,
  g double,
  h varchar,
  i varchar, -- binary
  j timestamp,
  k DECIMAL(10, 4),
  l varchar, -- char(10)
  m varchar, -- varchar(100)
  n date
) ENGINE = 'OSS' TABLE_PROPERTIES='{
    "format": "csv",
    "endpoint":"oss-cn-hangzhou-internal.aliyuncs.com",
    "accessid":"accesskey_id",
    "accesskey":"accesskey_secret",
    "url":"oss://testBucketname/adb_data/",
    "delimiter": "\\1",
    "null_value": "\\\\N",
    "oss_ignore_quote_and_escape": "true",
    "ossnull": 2
}';
说明

在创建OSSCSV格式的外表来读取Hive TEXT文件时,需注意如下几点:

  • Hive TEXT文件的默认列分隔符为\1。若您需要通过OSSCSV格式的外表读写Hive TEXT文件,您可以在配置delimiter参数时将其转义为\\1

  • Hive TEXT文件的默认NULL值为\N。若您需要通过OSSCSV格式的外表读写Hive TEXT文件,您可以在配置null_value参数时将其转义为 \\\\N

  • Hive的其他基本数据类型(如BOOLEAN)与AnalyticDB for MySQL的数据类型一一对应,但BINARYCHAR(n)VARCHAR(n)类型均对应AnalyticDB for MySQL中的VARCHAR类型。

附录:Parquet文件、ORC文件、Paimon文件与AnalyticDB for MySQL数据类型的映射关系

Parquet文件与AnalyticDB for MySQL的数据类型映射关系

Parquet基本类型

ParquetlogicalType类型

AnalyticDB for MySQL的数据类型

BOOLEAN

BOOLEAN

INT32

INT_8

TINYINT

INT32

INT_16

SMALLINT

INT32

INTINTEGER

INT64

BIGINT

FLOAT

FLOAT

DOUBLE

DOUBLE

  • FIXED_LEN_BYTE_ARRAY

  • BINARY

  • INT64

  • INT32

DECIMAL

DECIMAL

BINARY

UTF-8

  • VARCHAR

  • STRING

  • JSON(如果已知Parquet该列内容为JSON格式)

INT32

DATE

DATE

INT64

TIMESTAMP_MILLIS

TIMESTAMPDATETIME

INT96

TIMESTAMPDATETIME

重要

Parquet格式外表暂不支持STRUCT类型,会导致建表失败。

ORC文件与AnalyticDB for MySQL的数据类型映射关系

ORC文件中的数据类型

AnalyticDB for MySQL中的数据类型

BOOLEAN

BOOLEAN

BYTE

TINYINT

SHORT

SMALLINT

INT

INTINTEGER

LONG

BIGINT

DECIMAL

DECIMAL

FLOAT

FLOAT

DOUBLE

DOUBLE

  • BINARY

  • STRING

  • VARCHAR

  • VARCHAR

  • STRING

  • JSON(如果已知ORC该列内容为JSON格式)

TIMESTAMP

TIMESTAMPDATETIME

DATE

DATE

重要

ORC格式外表暂不支持LISTSTRUCTUNION等复合类型,会导致建表失败。ORC格式外表的列使用MAP类型可以建表,但ORC的查询会失败。

Paimon文件与AnalyticDB for MySQL的数据类型映射关系

Paimon文件中的数据类型

AnalyticDB for MySQL中的数据类型

CHAR

VARCHAR

VARCHAR

VARCHAR

BOOLEAN

BOOLEAN

BINARY

VARBINARY

VARBINARY

VARBINARY

DECIMAL

DECIMAL

TINYINT

TINYINT

SMALLINT

SMALLINT

INT

INTEGER

BIGINT

BIGINT

FLOAT

REAL

DOUBLE

DOUBLE

DATE

DATE

TIME

不支持

TIMESTAMP

TIMESTAMP

LocalZonedTIMESTAMP

TIMESTAMP(忽略本地时区信息)

ARRAR

ARRAR

MAP

MAP

ROW

ROW