# 使用SELECT INTO OUTFILE OBS命令导出数据
#### 操作场景
您可以使用 **SELECT INTO OUTFILE OBS** 语句从TaurusDB数据库中查询数据，将数据导出为文本文件并保存到OBS桶中。文件首先存储到本地数据盘上，然后导出到OBS。导出完成后，将删除本地文件。
该语句仅将**表数据**导出为文本文件，不会导出表结构。
#### 版本约束
将TaurusDB的文本文件导出到OBS，需要数据库内核版本大于等于2.0.75.260300。
内核版本的查询方法请参见[如何查看云数据库 TaurusDB实例的版本号](https://support.huaweicloud.com/taurusdb_faq/taurusdb_faq_0141.html)。
#### 前提条件
- 开启导入导出功能，需打开参数开关rds_load_from_obs_enable，修改参数值为ON。参数修改请参见[修改TaurusDB实例参数](https://support.huaweicloud.com/usermanual-taurusdb/taurusdb_configuration.html)。
- 执行导出的用户必须有对应库表的 SELECT和FILE权限。
- 您必须先为TaurusDB数据库集群授予OBS的访问权限，然后才能从OBS存储桶中加载数据。
  - 如果用户通过主账号开启加载OBS存储桶，不需要任何额外配置。如果是IAM子用户并且是第一次操作开启加载OBS存储桶，则需要给子用户临时配置创建委托的权限。
  
  - 加载OBS存储桶时必须拥有如下IAM权限：
    表1IAM权限与委托 
    | IAM策略   | IAM权限                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   | 委托                                                                                                                                                                     |
    |:---|:---|:---|
    | 基于角色或策略 | - iam:agencies:listAgencies  - iam:agencies:createAgency  - iam:permissions:listRolesForAgencyOnProject  - iam:permissions:grantRoleToGroupOnProject  - iam:permissions:grantRoleToAgencyOnProject  - iam:roles:listRoles  - iam:roles:createRole   如不满足，请[创建自定义策略](https://support.huaweicloud.com/usermanual-iam/iam_01_0605.html)。 | 会自动创建委托DbsObsLoadAgency，该委托用户可见，删除委托会导致加载OBS存储桶失败。                                                                                                                   |
    | 基于身份策略  | iam:agencies:list 如不满足，请[创建自定义身份策略](https://support.huaweicloud.com/usermanual-iam5/iam_01_0917.html)。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  | 需要[手动创建DbsObsLoadAgency委托](https://support.huaweicloud.com/usermanual-taurusdb/taurusdb_03_0048.html#ZH-CN_TOPIC_0000002571977878__section37482417718)。如果您已创建过委托，可跳过。 |
       
    
   
 
#### 约束限制
- 导出到OBS桶的文件数量取决于**SELECT INTO OUTFILE OBS** 语句选择的数据量以及OBS文件大小阈值。OBS默认的文件大小阈值约为6GB。
  - **数据量 \< 阈值**：生成单个OBS文件。
  
  - **数据量 ≥ 阈值**：需设置MANIFEST=ON，系统自动创建多个OBS文件，并自动生成清单文件。
   
- TaurusDB保证数据文件中的行记录不会跨文件边界拆分。系统会尽量使每个数据文件（除最后一个外）的大小接近预设阈值。为确保行数据完整性，当一行数据超出当前文件剩余空间时，整行数据也会完整写入到当前文件，此时文件大小会大于文件大小阈值。
- 如果要选择的数据量很大（超过25GB），建议您使用多个**SELECT INTO OUTFILE OBS** 语句，将数据导出到OBS中。
  每个语句应选择不同部分的数据来保存，并且在保存数据文件时OBS-URI中使用不同的object对象名。使用多个语句对数据进行分段导出，可以便于快速恢复，避免长时间运行的单个大事务，减少对数据库性能的影响。
  若某条导出语句出错，只需重新执行该部分数据，无需重新导出全部数据。
  
- 如果多个**SELECT INTO OUTFILE OBS**中 OBS_URI 相同，并且是并行执行这些语句，则导出行为是不确定的，部分SQL语句会执行失败，只有一个SQL会执行成功。
- 如果重新运行中断的**SELECT INTO OUTFILE OBS** 语句，需先删除OBS桶中与OBS_URI相同的文件，或使用**SELECT INTO OUTFILE OBS OVERWRITE ON**语句进行覆盖。
- 如果OBS桶中存在与 OBS-URI 相同的文件，导出时会报"文件已存在"，此时您可以修改OBS-URI对象名为不重复的对象名，或删除OBS文件，或配置OVERWRITE ON。
- 当前不支持查询导出进度，但可以通过导出到OBS的文件大小与所选数据量的数据大小对比，估算导出进度。
- 执行**SELECT INTO OUTFILE OBS**时，如果发生crash，需手动清理OBS残留文件。
- 语法树中的所有参数项有顺序要求，调转顺序会报语法错误。
- 导出时，SQL里面的URI的限制不能以manifest结尾，因为导出清单文件时默认使用此关键字，避免冲突。
 
#### 手动创建DbsObsLoadAgency委托
1. 登录[IAM控制台](https://console.huaweicloud.com/iam/?locale=zh-cn#/iam/users)。
2. 在统一身份认证服务的左侧导航窗格中，选择"委托"页签，在上方输入框中输入"DbsObsLoadAgency"执行搜索。 
   - 如果无此委托，执行[3]。
   
   - 如果已有委托，单击操作列的"授权"，执行[6]。
   
   
   
   
3. 在创建委托页面，设置委托信息。
   
   图1创建委托   
   ![](https://support.huaweicloud.com/usermanual-taurusdb/figure/zh-cn_image_0000002571977940.png "点击放大")
   
   - 委托名称：DbsObsLoadAgency
   
   - 委托类型：云服务
   
   - 云服务：搜索op_svc_rds，选择数据库服务DBS
   
   - 持续时间：永久
   
   
   
   
4. 单击"完成"。
5. 在授权的确认弹窗中，单击"立即授权"。
6. 搜索勾选DbsObsLoad权限，单击"下一步"。
   
   ![](https://support.huaweicloud.com/usermanual-taurusdb/figure/zh-cn_image_0000002602617045.png "点击放大")
   
   
   
7. 选择指定区域项目资源，勾选要授权的Region，单击"确定"。 
   ![](https://support.huaweicloud.com/usermanual-taurusdb/figure/zh-cn_image_0000002572137582.png "点击放大")
   
   
   
 
#### 使用SELECT INTO OUTFILE OBS导出数据
- **语法介绍**
  ```
  SELECT
      [ALL | DISTINCT | DISTINCTROW ]
      [HIGH_PRIORITY]
      [STRAIGHT_JOIN]
      [SQL_SMALL_RESULT] [SQL_BIG_RESULT] [SQL_BUFFER_RESULT]
      [SQL_CACHE | SQL_NO_CACHE] [SQL_CALC_FOUND_ROWS]
      select_expr [, select_expr ...]
      [FROM table_references
      [PARTITION partition_list]
      [WHERE where_condition]
      [GROUP BY {col_name | expr | position}
      [ASC | DESC], ... [WITH ROLLUP]]
      [HAVING where_condition]
      [ORDER BY {col_name | expr | position}
      [ASC | DESC], ...]
      [LIMIT {[offset,] row_count | row_count OFFSET offset}]
  INTO OUTFILE OBS 'OBS-URI'
      [CHARACTER SET charset_name]
      [export_options]
  [MANIFEST {ON | OFF}]
  [OVERWRITE {ON | OFF}]
  ```
  export_options:
  ```
  [FORMAT {CSV|TEXT} [HEADER]]
      [{FIELDS | COLUMNS}
          [TERMINATED BY 'string']
          [[OPTIONALLY] ENCLOSED BY 'char']
          [ESCAPED BY 'char']
      ]
      [LINES
          [STARTING BY 'string']
          [TERMINATED BY 'string']
  ]
  ```
  SELECT INTO OUTFILE OBS语句使用以下特定的必需和可选参数。更多参数请参考[MySQL官方文档](https://dev.mysql.com/doc/refman/8.0/en/select-into.html) 。
  - FORMAT {CSV\|TEXT}：指定导出文件的格式，CSV或TEXT格式。
  
  - HEADER：指定导出文件包含一个标题行，标题与SELECT语句中的列名相对应。
  
  - select_expr：要查询并导出的列或表达式。
  
  
  
  - OBS-URI：OBS文件地址，格式固定为obs://*bucket* /*object* 。
    - bucket：要将数据保存到的OBS桶的名称。
    
    - object：指定要保存到OBS的文件的名称。
     
  
  - MANIFEST {ON \| OFF}：指示是否创建清单文件。字段可选，默认为OFF。 如果在查询中指定 MANIFEST ON，则会在创建并上传所有数据文本文件后，在 OBS中自动创建JSON格式的清单文件，文件内容包含所有已上传的文本文件的url。
    文件名会添加\`.part_xxxxx\`后缀，其中xxxxx为五位整数，如：\`obs://bucket/object.part_00000\`。
    清单文件路径为：\`obs://bucket/object.manifest\`。
    清单文件是JSON格式文件，此文件列出了要保存到OBS的文本文件。其格式和内容如下：
    ```
    {
        "entries": [
            {
                "url": "obs://bucket/customermeta",
                "mandatory": true
            },
            {
                "url": "obs://bucket/customerdata",
                "mandatory": true
            }
        ]
    }
    ```
    
  
  - OVERWRITE {ON \| OFF} 指示上传到OBS时，是否覆盖桶中现有文件。如果指定OVERWRITE ON，则会覆盖相同URI的文件，否则重复文件会报错。
    
  
  - FIELDS 和 COLUMNS：可选参数。指定字段格式。
    - TERMINATED BY：指定字段间的分隔符，默认是 \\t。
    
    - ENCLOSED BY：指定字段值的封装字符，如果使用OPTIONALLY，则只封装字符类型字段；若不指定，则封装所有字段。
    
    - ESCAPED BY：指定转义字符，默认为反斜杠"\\"。
     
  
  - LINES：可选参数。指定行格式。
    - STARTING BY：指定每行数据忽略的前缀字符串。
    
    - TERMINATED BY：指定行终止符，默认为换行符"\\n"。
     
   
- **参考示例**
  - 导出单个文件。 将TaurusDB数据库中test库下的t表导出到OBS上bucket桶中的t.txt文本文件中。
    ```
    SELECT * FROM test.t into OUTFILE OBS "obs://bucket/t.txt";
    ```
    
  
  
  
  - 导出清单文件。
    - 将TaurusDB数据库中的t表数据，导出到OBS上bucket桶中的test.part_00000、test.part_00001等数据文件中，并生成test.manifest清单文件。
      ```
      SELECT * FROM t into OUTFILE OBS "obs://bucket/test" MANIFEST ON;
      ```
      
    
    - 将bucket桶中同名的文件全部覆盖，包括test.part_00000等数据文件，和test.manifest清单文件。
      ```
      SELECT * FROM t into OUTFILE OBS "obs://bucket/test" MANIFEST ON OVERWRITE ON;
      ```
      
     
  
  
  
  - 复杂导出语句示例。
    如下SQL语句从特定的分区表中提取去重后的已完成订单，进行分组统计（带 ROLLUP 总计）和降序排列，最后以标准 CSV 格式导出到 OBS。该语句开启了覆盖模式和清单记录。
    ```
    SELECT 
        DISTINCT -- 过滤重复
        HIGH_PRIORITY -- 优化器高优先级
        id, user_name, order_amount
    FROM orders
    PARTITION (p2023, p2024) -- 仅导出指定分区
    WHERE order_status = 'COMPLETED'
    GROUP BY id, user_name, order_amount
        ASC WITH ROLLUP -- 分组排序并生成聚合统计行
    HAVING order_amount > 100
    ORDER BY order_amount DESC
    LIMIT 1000 -- 只取前1000条
    INTO OUTFILE OBS 'obs://bucket/export/order_report/'
        CHARACTER SET utf8mb4 -- 指定字符集
        FORMAT CSV HEADER -- CSV格式带表头
        FIELDS 
            TERMINATED BY ',' -- 逗号分隔
            OPTIONALLY ENCLOSED BY '""' -- 字符串用双引号
            ESCAPED BY '\\' -- 反斜杠转义
        LINES 
            STARTING BY '' -- 行无前缀
            TERMINATED BY '\n' -- 换行符
        MANIFEST ON -- 生成清单文件
        OVERWRITE ON; -- 允许覆盖旧文件
    ```
    
  
  
  
  - 包含更多关键字示例。 从users表和orders表中，强制以users表为驱动进行连接，并按照用户 ID 分组（附带总计行）去重后，将结果以竖线分隔、带表头的文本格式导出到OBS存储，同时生成清单文件并覆盖已有文件。
    ```
    SELECT 
        DISTINCTROW -- 同 DISTINCT，指定从结果集中移除重复行
        SQL_SMALL_RESULT -- 告诉优化器结果集很小，直接用内存临时表
        SQL_CALC_FOUND_ROWS -- 指示计算结果集中的行数，且不考虑任何 LIMIT 子句。随后可通过 SELECT FOUND_ROWS() 获取行数
        STRAIGHT_JOIN -- 强制表连接顺序，users 表作为驱动表，orders表作为被驱动表
        u.user_id, 
        o.order_no
    FROM users u 
    JOIN orders o ON u.user_id = o.user_id
    WHERE u.status = 'active'
    GROUP BY u.user_id
        DESC
        WITH ROLLUP -- 产生小计/总计行，即在按用户ID分组统计的基础上，额外增加一行总计行
    INTO OUTFILE OBS 'obs://bucket/full_test/data_'
        CHARACTER SET gbk -- 指定字符集为 gbk
        FORMAT TEXT HEADER -- 文本格式带表头
        COLUMNS
            TERMINATED BY '|' 
            OPTIONALLY ENCLOSED BY ""'"" 
            ESCAPED BY '!' -- 使用感叹号作为转义符
        LINES 
            STARTING BY '>>>' -- 每行开头都加上前缀
            TERMINATED BY '\r\n' -- Windows 风格换行符
        MANIFEST ON 
        OVERWRITE ON;
    ```
    
   
 
#### 常见错误信息
导入文本文件时，错误信息中包含的OBS Error错误码具体含义如下：
表2OBS Error 错误码 
| 错误码                  | 错误信息   | 处理措施                              |
|:---|:---|:---|
| HttpErrorNotFound    | 对象不存在   | 请检查OBS桶中对象是否存在。                  |
| InvalidAccessKeyId | AK不合法 | SQL执行时间过长，临时AK已过期。建议避免单次导出过大数据量。 |
   
其他常见OBS错误码，请参见[OBS错误码](https://support.huaweicloud.com/api-obs/obs_04_0115.html)。
