技術分享 | OceanBase 資料處理之控制檔案

愛可生雲資料庫發表於2023-02-21

作者:楊文

DBA,負責客戶專案的需求與維護,會點資料庫,不限於MySQL、Redis、Cassandra、GreenPlum、ClickHouse、Elastic、TDSQL等等。

本文來源:原創投稿

*愛可生開源社群出品,原創內容未經授權不得隨意使用,轉載請聯絡小編並註明來源。


1、問題描述

有時我們在匯入匯出資料時,需要對資料進行處理,來滿足業務上的資料需求,此時需要使用控制檔案配合導數工具來滿足業務上不同資料的需求。

2、控制檔案模板:

lang=java(
  列名 位元組偏移位置(可選) "預處理函式" 對映定義(可選),
  列名 位元組偏移位置(可選) "預處理函式" 對映定義(可選),
  列名 位元組偏移位置(可選) "預處理函式" 對映定義(可選)
);

簡單示例:

lang=java
server=mysql/oracle
(
    c1 "nvl(c1,'not null')" map(field_position),
    c2 "none" map(field_position)
);

引數說明:

  • field_position為匯入的資料檔案中預處理資料的列位置。
  • 控制檔案的命名規範:table_name.ctl,大小寫與資料庫中保持一致。
  • 控制檔案的內容要求列名的順序與表中定義的列順序保持一致,且列名大小寫與表中的列名大小寫保持一致。

3、使用案例:

3.1、測試資料:

cat /data/test/TABLE/test.dat
1@##oceanbase@##2023-01-12 15:00:00.0@##1@##ob@##1@##ob
2@##oceanbase@##2023-01-12 15:00:00.0@##2@##ob@##2@##ob
3@##oceanbase@##2023-01-12 15:00:00.0@##3@##ob@##3@##ob

create table test01 (
id int(10) not null primary key,
name varchar(10),
time timestamp not null default '1971-01-01 01:01:01',
blank varchar(255) null
);

create table test02 (
id int(10) not null primary key,
name varchar(10) not null,
time timestamp not null,
bar varchar(255) default null,
blank varchar(255) default null,
line varchar(255) default null,
mark  varchar(255) default null,
test  varchar(255) not null
);

3.2、案例1:

表列少於文字列:表全列匯入。

控制檔案:

vi /data/test01.ctl
lang=java(
id "none" map(1),
name "none" map(2),
time "none" map(3),
blank "none" map(5)
);

匯入語句:

./obloader -h 10.186.60.94 -P 2883 -u root -p rootroot \
-c ywob -t mysql_yw_tent -D ywdb --table test01 --cut \
-f /data/test/TABLE/test.dat --log-path /data/ --external-data \
--replace-data --column-splitter '@##' --ctl-path /data/test01.ctl

輸出結果:

All Dump Tasks Finished:
----------------------------------------------------------------------------------------------------
         No.#      |        Type       |        Name       |       Count       |       Status
----------------------------------------------------------------------------------------------------
          1        |       TABLE       |      test01       |         3         |      SUCCESS
-------------------------------------------------------------------------

可以看到是成功的。此時,我們進庫再進行select查詢資料進行驗證,可以看到的確是成功的。

3.3、案例2:

表列少於文字列:表部分列匯入。

控制檔案:

vi /data/test01.ctl
lang=java(
id "none" map(1)
);

匯入資料,可以看到報錯資訊:

Error:"Field 'id' doesn't have a default value"

修改控制檔案:

vi /data/test01.ctl
lang=java(
id "none" map(1),
name "none" map(2)
);

此時再匯入是成功的。

說明:

  • 插入部分列時,需要為插入的每列,在引數檔案中指定對應的文字列。
  • not null列必須有對應的插入資料,或者是有預設值。

3.4、案例3:

表列多於文字列:全列匯入。

控制檔案:

vi /data/test02.ctl
lang=java(
id "none" map(1),
name "none" map(2),
time "none" map(3),
bar "none" map(4),
blank "none" map(5),
line "none" map(6),
mark "none" map(7)
);

匯入語句:

./obloader -h 10.186.60.94 -P 2883 -u root -p rootroot \
-c ywce -t mysql_yw_tent -D ywdb --table test02 --cut \
-f /data/test/TABLE/test.dat --log-path /data/ --external-data \
--replace-data --column-splitter '@##' --ctl-path /data/test02.ctl

輸出結果:

All Dump Tasks Finished:
----------------------------------------------------------------------------------------------------
         No.#      |        Type       |        Name       |       Count       |       Status
----------------------------------------------------------------------------------------------------
          1        |       TABLE       |      test02       |         3         |      SUCCESS
----------------------------------------------------------------------------------------------------

可以看到是成功的。但是今天在另一個同版本的OB環境下意外的發現了一個怪事,竟然報錯了:

Error: Column count doesn't match value count at row 1

報錯資訊:列數不匹配。

根據這種情況進行分析:發現JDK版本不一致。並且可以看到匯入的資料檔案比表結構少一列,資料檔案以“@##”作為列分隔符,並且最後一列結尾沒有分隔符。

解決:

方式1:修改控制檔案:

vi /data/test02.ctl
lang=java(
id "none" map(1),
name "none" map(2),
time "none" map(3),
bar "none" map(4),
blank "none" map(5),
line "none" map(6),
mark "none" map(7),
test "none" map(1)
);

方式2:修改表結構,最後一個欄位可以為null。

方式3:修改資料檔案,在最後面新增‘@##’字尾。

3.5、在使用“obdumper+控制檔案”匯出資料時,也有可能會出現該報錯資訊:

Error: Column count doesn't match value count at row 1

可能的原因:資料庫名大小寫敏感,即資料庫中的庫名是小寫,但是匯出命令中寫成了大寫,導致控制檔案中的配置內容不生效。

補充:

其實,還可以使用SUBSTR(char,position[,length ])進行擷取處理資料;

示例:

SUBSTR('abc',0,3)

小建議:

資料匯入後進行簡單檢視每個欄位匯入的資料是否是對應的。可能存在某些情況下資料匯入了,但實際資料和欄位並沒有對齊,可能只是恰巧資料能存入對應欄位。以及檢視中文是否正常顯示。

相關文章