摘要:本文主要介绍使用kettle设计
![](/icons/24740yi.gif)
些ETL任务时
![](/icons/24740yi.gif)
些常见问题
![](/icons/24740dou.gif)
这些问题大部分都不在官方FAQ上
![](/icons/24740dou.gif)
你可以在kettle
![](/icons/24740de.gif)
论坛上找到
![](/icons/24740yi.gif)
些问题
![](/icons/24740de.gif)
答案
![](http://www.crazycoder.cn/WebFiles/200812/ff3043a9-5475-4f61-a3f4-82be07186cfd.jpg)
1. Join
我得到A 数据流(不管是基于文件或数据库)
![](/icons/24740dou.gif)
A包含field1 , field2 , field3 字段
![](/icons/24740dou.gif)
然后我还有
![](/icons/24740yi.gif)
个B数据流
![](/icons/24740dou.gif)
B包含field4 , field5 , field6 , 我现在想把它们 ‘加’ 起来, 应该如何样做.
这是新手最容易犯错
![](/icons/24740de.gif)
![](/icons/24740yi.gif)
个地方
![](/icons/24740dou.gif)
A数据流跟B数据流能够Join
![](/icons/24740dou.gif)
肯定是它们包含join key ,join key 可以是
![](/icons/24740yi.gif)
个字段也可以是多个字段
![](/icons/24740dou2.gif)
如果两个数据流没有join key ,那么它们就是在做笛卡尔积
![](/icons/24740dou.gif)
![](/icons/24740yi.gif)
般很少会这样
![](/icons/24740dou2.gif)
比如你现在需要列出
![](/icons/24740yi.gif)
个员工
![](/icons/24740de.gif)
姓名和他所在部门
![](/icons/24740de.gif)
姓名
![](/icons/24740dou.gif)
如果这是在同
![](/icons/24740yi.gif)
个数据库
![](/icons/24740dou.gif)
大家都知道会在
![](/icons/24740yi.gif)
个sql 里面加上where 限定条件
![](/icons/24740dou.gif)
但是如果员工表和部门表在两个区别
![](/icons/24740de.gif)
数据流里面
![](/icons/24740dou.gif)
尤其是数据源
![](/icons/24740de.gif)
来源是多个数据库
![](/icons/24740de.gif)
情况
![](/icons/24740dou.gif)
我们
![](/icons/24740yi.gif)
般是要使用Database Join 操作
![](/icons/24740dou.gif)
然后用两个database table input 来表示输入流
![](/icons/24740dou.gif)
![](/icons/24740yi.gif)
个输入是部门表
![](/icons/24740de.gif)
姓名
![](/icons/24740dou.gif)
另
![](/icons/24740yi.gif)
个是员工表
![](/icons/24740de.gif)
姓名
![](/icons/24740dou.gif)
然后我们认为这两个表就可以 ”Join” 了
![](/icons/24740dou.gif)
我们需要
![](/icons/24740de.gif)
输出
![](/icons/24740de.gif)
确是这两个字段
![](/icons/24740dou.gif)
但是这两个字段
![](/icons/24740de.gif)
输出并不代表只需要这两个字段
![](/icons/24740de.gif)
输入
![](/icons/24740dou.gif)
它们的间肯定是需要
![](/icons/24740yi.gif)
个约束关系存在
![](/icons/24740de.gif)
![](/icons/24740dou2.gif)
另外
![](/icons/24740dou.gif)
无论是在做 Join , Merge , Update , Delete 这些常规操作
![](/icons/24740de.gif)
时候
![](/icons/24740dou.gif)
都是先需要做
![](/icons/24740yi.gif)
个compare 操作
![](/icons/24740de.gif)
![](/icons/24740dou.gif)
这个compare 操作都是针对compare key
![](/icons/24740de.gif)
![](/icons/24740dou.gif)
无论两个表结构是不是
![](/icons/24740yi.gif)
样
![](/icons/24740de.gif)
![](/icons/24740dou.gif)
比如employee 表和department 表
![](/icons/24740dou.gif)
它们比较
![](/icons/24740de.gif)
依据就是employee
![](/icons/24740de.gif)
外键department_id , 没有这个compare key 这两个表是不可能连接
![](/icons/24740de.gif)
起来
![](/icons/24740de.gif)
.. 对于两个表可能还有人知道是直接sql 来做连接
![](/icons/24740dou.gif)
如果是多个输入数据源
![](/icons/24740dou.gif)
然后是 3个表
![](/icons/24740dou.gif)
有人就开始迷茫了
![](/icons/24740dou.gif)
A表
![](/icons/24740yi.gif)
个字段
![](/icons/24740dou.gif)
B表
![](/icons/24740yi.gif)
个字段
![](/icons/24740dou.gif)
C表
![](/icons/24740yi.gif)
个字段
![](/icons/24740dou.gif)
然后就连Join操作都没有
![](/icons/24740dou.gif)
直接 database table output , 然后开始报错
![](/icons/24740dou.gif)
报完错就到处找高手问
![](/icons/24740dou.gif)
他们
![](/icons/24740de.gif)
数据库原理老师已经在吐血了
![](/icons/24740dou2.gif)
如果是 3个表连接
![](/icons/24740dou.gif)
![](/icons/24740yi.gif)
个sql 不能搞定
![](/icons/24740dou.gif)
就需要先两个表两个表
![](/icons/24740de.gif)
连接
![](/icons/24740dou.gif)
通过两次compare key 连接的后得到你
![](/icons/24740de.gif)
输出
![](/icons/24740dou.gif)
记住
![](/icons/24740dou.gif)
你
![](/icons/24740de.gif)
输出并不能代表你
![](/icons/24740de.gif)
输入. 下面整理总结
![](/icons/24740yi.gif)
下:
1. 单数据源输入
![](/icons/24740dou.gif)
直接用sql 做连接
2. 多数据源输入
![](/icons/24740dou.gif)
(可能是文本或是两个以上源数据库)
![](/icons/24740dou.gif)
用database join 操作.
3. 3个表以上
![](/icons/24740de.gif)
多字段输出.
2. Kettle
![](/icons/24740de.gif)
数据库连接模式
Kettle
![](/icons/24740de.gif)
数据库连接是
![](/icons/24740yi.gif)
个步骤里面控制
![](/icons/24740yi.gif)
个单数据库连接
![](/icons/24740dou.gif)
所以kettle
![](/icons/24740de.gif)
连接有数据库连接池
![](/icons/24740dou.gif)
你可以在指定
![](/icons/24740de.gif)
数据库连接里面指定
![](/icons/24740yi.gif)
开始连接池里面放多少个数据库连接
![](/icons/24740dou.gif)
在创建数据库连接
![](/icons/24740de.gif)
时候就有Pooling 选项卡
![](/icons/24740dou.gif)
里面可以指定最大连接数和
![](/icons/24740chushi.gif)
连接数
![](/icons/24740dou.gif)
这可以
![](/icons/24740yi.gif)
定程度上提高速度.
3. transaction
我想在步骤A执行
![](/icons/24740yi.gif)
个操作(更新或者插入)
![](/icons/24740dou.gif)
然后在经过若干个步骤的后
![](/icons/24740dou.gif)
如果我发现某
![](/icons/24740yi.gif)
个条件成立
![](/icons/24740dou.gif)
我就提交所有
![](/icons/24740de.gif)
操作
![](/icons/24740dou.gif)
如果失败
![](/icons/24740dou.gif)
我就回滚
![](/icons/24740dou.gif)
kettle提供这种事务性
![](/icons/24740de.gif)
操作吗?
Kettle 里面是没有所谓事务
![](/icons/24740de.gif)
概念
![](/icons/24740de.gif)
![](/icons/24740dou.gif)
每个步骤都是自己管理自己
![](/icons/24740de.gif)
连接
![](/icons/24740de.gif)
![](/icons/24740dou.gif)
在这个步骤开始
![](/icons/24740de.gif)
时候打开数据库连接
![](/icons/24740dou.gif)
在结束
![](/icons/24740de.gif)
时候关闭数据库连接
![](/icons/24740dou.gif)
![](/icons/24740yi.gif)
个步骤是肯定不会跨session
![](/icons/24740de.gif)
(数据库里面
![](/icons/24740de.gif)
session), 另外
![](/icons/24740dou.gif)
由于kettle是并行执行
![](/icons/24740de.gif)
![](/icons/24740dou.gif)
所以不可能把
![](/icons/24740yi.gif)
个数据库连接打开很长时间不放
![](/icons/24740dou.gif)
这样可能会造成锁出现
![](/icons/24740dou.gif)
虽然不
![](/icons/24740yi.gif)
定是死锁
![](/icons/24740dou.gif)
但是对性能还是影响太大了
![](/icons/24740dou2.gif)
ETL中
![](/icons/24740de.gif)
事务对性能影响也很大
![](/icons/24740dou.gif)
所以不应该设计
![](/icons/24740yi.gif)
种依赖和事务方式
![](/icons/24740de.gif)
ETL执行顺序
![](/icons/24740dou.gif)
毕竟这不是OLTP
![](/icons/24740dou.gif)
![](/icons/24740yinwei.gif)
你可能
![](/icons/24740yi.gif)
次需要提交
![](/icons/24740de.gif)
数据量是几百 GB都有可能
![](/icons/24740dou.gif)
任何
![](/icons/24740yi.gif)
种数据库维持
![](/icons/24740yi.gif)
个几百GB
![](/icons/24740de.gif)
回滚段性能都是会不大幅下降
![](/icons/24740de.gif)
.
4. 我真
![](/icons/24740de.gif)
需要transaction 但又不想要
![](/icons/24740yi.gif)
个很复杂
![](/icons/24740de.gif)
设计
![](/icons/24740dou.gif)
能不能提供
![](/icons/24740yi.gif)
个简单
![](/icons/24740yi.gif)
点
![](/icons/24740de.gif)
方式
Kettle 在3.0.2GA版中将推出
![](/icons/24740yi.gif)
种新功能
![](/icons/24740dou.gif)
在
![](/icons/24740yi.gif)
个table output 步骤中有
![](/icons/24740yi.gif)
个Miscellaneous 选项卡
![](/icons/24740dou.gif)
其中有
![](/icons/24740yi.gif)
个Use unique connections
![](/icons/24740de.gif)
选项
![](/icons/24740dou.gif)
如果你选中
![](/icons/24740de.gif)
话就可以得到
![](/icons/24740yi.gif)
个transaction
![](/icons/24740de.gif)
简单版
![](/icons/24740dou.gif)
由于是使用
![](/icons/24740de.gif)
单数据库连接
![](/icons/24740dou.gif)
所以可以有
![](/icons/24740cuowu.gif)
![](/icons/24740de.gif)
时候回滚事务
![](/icons/24740dou.gif)
不过要提醒
![](/icons/24740yi.gif)
点是这种方式是以牺牲非常大
![](/icons/24740de.gif)
性能为前提条件
![](/icons/24740de.gif)
![](/icons/24740dou.gif)
对于太大
![](/icons/24740de.gif)
数据量是不适合
![](/icons/24740de.gif)
(个人仍然不建议使用这种方式)
5. temporary 表如何使用
我要在ETL过程中创建
![](/icons/24740yi.gif)
个中间表
![](/icons/24740dou.gif)
当某个条件成立
![](/icons/24740de.gif)
时候
![](/icons/24740dou.gif)
我要把中间表
![](/icons/24740de.gif)
数据进行转换
![](/icons/24740dou.gif)
当另
![](/icons/24740yi.gif)
条件成立
![](/icons/24740de.gif)
时候我要对中间表进行另
![](/icons/24740yi.gif)
个操作
![](/icons/24740dou.gif)
我想使用数据库
![](/icons/24740de.gif)
临时表来操作
![](/icons/24740dou.gif)
应该用什么步骤
![](/icons/24740dou2.gif)
首先从temp 表
![](/icons/24740de.gif)
生命周期来分
![](/icons/24740dou.gif)
temp分为事务临时表和会话临时表
![](/icons/24740dou.gif)
前面已经解释过了
![](/icons/24740dou.gif)
kettle是没有所谓事务
![](/icons/24740de.gif)
概念
![](/icons/24740de.gif)
![](/icons/24740dou.gif)
所以自然也没有所谓
![](/icons/24740de.gif)
事务临时表
![](/icons/24740dou2.gif)
Kettle
![](/icons/24740de.gif)
每个步骤管理自己
![](/icons/24740de.gif)
数据库连接
![](/icons/24740dou.gif)
连接
![](/icons/24740yi.gif)
结束
![](/icons/24740dou.gif)
kettle也就自然丢掉了这个连接
![](/icons/24740de.gif)
session
![](/icons/24740de.gif)
handler , 没有办法可以在其他步骤拿回这个session
![](/icons/24740de.gif)
handler , 所以也就不能使用所谓
![](/icons/24740de.gif)
会话临时表
![](/icons/24740dou.gif)
当你尝试再开
![](/icons/24740yi.gif)
个连接
![](/icons/24740de.gif)
时候
![](/icons/24740dou.gif)
你可以连上这个临时表
![](/icons/24740dou.gif)
但是你想要
![](/icons/24740de.gif)
临时表里面
![](/icons/24740de.gif)
数据都已经是空
![](/icons/24740de.gif)
(数据不
![](/icons/24740yi.gif)
定被清除了
![](/icons/24740dou.gif)
但是你连不上了)
![](/icons/24740dou.gif)
所以不要设计
![](/icons/24740yi.gif)
个需要使用临时表
![](/icons/24740de.gif)
转换
的所以会使用临时表
![](/icons/24740dou.gif)
其实跟需要 ”事务” 特性有
![](/icons/24740yi.gif)
点类似
![](/icons/24740dou.gif)
都是希望在ETL过程中提供
![](/icons/24740yi.gif)
种缓冲
![](/icons/24740dou2.gif)
临时表很多时候都不是某
![](/icons/24740yi.gif)
个源表
![](/icons/24740de.gif)
全部数据
![](/icons/24740de.gif)
镜像
![](/icons/24740dou.gif)
很多时候临时表都是很小
![](/icons/24740yi.gif)
部分结果集
![](/icons/24740dou.gif)
可能经过了某种计算过程
![](/icons/24740dou.gif)
你需要临时表无非是基于下面 3个特性:
1. 表结构固定
![](/icons/24740dou.gif)
用
![](/icons/24740yi.gif)
个固定
![](/icons/24740de.gif)
表来接受
![](/icons/24740yi.gif)
部分数据
![](/icons/24740dou2.gif)
2. 每次连接
![](/icons/24740de.gif)
时候里面没有数据
![](/icons/24740dou2.gif)
你希望它接受数据
![](/icons/24740dou.gif)
但是不保存
![](/icons/24740dou.gif)
每次都好像执行了truncate table 操作
![](/icons/24740yi.gif)
样
3. 区别
![](/icons/24740de.gif)
时候连接临时表用同
![](/icons/24740yi.gif)
个名字
![](/icons/24740dou.gif)
你不想使用多个连接
![](/icons/24740de.gif)
时候用类似和temp1 , temp2 , temp3 , temp4 这种名字
![](/icons/24740dou.gif)
应为它们表结构
![](/icons/24740yi.gif)
样
![](/icons/24740dou2.gif)
既然临时表不能用
![](/icons/24740dou.gif)
应该如何设计ETL过程呢?(可以用某种诡异
![](/icons/24740de.gif)
操作搞出临时表
![](/icons/24740dou.gif)
不过不建议这样做罢了)
如果你
![](/icons/24740de.gif)
ETL过程比较
![](/icons/24740de.gif)
单线程性
![](/icons/24740dou.gif)
也就是你清楚
![](/icons/24740de.gif)
知道同
![](/icons/24740yi.gif)
时间只有
![](/icons/24740yi.gif)
个这样
![](/icons/24740de.gif)
表需要
![](/icons/24740dou.gif)
你可以创建
![](/icons/24740yi.gif)
个普通
![](/icons/24740de.gif)
表
![](/icons/24740dou.gif)
每次连接
![](/icons/24740de.gif)
时候都执行truncate 操作
![](/icons/24740dou.gif)
不论是通过table output
![](/icons/24740de.gif)
truncate table 选项
![](/icons/24740dou.gif)
还是通过手工执行truncate table sql 语句(在execute sql script 步骤)都可以达到目
![](/icons/24740de.gif)
(基于上面
![](/icons/24740de.gif)
1
![](/icons/24740dou.gif)
2 特性)
如果你
![](/icons/24740de.gif)
ETL操作比较
![](/icons/24740de.gif)
多线程性
![](/icons/24740dou.gif)
同
![](/icons/24740yi.gif)
时间可能需要多个表结构
![](/icons/24740yi.gif)
样并且里面都是为空
![](/icons/24740de.gif)
表(基于上面1
![](/icons/24740dou.gif)
2
![](/icons/24740dou.gif)
3特性)
![](/icons/24740dou.gif)
你可以创建
![](/icons/24740yi.gif)
个 “
![](/icons/24740zifu.gif)
串+序列”
![](/icons/24740de.gif)
模式
![](/icons/24740dou.gif)
每次需要
![](/icons/24740de.gif)
时候
![](/icons/24740dou.gif)
就创建这样
![](/icons/24740de.gif)
表
![](/icons/24740dou.gif)
用完的后就删除
![](/icons/24740dou.gif)
![](/icons/24740yinwei.gif)
你自己不
![](/icons/24740yi.gif)
定知道你需要多少个这种类型
![](/icons/24740de.gif)
表
![](/icons/24740dou.gif)
所以删除会比truncate 好
![](/icons/24740yi.gif)
些
![](/icons/24740dou2.gif)
下面举个例子如何创建这种表:
你可以使用某种约定
![](/icons/24740de.gif)
表名比如department_temp 作为department
![](/icons/24740de.gif)
临时表
![](/icons/24740dou2.gif)
或者
把argument 传到表名
![](/icons/24740dou.gif)
使用 department_${argument}
![](/icons/24740de.gif)
语法
如果你需要多个这种表
![](/icons/24740dou.gif)
使用
![](/icons/24740yi.gif)
个sequence 操作+execute sql script 操作
![](/icons/24740dou.gif)
execute sql script 就下面这种模式
Create table_? (…………..)
在表
![](/icons/24740de.gif)
名字上加参数
![](/icons/24740dou.gif)
前面接受
![](/icons/24740yi.gif)
个sequence 或类似
![](/icons/24740de.gif)
输入操作.
需要注意
![](/icons/24740de.gif)
是这种参数表名包括database table input 或者execute sql script
![](/icons/24740dou.gif)
只要是参数作为表名
![](/icons/24740de.gif)
情况前面
![](/icons/24740de.gif)
输入不能是从数据库来
![](/icons/24740de.gif)
,应为没有办法执行这种preparedStatement 语句
![](/icons/24740dou.gif)
从数据库来
![](/icons/24740de.gif)
值后面
![](/icons/24740de.gif)
操作是 “值操作” ,而不是
![](/icons/24740zifu.gif)
串替换
![](/icons/24740dou.gif)
只有argument 或者sequence 操作当作参数才是
![](/icons/24740zifu.gif)
串替换. (这
![](/icons/24740yi.gif)
点官方FAQ也有提到)
6. update table 和execute sql script 里面执行update
![](/icons/24740de.gif)
区别
执行update table 操作是比较慢
![](/icons/24740de.gif)
![](/icons/24740dou.gif)
它会
![](/icons/24740yi.gif)
条
![](/icons/24740yi.gif)
条基于compare key 对比数据
![](/icons/24740dou.gif)
然后决定是不是要执行update sql , 如果你知道你要如何更新数据尽可能
![](/icons/24740de.gif)
使用execute sql script 操作
![](/icons/24740dou.gif)
在里面手写update sql (注意源数据库和目标数据库在哪)
![](/icons/24740dou.gif)
这种多行执行方式(update sql)肯定比单行执行方式(update table 操作)快
![](/icons/24740de.gif)
多
![](/icons/24740dou2.gif)
另
![](/icons/24740yi.gif)
个区别是execute sql script 操作是可以接受参数
![](/icons/24740de.gif)
输入
![](/icons/24740de.gif)
![](/icons/24740dou2.gif)
它前面可以是
![](/icons/24740yi.gif)
个跟它完全不关
![](/icons/24740de.gif)
表
![](/icons/24740yi.gif)
个sql :
select field1, field2 field3 from tableA
后面执行另
![](/icons/24740yi.gif)
个表
![](/icons/24740de.gif)
更新操作:
update tableB
![](/icons/24740set.gif)
field4 = ? where field5=? And field6=?
然后选中execute sql script
![](/icons/24740de.gif)
execute for each row .注意参数是
![](/icons/24740yi.gif)
![](/icons/24740yi.gif)
对应
![](/icons/24740de.gif)
.(field4 对应field1
![](/icons/24740de.gif)
值
![](/icons/24740dou.gif)
field5 对应field2
![](/icons/24740de.gif)
值
![](/icons/24740dou.gif)
field6 对应field3
![](/icons/24740de.gif)
值)
7. kettle
![](/icons/24740de.gif)
性能
kettle本身
![](/icons/24740de.gif)
性能绝对是能够应对大型应用
![](/icons/24740de.gif)
![](/icons/24740dou.gif)
![](/icons/24740yi.gif)
般
![](/icons/24740de.gif)
基于平均行长150
![](/icons/24740de.gif)
![](/icons/24740yi.gif)
条记录
![](/icons/24740dou.gif)
假设源数据库
![](/icons/24740dou.gif)
目标数据库以及kettle都分别在几台机器上(最常见
![](/icons/24740de.gif)
桌面工作模式
![](/icons/24740dou.gif)
双核
![](/icons/24740dou.gif)
1G内存)
![](/icons/24740dou.gif)
速度大概都可以到5000 行每秒左右
![](/icons/24740dou.gif)
如果把硬件提高
![](/icons/24740yi.gif)
些
![](/icons/24740dou.gif)
性能还可以提升 , 但是ETL 过程中难免遇到性能问题
![](/icons/24740dou.gif)
下面
![](/icons/24740yi.gif)
些通用
![](/icons/24740de.gif)
步骤也许能给你
![](/icons/24740yi.gif)
些帮助.
尽量使用数据库连接池
尽量提高批处理
![](/icons/24740de.gif)
commit size
尽量使用缓存Cache
![](/icons/24740dou.gif)
缓存Cache尽量大
![](/icons/24740yi.gif)
些(主要是文本文件和数据流)
Kettle 是Java 做
![](/icons/24740de.gif)
![](/icons/24740dou.gif)
尽量用大
![](/icons/24740yi.gif)
点
![](/icons/24740de.gif)
内存参数启动Kettle.
可以使用sql 来做
![](/icons/24740de.gif)
![](/icons/24740yi.gif)
些操作尽量用sql
Group , merge , stream lookup ,split field 这些操作都是比较慢
![](/icons/24740de.gif)
![](/icons/24740dou.gif)
想办法避免他们.
![](/icons/24740dou.gif)
能用sql 就用sql
插入大量数据
![](/icons/24740de.gif)
时候尽量把索引删掉
尽量避免使用update , delete 操作
![](/icons/24740dou.gif)
尤其是update , 如果可以把update 变成先delete , 后insert .
能使用truncate table
![](/icons/24740de.gif)
时候
![](/icons/24740dou.gif)
就不要使用delete all row 这种类似sql
合理
![](/icons/24740de.gif)
分区
如果删除操作是基于某
![](/icons/24740yi.gif)
个分区
![](/icons/24740de.gif)
![](/icons/24740dou.gif)
就不要使用delete row 这种方式(不管是delete sql 还是delete 步骤),直接把分区drop 掉
![](/icons/24740dou.gif)
再重新创建
尽量缩小输入
![](/icons/24740de.gif)
数据集
![](/icons/24740de.gif)
大小(增量更新也是为了这个目
![](/icons/24740de.gif)
)
尽量使用数据库原生
![](/icons/24740de.gif)
方式装载文本文件(Oracle
![](/icons/24740de.gif)
sqlloader , mysql
![](/icons/24740de.gif)
bulk loader 步骤)
尽量不要用kettle
![](/icons/24740de.gif)
calculate 计算步骤
![](/icons/24740dou.gif)
能用数据库本身
![](/icons/24740de.gif)
sql 就用sql ,不能用sql 就尽量想办法用procedure , 实在不行才是calculate 步骤.
要知道你
![](/icons/24740de.gif)
性能瓶颈在哪
![](/icons/24740dou.gif)
可能有时候你使用了不恰当
![](/icons/24740de.gif)
方式
![](/icons/24740dou.gif)
导致整个操作都变慢
![](/icons/24740dou.gif)
观察kettle log 生成
![](/icons/24740de.gif)
方式来了解你
![](/icons/24740de.gif)
ETL操作最慢
![](/icons/24740de.gif)
地方
![](/icons/24740dou2.gif)
远程数据库用文件+FTP
![](/icons/24740de.gif)
方式来传数据
![](/icons/24740dou.gif)
文件要压缩
![](/icons/24740dou2.gif)
(只要不是局域网都可以认为是远程连接)
8. 描述物理环境
源数据库
![](/icons/24740de.gif)
操作系统
![](/icons/24740dou.gif)
硬件环境
![](/icons/24740dou.gif)
是单数据源还是多数据源
![](/icons/24740dou.gif)
数据库如何分布
![](/icons/24740de.gif)
![](/icons/24740dou.gif)
做ETL
![](/icons/24740de.gif)
那台机器放在哪
![](/icons/24740dou.gif)
操作系统和硬件环境是什么
![](/icons/24740dou.gif)
目标数据仓库
![](/icons/24740de.gif)
数据库是什么
![](/icons/24740dou.gif)
操作系统
![](/icons/24740dou.gif)
硬件环境
![](/icons/24740dou.gif)
数据库
![](/icons/24740de.gif)
![](/icons/24740zifu.gif)
集如何选
![](/icons/24740dou.gif)
数据传输方式是什么
![](/icons/24740dou.gif)
开发环境
![](/icons/24740dou.gif)
测试环境和实际
![](/icons/24740de.gif)
生产环境有什么区别
![](/icons/24740dou.gif)
是不是需要
![](/icons/24740yi.gif)
个中间数据库(staging 数据库)
![](/icons/24740dou.gif)
源数据库
![](/icons/24740de.gif)
数据库版本号是多少
![](/icons/24740dou.gif)
测试数据库
![](/icons/24740de.gif)
版本号是多少
![](/icons/24740dou.gif)
真正
![](/icons/24740de.gif)
目标数据库
![](/icons/24740de.gif)
版本号是多少……. 这些信息也许很零散
![](/icons/24740dou.gif)
但是都需要
![](/icons/24740yi.gif)
份专门
![](/icons/24740de.gif)
文档来描述这些信息
![](/icons/24740dou.gif)
无论是你遇到问题需要别人帮助
![](/icons/24740de.gif)
时候描述问题本身
![](/icons/24740dou.gif)
还是发现测试环境跟目标数据库
![](/icons/24740de.gif)
版本号不
![](/icons/24740yi.gif)
致,这份专门
![](/icons/24740de.gif)
文档都能提供
![](/icons/24740yi.gif)
些基本
![](/icons/24740de.gif)
信息
9. procedure
为什么我不能触发procedure?
这个问题在官方FAQ里面也有提到
![](/icons/24740dou.gif)
触发procedure 和 http client 都需要
![](/icons/24740yi.gif)
个类似和触发器
![](/icons/24740de.gif)
条件
![](/icons/24740dou.gif)
你可以使用generate row 步骤产生
![](/icons/24740yi.gif)
个空
![](/icons/24740de.gif)
row ,然后把这条记录连上procedure 步骤
![](/icons/24740dou.gif)
这样就会使这条没有记录
![](/icons/24740de.gif)
空行触发这个procedure (如果你打算使用无条件
![](/icons/24740de.gif)
单次触发)
![](/icons/24740dou.gif)
当然procedure 也可以象table input 里面
![](/icons/24740de.gif)
步骤那样传参数并且多次执行.
另外
![](/icons/24740yi.gif)
个建议是不要使用复杂
![](/icons/24740de.gif)
procedure 来完成本该ETL任务完成
![](/icons/24740de.gif)
任务
![](/icons/24740dou.gif)
比如创建表
![](/icons/24740dou.gif)
填充数据
![](/icons/24740dou.gif)
创建物化视图等等.
10.
![](/icons/24740zifu.gif)
集
Kettle使用Java 通常使用
![](/icons/24740de.gif)
UTF8 来传输
![](/icons/24740zifu.gif)
集
![](/icons/24740dou.gif)
所以无论你使用何种数据库
![](/icons/24740dou.gif)
任何数据库种类
![](/icons/24740de.gif)
![](/icons/24740zifu.gif)
集
![](/icons/24740dou.gif)
kettle 都是支持
![](/icons/24740de.gif)
![](/icons/24740dou.gif)
如果你遇到了
![](/icons/24740zifu.gif)
集问题
![](/icons/24740dou.gif)
也许下面这些提示可以帮助你:
1. 单数据库到单数据库是绝对不会出现乱码问题
![](/icons/24740de.gif)
![](/icons/24740dou.gif)
不管原数据库和目标数据库是何种种类
![](/icons/24740dou.gif)
何种
![](/icons/24740zifu.gif)
集
2. 多种区别
![](/icons/24740zifu.gif)
集
![](/icons/24740de.gif)
原数据库到
![](/icons/24740yi.gif)
个目标数据库
![](/icons/24740dou.gif)
你首先需要确定多种源数据库
![](/icons/24740de.gif)
![](/icons/24740zifu.gif)
集
![](/icons/24740de.gif)
最大兼容
![](/icons/24740zifu.gif)
集是什么
![](/icons/24740dou.gif)
如果你不清楚
![](/icons/24740dou.gif)
最好
![](/icons/24740de.gif)
办法就是使用UTF8来创建数据库.
3. 不要以你工作
![](/icons/24740de.gif)
环境来判断
![](/icons/24740zifu.gif)
集:现在某
![](/icons/24740yi.gif)
个测试人员手上有
![](/icons/24740yi.gif)
个oracle
![](/icons/24740de.gif)
基于xxx
![](/icons/24740zifu.gif)
集
![](/icons/24740de.gif)
已经存在
![](/icons/24740de.gif)
数据库
![](/icons/24740dou.gif)
并且非常不幸
![](/icons/24740de.gif)
是xxx
![](/icons/24740zifu.gif)
集不是utf8 类型
![](/icons/24740de.gif)
![](/icons/24740dou.gif)
于是他把另
![](/icons/24740yi.gif)
个基于yyy
![](/icons/24740zifu.gif)
集
![](/icons/24740de.gif)
oracle 数据库要经过某
![](/icons/24740yi.gif)
个ETL过程转换到oracle , 后来他发现无论如何样设置都会出现乱码
![](/icons/24740dou.gif)
这是
![](/icons/24740yinwei.gif)
你
![](/icons/24740de.gif)
数据库本身
![](/icons/24740de.gif)
![](/icons/24740zifu.gif)
集不支持
![](/icons/24740dou.gif)
无论你如何设置都是没用
![](/icons/24740de.gif)
. 测试
![](/icons/24740de.gif)
数据库不代表最后产品运行
![](/icons/24740de.gif)
数据库
![](/icons/24740dou.gif)
尤其是有时候为了省事把多个区别
![](/icons/24740de.gif)
项目
![](/icons/24740de.gif)
不相关
![](/icons/24740de.gif)
数据库装在同
![](/icons/24740yi.gif)
台机器上
![](/icons/24740dou.gif)
测试
![](/icons/24740de.gif)
时候又没有分析清楚这种环境
![](/icons/24740dou.gif)
所以也再次强调描述物理环境
![](/icons/24740de.gif)
重要性.
4. 你所看到
![](/icons/24740de.gif)
不
![](/icons/24740yi.gif)
定代表实际储存
![](/icons/24740de.gif)
:mysql 处理
![](/icons/24740zifu.gif)
集
![](/icons/24740de.gif)
时候是要在jdbc 连接
![](/icons/24740de.gif)
参数里面加上
![](/icons/24740zifu.gif)
集参数
![](/icons/24740de.gif)
![](/icons/24740dou.gif)
而oracle 则是需要服务器端和客户端使用同
![](/icons/24740yi.gif)
种
![](/icons/24740zifu.gif)
集才能正确显示
![](/icons/24740dou.gif)
所以你要明确你所看到
![](/icons/24740de.gif)
![](/icons/24740zifu.gif)
集乱码不
![](/icons/24740yi.gif)
定代表真
![](/icons/24740de.gif)
就是
![](/icons/24740zifu.gif)
集乱码
![](/icons/24740dou.gif)
这需要你检查在转换的前
![](/icons/24740de.gif)
![](/icons/24740zifu.gif)
集是否会出现乱码和转换的后是否出现乱码
![](/icons/24740dou.gif)
你
![](/icons/24740de.gif)
桌面环境可能需要变动
![](/icons/24740yi.gif)
些参数来适应这种变动
5. 不要在
![](/icons/24740yi.gif)
个转换中使用多个
![](/icons/24740zifu.gif)
集做为数据源.
11. 预定义时间维
Kettle提供了
![](/icons/24740yi.gif)
个小工具帮助我们预填充时间维
![](/icons/24740dou.gif)
这个工具在kettle_home / samples / transformations / General – populate date dimension. 这个举例产生
![](/icons/24740de.gif)
数据不
![](/icons/24740yi.gif)
定能满足各种需要
![](/icons/24740dou.gif)
不过你可以通过修改这个举例来满足自己
![](/icons/24740de.gif)
需求.
12. SQL tab 和 Options tab
在你创建
![](/icons/24740yi.gif)
个数据库连接
![](/icons/24740de.gif)
时候除了可以指定你
![](/icons/24740yi.gif)
次需要
![](/icons/24740chushi.gif)
化
![](/icons/24740de.gif)
连接池参数的外(在 Pooling 选项卡下面)
![](/icons/24740dou.gif)
还包括
![](/icons/24740yi.gif)
个Options 选项卡和
![](/icons/24740yi.gif)
个 SQL 选项卡, Options 选项卡里面主要设置
![](/icons/24740yi.gif)
些连接时
![](/icons/24740de.gif)
参数
![](/icons/24740dou.gif)
比如autocommit 是on 还是off , defaultFetchSize , useCursorFetch (mysql 默认支持
![](/icons/24740de.gif)
)
![](/icons/24740dou.gif)
oracle 还支持比如defaultExecuteBatch , oracle.jdbc.StreamBufferSize, oracle.jdbc.FreeMemoryOnEnterImplicitCache ,你可以查阅对应数据库所支持
![](/icons/24740de.gif)
连接参数
![](/icons/24740dou.gif)
另外
![](/icons/24740yi.gif)
个小提示:在创建数据库连接
![](/icons/24740de.gif)
时候
![](/icons/24740dou.gif)
选择你
![](/icons/24740de.gif)
数据库类型
![](/icons/24740dou.gif)
然后选到Options 选项卡
![](/icons/24740dou.gif)
下面有
![](/icons/24740yi.gif)
个Show help text _disibledevent="_blank">Kettle