OceanBase 知识加油站(工具篇一):准备好您的数据了吗?

387 阅读10分钟

玉璁,OceanBase 工具团队技术专家 孙夕恩,花名玉璁,长期从事基础架构与中间件领域研发工作。现任职于 OceanBase 工具团队,负责基础组件&工具的研发工作,致力于为 OceanBase 建设一套完善的生态工具体系。在Java、分布式、基础架构、中间件、“去O”等领域有着较为丰富的研发实战经验。

  引言

在企业级的应用系统中,不是所有的业务都是使用在线迁移/同步工具处理数据。有些业务使用导出工具将数据库中的数据导出,再导入到其它库中供业务分析;有些业务使用导出工具将数据库中的数据导出,文件传递给其它系统进行处理....包括定期逻辑备份恢复,日常的离线迁移等操作,我们都需要将数据库中的模式或者数据导出到文件中。我们只有准确地理解不同的数据格式的规范,熟练地使用导入导出工具,才能在日常的工作中更好地运用这些数据。

本文主要是结合 OceanBase 开源的导入导出工具,讲述常用的数据格式、最佳实践、常见案例和一些注意事项。

正文

OBLOADER 是一款使用 Java 开发的客户端导入工具,提供向 OceanBase 数据库导入结构和数据的能力。该工具提供了非常灵活的命令行选项,您可以在多种复杂的场景下,将结构和数据导入到 OceanBase 数据库中。OBLOADER 主要与 OBDUMPER 搭配使用。但是在外部业务中,OBLOADER 也支持如 Navicat、Mydumper 和 SQLDeveloper 等工具导出的 SQL 或 CSV 格式的文件导入。OBLOADER 充分利用 OceanBase 分布式系统的特性,重点优化了导入的性能。  

文件大小限制和建议

强烈建议您不要直接使用太大的文件,例如 100 GB 或更大的数据文件。如果您使用的导数工具(如 mysqldump 和 SQLDeveloper 等)无法按照文件块导出时,我们可以寻找第三方的切分工具对大文件进行切分。下述介绍了在不同系统下如何进行数据切分。 

Linux or macOSX

使用系统内置的切分命令 split 就可以把大的 CSV 文件切分成若干小的文件。 split [-a suffix_length] [-bbyte_count[k|m]] [-l line_count] [-p pattern] [file [name]] 示例语句如下所示:split -l 100000 pagecounts-20210723.csvpages

上述示例是将数据文件 pagecounts-20210723.csv 根据行数进行切分。假设当前文件大小是 8 GB,且包含 1000 万行数据,以 100,000 行作为条件,将大文件切分成 100 份子文件,每一份子文件的名称以pages作为后缀且大小将是80MB(1,000,000/100,000=100)。

 注意: split 命令是根据行数切分文件,数据存在换行时可能会出现切分错误。 

Windows

Windows 平台没有系统内置的切分工具。但是在网上您可以搜索许多第三方的切分工具和脚本用来切分大文件。

说明: 1.使用 OBDUMPER 导出数据时,为了避免将一张表中所有的数据写入单个文件从而导致在磁盘中生成超大文件的情况,程序默认会限制文件的大小是 1 GB。如果导出的数据体积超出 1 GB,程序会生成一份新的文件并继续写入。 2.使用 OBLOADER 导入数据时,为了提升导入性能,程序内部默认会对文件进行逻辑拆分。需要注意的是,这里只是逻辑拆分,过程中不会产生任何临时文件。即使遇到大文件(100 GB 以上),程序也可以在很短的时间内完成文件拆分,从而并行解析每一份子文件,然后并发导入到数据库中。因此,您无需启动多个 OBLOADER 进程进行并发导入的操作。

准确地辨识数据格式

在离线迁移和逻辑备份等场景中 OBDUMPER 支持三种通用的数据格式,包括 CSV、Insert 和 Delimited Text。文件格式与文件后缀名不是同一个概念。文件格式,通常是指文件中的内容的组织形式。例如 123.csv 文件通常存放的是 CSV 格式的数据,文件使用 .csv 作为后缀名是为了增加辨识度。您也可以在 123.txt 文件中存放 CSV 格式的数据,它并不影响软件程序解析该数据文件,只是您可能会难以通过文件名辨识文件中的内容。为了准确地确认数据格式,最快速的办法就是预览部分数据内容。这一节,我们主要教大家如何辨识这些数据格式,避免日常操作中频犯错误。 

CSV 格式

CSV 格式是业界最常见的、最通用的数据保存格式,也是我们推荐使用的数据格式。除了基本的格式规范(参照:RFC4180 <点击阅读原文查看>)以外,需要特别注意以下 2 个容易犯错的地方。 1、数据中含有某种特殊字符。CSV 格式的基本符号有定界符、列分隔符和行分隔符。如果数据中存在上述符号或者 NULL 值,导出的命令中必须要设置转义符参数,否则生成的 CSV 文件是无法被正确地解析。

