背景
由于要替换 HANA、TeraData,必然会有数据迁移的问题
这里参考 腾讯的 DB-bridege,列出迁移中可能的问题
这里有两份腾讯的迁移相关文档,也值得参考
迁移步骤
上图是迁移 Oracle 时,给出的评估
对于HANA、TD 我们根据上图,也列出类似的情况:
- 表
- 索引
- 约束
- 视图
- 物化视图
- 函数
- 存储过程
- 触发器
- 数据类型
对于是否能迁移列出三种情况:
- 完全兼容,比如 varchar -> varchar,这种不用改,直接迁移
- 可转换的,比如Oracle的varchar2,可以用varchar替代
- 不可转换的,比如 自定义的函数,这种就没有对应的,需要在目标端也做修改
根据db-bridge的文档,在迁移Oracle时,也无法做到 100% 兼容和可转换,必然有一些无法转换的
腾讯给出的例子,无法转换的比例是 1.8% , 考虑到是对外宣传的,实际这个数字可能会高不少
而无法转换,就会导致双方都需要改动,也就是主要的迁移成本
整个迁移过程包括:
- 评估
- 测试环境搭建
- 全量数据迁移
- 数据一致性校验
- 增量数据迁移
- 数据一致性再校验
- 反向迁移(可选)
重点问题
- 源和目标数据库的表、数据类型兼容问题
- 写出迁移工具,实现自动化转换工具
- 对于少量不支持的情况,可以手动修改
- 目标库的表建完后,要跑一边源端的SQL,检查兼容性
- ETL工具本身的高可用
- db-bridge是将数据写入到本地的db中(这个db修改自PG)来保障同步过程中数据不丢
- 数据拷贝过程中,需要读源库(一般是从库),但不能对源库造成太大压力
- 增量数据如何同步
- db-bridge可能是针对Oracle开发了一套增量迁移工具
- 现有方案一般是将增量数据写入到kafka中
- 也可以将源端写入到kafka中,然后从kafka消费数据,再同时写入到 源库和目标库,需要修改应用层代码
- 增量同步过程中的也要保证高可用,数据不能丢
- 一致性校验
下面列出 HANA、TeraData的数据类型、各种语法
HANA
数据类型
参考自 官方文档
数据类型 |
描述 |
VARBINARY |
可变的二进制长度,默认为1,可以指定长度n |
BOOLEAN |
|
VARCHAR |
|
NVARCHAR |
存储unicode的varchar |
ALPHANUM |
包含字母数字的的可变长字符串 |
SHORTTEXT |
可变长字符,但只能用于 列存 |
DATE |
|
TIME |
|
SECONDDATE |
|
TIMESTAMP |
|
BLOB |
|
CLOB |
|
NCLOB |
类似CLOB,存储Unicode 值 |
TEXT |
|
ARRAY |
数组类型,其元素可以是整数、浮点数、变长字符,不支持空间、LOB,也不支持多维数组 |
TINYINT |
0 - 255 |
SMALLINT |
-32,768 到 32,767 |
INTEGER |
-2,147,483,648 到 2,147,483,647 |
BIGINT |
-9,223,372,036,854,775,808 到 9,223,372,036,854,775,807 |
DECIMAL |
|
SMALLDECIMAL |
|
REAL |
|
DOUBLE |
-1.7976931348623157E308 到 1.7976931348623157E308 |
FLOAT |
|
HANA Data Types for Spark
系统和数据类型限制
内置的函数
由于内置的函数很多,这里只给出官方文档的链接
特殊语法
一些语法示例
这里直接引用官方文档内容:
索引和视图
全文搜索 ,参考 -> 这里
1
2
|
CREATE FULLTEXT INDEX <index_name> ON <table_name> ( <column_name> )
[ <fulltext_parameter_list> ]
|
索引 ,参考 -> 这里
1
2
3
4
5
6
|
CREATE [ UNIQUE ] [ BTREE | CPBTREE | INVERTED [ <composite_type> ] ] INDEX <index_name> ON <table_name>
( <column_name_order_entry>[, <column_name_order_entry> [,...])
[ <global_index_order> ]
[ <fillfactor> ]
[ NOWAIT ]
[ ONLINE ]
|
投影视图, 参考 -> 这里
1
2
3
4
5
6
|
CREATE [ OR REPLACE ] PROJECTION VIEW <projection_view_name> [ ( <view_column_name_list> ) ]
AS SELECT <table_column_list>
FROM [ <schema>.]<source_table_name>
[ <with_association_clause> ]
[ <with_annotations_clause> ]
[ WITH DDL ONLY ]
|
视图,参考 -> 这里
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
CREATE [ OR REPLACE ] VIEW <view_name> [ COMMENT <string_literal> ]
[ ( <column_name_list> ) ] [ ( <parameterized_view_clause> ) ]
<as_subquery> [ <with_association_clause> ]
[ WITH MASK ( <column_name> USING <mask_expression> [,...] ) ]
[ WITH EXPRESSION MACROS( <expression_macro_list> ) ]
[ WITH <annotations> ]
[ WITH STRUCTURED PRIVILEGE CHECK ]
[ WITH [ <cache_type> ] CACHE ]
[ RETENTION <minute_value> ]
[ OF <projection_list> ] ]
[ FILTER <filter_condition> ]
[ <location_clause> ]
[ FORCE ]
[ WITH CHECK OPTION ]
[ WITH DDL ONLY ]
[ WITH READ ONLY ]
[ WITH ANONYMIZATION ( ALGORITHM <algorithm_name> { [ <view_level_parameters> ] [ <column_level_parameters> ] } ) ]
|
建表、scheme、同义词等
schema和同义词, 参考 -> schema
同义词
1
2
3
|
CREATE SCHEMA <schema_name> [OWNED BY <user_name>]
CREATE [OR REPLACE] SCHEMA SYNONYM <synonym_name> FOR <schema_reference>
|
同义词 , 参考 -> 这里
1
|
CREATE [ OR REPLACE ] [ PUBLIC ] SYNONYM <synonym_name> FOR <synonym_source_object_name>
|
建表, 参考 -> 这里
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
CREATE [ <table_type> ] { <table_name> | <replica_name> }
[<table_contents_source>
[<system_versioning_spec>]
[<application_time_period_configuration>]
[<bi_temporal_table_spec>]
[<with_association_clause>]
[<with_annotation_clause>]
[<with_mask_clause>]
[<logging_option>]
[<auto_merge_option>]
[<unload_priority_clause>]
[<schema_flexibility_option>]
[<partition_clause>]
[<persistent_memory_spec_clause>]
[<group_option_list>]
[<location_clause>]
[<replica_clause>]
[<global_temporary_option>]
[<series_clause>]
[<unused_retention_period_option>]
[<record_commit_timestamp_clause>]
[COMMENT <comment_string>]
[<numa_node_preference_clause>]
[<load_unit>]
|
虚拟表,参考 -> 这里
1
2
|
CREATE VIRTUAL TABLE <virtual_table_name>
AT <remote_location_clause> [ <remote_property_clause> ]
|
存储过程
函数,参考 -> 这里
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
CREATE [ OR REPLACE ] FUNCTION <function_name>
[ ( <input_parameter_clause> ) ]
RETURNS <return_type>
[ LANGUAGE <lang> ]
[ SQL SECURITY <mode> ]
[ DEFAULT SCHEMA <default_schema_name> ]
[ DETERMINISTIC ]
[ <cache_clause> ]
[ <variable_cache_clause> ]
[ WITH ENCRYPTION ]
AS
{ BEGIN
<statement_body>
END
| HEADER ONLY }
|
虚拟函数,参考 -> 这里
1
2
3
|
CREATE VIRTUAL FUNCTION <func_name> [(<parameter_clause>)]
RETURNS <return_table_type> [SQL SECURITY <mode>] [<package_clause>]
CONFIGURATION <remote_proc_properties> AT <source_name>
|
存储过程,参考 -> 这里
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
CREATE [ OR REPLACE ] PROCEDURE <proc_name> [ (<input_output_parameter_clause>) ]
[ LANGUAGE <lang> ]
[ SQL SECURITY <mode> ]
[ DEFAULT SCHEMA <default_schema_name> ]
[ DETERMINISTIC ]
[ READS SQL DATA [ WITH RESULT VIEW <view_name> ] ]
[ <route_target_element> ]
[ <variable_cache_clause> ]
[ WITH ENCRYPTION ]
[ AUTOCOMMIT DDL { ON | OFF } ]
AS
{ BEGIN [ SEQUENTIAL EXECUTION ]
<statement_body>
END
| HEADER ONLY }
|
虚拟存储过程,参考 -> 这里
1
2
3
4
5
6
7
8
9
|
CREATE VIRTUAL PROCEDURE <proc_name> [(<parameter_clause>)]
[SQL SECURITY <mode>]
[<package_clause>] LANGUAGE <lang>
AT <source_name>
[AS
BEGIN
<procedure_body>
END
]
|
用户定义的类型,参考 -> 这里
1
2
|
CREATE TYPE <type_name>
AS TABLE (<column_definition>[{,<column_definition>}...]) [ SQLSCRIPT SEARCH KEY( <column_name> [,…] ) ]
|
自增列
序列 ,参考 -> 这里
1
2
|
CREATE SEQUENCE <sequence_name> [ <sequence_parameter_list> ]
[ RESET BY <subquery> ]
|
也可以设置某一列为自增的
1
2
3
|
CREATE COLUMN TABLE "TEST" (
"ID" bigint NOT NULL primary key GENERATED BY DEFAULT AS IDENTITY
);
|
安全
详细语法,参考 -> 1 2
1
2
3
4
5
|
CREATE CLIENTSIDE ENCRYPTION COLUMN KEY [ <schema_name>.]<key_name>
[ ALGORITHM <algorithm_name> ]
{ ENCRYPTED WITH KEYPAIR <keypair_name> | HEADER ONLY }
CREATE CLIENTSIDE ENCRYPTION KEYPAIR <keypair_name> [ ALGORITHM <algorithm_name> ]
|
数据集成
详细语法细节,参考 -> 这里
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
CREATE ADAPTER <adapter_name> [PROPERTIES <properties>] AT LOCATION
{DPSERVER | AGENT <agent_name>}
CREATE AGENT <agent_name> PROTOCOL { 'HTTP' | 'TCP' HOST <agent_hostname> PORT <agent_port_number> [{ENABLE | DISABLE} SSL]} [AGENT GROUP <agent_group_name>]
CREATE AGENT GROUP <agent_group_name>
<audit_action_name> ::= CREATE AGENT
| ALTER AGENT
| DROP AGENT
| CREATE AGENT GROUP
| DROP AGENT GROUP
| CREATE ADAPTER
| ALTER ADAPTER
| DROP ADAPTER
| CREATE REMOTE SUBSCRIPTION
| ALTER REMOTE SUBSCRIPTION
| DROP REMOTE SUBSCRIPTION
| PROCESS REMOTE SUBSCRIPTION EXCEPTION
CREATE REMOTE SUBSCRIPTION [<schema_name>.]<subscription_name>
{
{ON [<schema_name>.]<virtual_table_name> } |
{AS (<subquery>)}
}
[ WITH SCHEMA CHANGES ]
{ TARGET TABLE <table_spec> <load_behavior> } |
{ TARGET TASK <task_spec> } |
{ PROCEDURE <proc_spec> }
|
其他
图表工作区 ,参考 -> 这里
1
2
3
4
5
6
7
|
CREATE GRAPH WORKSPACE <workspace_name>
EDGE TABLE <edge_table_name>
SOURCE COLUMN <source_column_name>
TARGET COLUMN <target_column_name>
KEY COLUMN <edge_key_column_name>
VERTEX TABLE <vertex_table_name>
KEY COLUMN <vertex_key_column_name>
|
统计信息 ,参考 -> 这里
1
2
3
4
|
CREATE STATISTICS [ <data_statistics_name> ] ON <data_sources>
[ <data_statistics_type> ]
[ <data_statistics_properties> ]
[ <initial_refresh> ]
|
触发器,参考 -> 这里
1
2
3
4
5
6
7
8
9
10
11
|
CREATE [ OR REPLACE ] TRIGGER <trigger_name> <trigger_action_time> <trigger_event_list>
ON <subject_table_name>
[ REFERENCING <transition_list> ]
[ <for_each> ]
[ <trigger_order_clause> ]
[ ONLINE ]
BEGIN
[ <trigger_decl_list> ]
[ <proc_handler_list> ]
<trigger_stmt_list>
END
|
租户,参考 -> 这里
1
2
3
4
5
6
|
CREATE DATABASE <database_name> [ AT [ LOCATION ] '<hostname>[:<port_number> ] ' ]
{ ADD '<servicetype>' [ AT [ LOCATION ] '<hostname>[:<port_number> ] ' ] }...
[ { AS REPLICA OF [ <source_database_name> ] AT [ LOCATION ] '<hostname>[:<port_number> ]' | SYSTEM USER PASSWORD <password> } ]
[ OS USER '<username>' OS GROUP '<groupname>' ]
[ NO START ]
[ <restart_mode> RESTART ]
|
workload 和映射,参考 -> 这里
映射
1
2
3
4
|
CREATE WORKLOAD CLASS <workload_class_name> [ <property_list> ] [ ENABLE | DISABLE ]
CREATE WORKLOAD MAPPING <mapping_name>
WORKLOAD CLASS <workloadclass_name> [ <property_list> [ <wildcard_option> ] ]
|
WAL
没有找到相关资料
案例
TeraData
数据类型
参考自 官方文档
文档中没有列出数据的范围
数据类型 |
描述 |
ARRAY |
|
VARRAY |
同上,长度可变 |
BYTE |
二进制类型 |
VARBYTE |
同上,长度可变 |
BLOB |
二进制大对象 |
CHAR |
|
VARCHAR |
|
CLOB |
|
AVRO |
带有schema 自描述的数据类型 |
DATE |
|
TIME |
|
TIMESTAMP |
|
TIME WITH TIME ZONE |
|
TIMESTAMP WITH TIME ZONE |
|
ST_Geometry |
地理位置数据,TD提供了对这个数据的检索、分析接口 |
MBR |
也是地理位置数据 |
INTERVAL YEAR |
时间间隔类型 |
INTERVAL YEAR TO MONTH |
|
INTERVAL MONTH |
|
INTERVAL DAY |
|
INTERVAL DAY TO HOUR |
|
INTERVAL DAY TO MINUTE |
|
INTERVAL DAY TO SECOND |
|
INTERVAL HOUR |
|
INTERVAL HOUR TO MINUTE |
|
INTERVAL HOUR TO SECOND |
|
INTERVAL MINUTE |
|
INTERVAL MINUTE TO SECOND |
|
INTERVAL SECOND |
|
JSON |
json格式数据 |
BYTEINT |
整数类型 |
SMALLINT |
|
INTEGER |
|
BIGINT |
|
DECIMAL/NUMERIC |
浮点类型 |
FLOAT/REAL/DOUBLE PRECISION |
|
NUMBER |
|
TD_ANYTYPE |
参数类型,这种类型只能用在 函数、方法、存储过程、外部存储过程的输入/输出中 |
VARIANT_TYPE |
同上 |
PERIOD(DATE) |
时间周期数据,其周期是一系列时间粒度数据,包含开头边界,但没有结束边界 |
PERIOD(TIME) |
同上 |
PERIOD(TIME WITH TIME ZONE) |
同上 |
PERIOD(TIMESTAMP) |
同上 |
PERIOD(TIMESTAMP WITH TIME ZONE) |
同上 |
Distinct |
用户自定义的数据类型 |
Structured |
同上 |
XML |
XML格式数据,内部是按照二进制方式存储的 |
内置的函数
由于内置的函数很多,这里只给出官方文档的链接
特殊语法
设置多重集表
Teradata基于如何处理重复记录将表分类为SET或MULTISET表。
- SET表的表不存储重复记录
- MULTISET表可存储重复记录
建表语句如下:
注意,建表时有一个关键字FALLBACK
,这相当于配置了一个副本,用于高可用的
1
2
3
4
5
6
7
8
9
|
CREATE SET TABLE EMPLOYEE,FALLBACK (
EmployeeNo INTEGER,
FirstName VARCHAR(30),
LastName VARCHAR(30),
DOB DATE FORMAT 'YYYY-MM-DD',
JoinedDate DATE FORMAT 'YYYY-MM-DD',
DepartmentNo BYTEINT
)
UNIQUE PRIMARY INDEX ( EmployeeNo );
|
宏
这是TD的特殊语法,类似存储过程,也有输入参数
宏里面包括多个SQL语句,而且整个 宏,是当做事务来执行的
1
2
3
4
5
6
7
8
9
10
11
12
13
|
CREATE MACRO <macroname> [(parameter1, parameter2,...)] (
<sql statements>
);
CREATE MACRO Get_Emp AS (
SELECT EmployeeNo, FirstName, LastName
FROM
employee
ORDER BY EmployeeNo;
);
-- 执行宏
EXEC <macroname>;
|
临时表
TD包含三种临时表:
- 一次查询中的,这是自动产生的
- 一次session中的
- 全局的
主要考虑后两种
session临时表
1
2
3
4
5
6
7
8
|
CREATE VOLATILE TABLE dept_stat (
dept_no INTEGER,
avg_salary INTEGER,
max_salary INTEGER,
min_salary INTEGER
)
PRIMARY INDEX(dept_no)
ON COMMIT PRESERVE ROWS;
|
全局临时表
1
2
3
4
5
6
7
|
CREATE SET GLOBAL TEMPORARY TABLE dept_stat (
dept_no INTEGER,
avg_salary INTEGER,
max_salary INTEGER,
min_salary INTEGER
)
PRIMARY INDEX(dept_no);
|
物化视图
join索引其实就是物化视图,包含这么几种:
- 单表连接索引(STJI)
- 多表连接索引(MTJI)
- 聚合连接索引(AJI)
语法:
1
2
3
4
5
6
7
8
9
10
11
12
|
CREATE JOIN INDEX <index name>
AS
<SELECT Query>
<Index Definition>;
-- 创建索引
CREATE JOIN INDEX Employee_JI
AS
SELECT EmployeeNo,FirstName,LastName,
BirthDate,JoinedDate,DepartmentNo
FROM Employee
PRIMARY INDEX(FirstName);
|
索引
主索引,类似主键
- 唯一主索引(UPI)
- 非唯一主索引(NUPI),允许重复
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
-- 唯一主索引
CREATE SET TABLE Salary (
EmployeeNo INTEGER,
Gross INTEGER,
Deduction INTEGER,
NetPay INTEGER
)
UNIQUE PRIMARY INDEX(EmployeeNo);
-- 非唯一主索引
CREATE SET TABLE Employee _Accounts (
EmployeeNo INTEGER,
employee_bank_account_type BYTEINT.
employee_bank_account_number INTEGER,
employee_bank_name VARCHAR(30),
employee_bank_city VARCHAR(30)
)
PRIMARY INDEX(EmployeeNo);
|
二级索引
包括:
- 唯一二级指数(USI)
- 非唯一二级指数(NUSI),允许重复
1
2
3
4
5
|
-- 唯一二级索引
CREATE UNIQUE INDEX(EmployeeNo) on employee;
-- 非唯一二级索引
CREATE INDEX(FirstName) on Employee;
|
分区索引
1
2
3
4
5
6
7
8
9
10
|
CREATE SET TABLE Orders (
StoreNo SMALLINT,
OrderNo INTEGER,
OrderDate DATE FORMAT 'YYYY-MM-DD',
OrderTotal INTEGER
)
PRIMARY INDEX(OrderNo)
PARTITION BY RANGE_N (
OrderDate BETWEEN DATE '2010-01-01' AND '2016-12-31' EACH INTERVAL '1' DAY
);
|
压缩
限制:
- 每列只能压缩255个值
- 主索引列不能压缩
- 不能压缩易失性表
列应用压缩时,此列的值不与该行一起存储。 相反,值存储在每个AMP中的表头中
1
2
3
4
5
6
7
8
9
10
11
|
-- 压缩第1、2、3列
CREATE SET TABLE employee (
EmployeeNo integer,
FirstName CHAR(30),
LastName CHAR(30),
BirthDate DATE FORMAT 'YYYY-MM-DD-',
JoinedDate DATE FORMAT 'YYYY-MM-DD-',
employee_gender CHAR(1),
DepartmentNo CHAR(02) COMPRESS(1,2,3)
)
UNIQUE PRIMARY INDEX(EmployeeNo);
|
自增列
语法如下,官方文档
1
2
3
4
5
6
7
8
9
|
create table TEST.i2 (
i INTEGER GENERATED BY DEFAULT AS IDENTITY
(START WITH 1
INCREMENT BY 1
NO MAXVALUE
NO CYCLE
),
STR VARCHAR(20)
) unique primary index i2 (i)
|
其他
存储过程
1
2
3
4
5
6
7
|
CREATE PROCEDURE <procedurename> ( [parameter 1 data type, parameter 2 data type..] )
BEGIN
<SQL or SPL statements>;
END;
--调用
CALL <procedure name> [(parameter values)];
|
统计信息
1
2
3
4
|
COLLECT STATISTICS COLUMN(EmployeeNo) ON Employee;
-- 查看表的统计信息
HELP STATISTICS employee;
|
不区分大小写 CASESPECIFIC
1
2
3
|
CREATE TABLE xxx (
name VARCHAR(200) CHARACTER SET LATIN NOT CASESPECIFIC,
);
|
COALESCE
返回表达式的第一个非空值的语句。 如果表达式的所有参数计算结果为NULL,则返回NULL
1
2
3
4
5
|
SELECT
EmployeeNo,
COALESCE(dept_no, 'Department not found')
FROM
employee;
|
WAL
没有找到WAL的具体格式
TD是OLAP类型的,所以WAL这块不用特别考虑,增量这块就用停机迁移来解决
像 TD自己的大版本迁移都是会有停机迁移情况
案例
建行数据从Teradata迁移到Greenplum
Teradata应用迁移至AnalyticDB PostgreSQL
Teradata SQL迁移GaussDB
传统数仓从 Teradata 迁移到 Hadoop平台实践
如何从Teradata迁移到Greenplum(上篇)
如何从Teradata迁移到Greenplum(下篇)
其他情况
1、转义字符
2、大小写
参考
TeraData官方文档
TeraData在线语法手册
HANA官方手册
HANA官方SQL语法文档
TeraData在线教程
HANA在线教程
Oracle应用迁移至AnalyticDB PostgreSQL
TBASE和ORACLE语法兼容清单.pdf
腾讯DBbridge产品-典型交付案例介绍.pptx