2、CSV 格式与 Excel 格式的区别。CSV 是文本格式,可以用任何编辑器打开预览。Excel 格式是二进制格式,只能使用 Microsoft Excel 软件打开。由于 Excel 软件可以解析 CSV 格式的数据,所以不少用户习惯用 Excel 软件预览 CSV 文件的内容,但是这要求您熟知 CSV 格式的灵活性以及对于 Excel 软件有较高的熟练度。例如 Excel 软件解析 CSV 文件时,其默认定界符是双引号,列分隔符是逗号,转义符是双引号。假设打开的 CSV 文件中没有使用 Excel 软件默认的符号,结果预览的就是错误的内容。另外,Windows 版本的 Excel 软件支持配置 CSV 格式,而 MacOS 版本的 Excel 软件不支持该配置。

下述为 CSV 的格式样例:

图片

CSV Header 是指 CSV 文件中第一行存放的是表中的列名,用户可以选择不插入列头。(可选)CSV Record 是指 CSV 文件中存放的是表中的数据。数据中含有的定界符、分隔符、换行符和 NULL 等需要转义。

Insert 格式

Insert 格式就是我们最熟悉的 Insert SQL 语句,为了确保 SQL 语法的正确性,您必须设置正确的转义符号。 Insert SQL 语句中一些容易造成语法错误的原因:

1.对象名或者列名是 SQL 关键字。该问题会导致 SQL 语句执行失败,解决办法是生成 Insert SQL 语句时,程序逻辑中给对象名或者列名加上转义符号。例如,Oracle 语法使用双引号转义("),MySQL 语法使用反引号(`)转义。

2.业务数据中存在单引号。该问题会造成 Insert SQL 解析错误,解决办法是生成 Insert SQL 语句时,程序逻辑中给数据做特殊字符的转义替换。使用 OBDUMPER 工具导出数据时,默认会对数据做转义处理,所以最终可以保证生成的是语法正确的 Insert SQL 语句。

下述为 Insert 格式样例:

图片 

Delimited Tex t 格式

Delimited Text 格式是最简单的文本格式,也是最容易与 CSV 格式混淆的格式。CSV 格式的分隔符只能是单个字符,默认是逗号。Delimited Text 格式的分隔符可以是单个字符,也可以是多个字符。Delimited Text 格式的基本符号是列分隔符和换行符,没有定界符。数据中不能出现与基本符号相冲突的字符,否则程序无法正确地解析。例如,Delimited Text 格式要求一行数据在文件中独占一行,假设数据中存在换行,最终解析出来的就是两行数据。

下述为 Delimited Text 格式样例:

图片 

半结构化数据的处理

通常我们所遇见的半结构化数据格式是 JSON 或 XML 数据类型。这两种数据类型自身也是一种复合的数据定义格式。比如,在 JSON 或者 XML 数据节点中可以存放 CSV 或者 Insert SQL 语句等任意格式的数据。所以您在准备数据的时候,一定要做好数据的定界和转义。目前文件中存在该类型的数据是无法被正确切分的,所以使用 OBLOADER 导入文件中包含 JSON 或者 XML 类型的数据时,可以调整文件拆分的阈值参数,让程序跳过对文件的自动拆分。 

二进制大对象的处理

像RAW、BINARY 和LOB(Large ObjectBinary)等二进制大对象类型在企业级的业务中的应用并不少见,有些数据库导入导出工具并不支持处理这些数据类型。强烈要求您将二进制类型的数据编码成 16 进制的字符串才能进行文件存储和解析,OBDUMPER 和 MySQLDump 等工具默认也是这么处理的。极端场景下,LOB 类型可能存储数百 MB 甚至若干 GB 的数据,这为导入导出工具的性能和存储空间两个方面带来巨大的挑战。您在日常的操作中,可以尽量将存在二进制大对象数据类型的表单独进行处理。 

日期时间类型的处理

在 Oracle 或者 OceanBaseOracle 模式下,日期时间相关的数据类型是比较复杂的,而且在使用的过程中也是极其容易犯错。比如精度、格式和时区错误等。

源库导出数据前,要求设置符合预期的日期时间格式,目标库导入前,也要设置符合预期的日期时间格式。假设源库和目标库的日期时间格式不一致,日期时间类型的数据是无法被正确地导入。在日常操作中,这种问题是很常见的。其次,不同数据库的日期时间类型存在差异。例如,DATE 类型在 MySQL、DB2、Oracle 和 OceanBase 等各个不同的数据库中所表示的日期时间信息是有差异的。而这些差异,您只能自行查阅数据库文档来解决兼容性的问题,否则可能会出现精度丢失或者写入失败等问题。

您可以通过下述参数设置日期时间数据的格式:

NLS_DATE_FORMAT              YYYY-MM-DDNLS_TIMESTAMP_FORMAT         YYYY-MM-DD HH24:MI:SSXFF AMNLS_TIMESTAMP_TZ_FORMAT      YYYY-MM-DD HH24:MI:SSXFF AM TZR 

写在最后

从数据库中导出数据时,只要您仔细根据上述的指导建议,并进行检查和设置。那么无论使用哪一种导数工具,它都能够产生符合要求的数据文件。同样,您也能够轻松地运用好这些数据文件以便于后续的导入工作。切记不要图省事儿!