kettle使⽤中遇到的⼀些常见问题总结
⼤数据在ETL处理过程中,使⽤的⼯具有kettle, dataStage,infomatica等等。kettle是属于开源免费的etl ⼯具。基于java开发,内置了很多强⼤的⼯具,在数据清洗加⼯处理⽅⾯,有优越的性能和处理效率。当然如果内置的组件不能满⾜要求,还⽀持⼆次开发插件来解决问题,实现功能。下⾯简单对⽇常中使⽤kettle中出现的问题做⼀个总结,⽅便⾃⼰也⽅便⼤家查问题的原因和解决思路。
1. Join
我得到A 数据流(不管是基于⽂件或数据库),A包含field1 , field2 , field3 字段,然后我还有⼀个B数据流,B包含field4 ,field5 , field6 , 我现在想把它们 ‘加’ 起来, 应该怎么样做.
这是新⼿最容易犯错的⼀个地⽅,A数据流跟B数据流能够Join,肯定是它们包含join key ,join key 可以是⼀个字段也可以是多个字段。如果两个数据流没有join key ,那么它们就是在做笛卡尔积,⼀般很少会这样。⽐如你现在需要列出⼀个员⼯的姓名和他所在部门的姓名,如果这是在同⼀个数据库,⼤家都知道会在⼀个sql ⾥⾯加上where 限定条件,但是如果员⼯表和部门表在两个不同的数据流⾥⾯,尤其是数据源的来源是多个数据库的情况,我们⼀般是要使⽤Database Join 操作,然后⽤两个database table input 来表⽰输⼊流,⼀个输⼊是部门表的姓名,另⼀个是员⼯表的姓名,然后我们认为这两个表就可以 ”Join” 了,我们需要的输出的确是这两个字段,但是这两个字段的输出并不代表只需要这两个字
段的输⼊,它们之间肯定是需要⼀个约束关系存在的。另外,⽆论是在做Join , Merge , Update , Delete 这些常规操作的时候,都是先需要做⼀个compare 操作的,这个compare 操作都是针对compare key 的,⽆论两个表结构是不是⼀样的,⽐如employee 表和department 表,它们⽐较的依据就是employee 的外键department_id , 没有这个compare key 这两个表是不可能连接的起来的.. 对于两个表可能还有⼈知道是直接sql 来做连接,如果是多个输⼊数据源,然后是三个表,有⼈就开始迷茫了,A表⼀个字段,B表⼀个字段,C表⼀个字段,然后就连Join操作都没有,直接database table output , 然后开始报错,报完错就到处⾼⼿问,他们的数据库原理⽼师已经在吐⾎了。如果是三个表连接,⼀个sql 不能搞定,就需要先两个表两个表的连接,通过两次compare key 连接之后得到你的输出,记住,你的输出并不能代表你的输⼊. 下⾯总结⼀下:
1. 单数据源输⼊,直接⽤sql 做连接
2. 多数据源输⼊,(可能是⽂本或是两个以上源数据库),⽤database join 操作.
3. 三个表以上的多字段输出.
2. Kettle的数据库连接模式
Kettle的数据库连接是⼀个步骤⾥⾯控制⼀个单数据库连接,所以kettle的连接有数据库连接池,你可
以在指定的数据库连接⾥⾯指定⼀开始连接池⾥⾯放多少个数据库连接,在创建数据库连接的时候就有Pooling 选项卡,⾥⾯可以指定最⼤连接数和初始连接数,这可以⼀定程度上提⾼速度.
3. transaction
我想在步骤A执⾏⼀个操作(更新或者插⼊),然后在经过若⼲个步骤之后,如果我发现某⼀个条件成⽴,我就提交所有的操作,如果失败,我就回滚,kettle提供这种事务性的操作吗?
Kettle⾥⾯是没有所谓事务的概念的,每个步骤都是⾃⼰管理⾃⼰的连接的,在这个步骤开始的时候打开数据库连接,在结束的时候关闭数据库连接,⼀个步骤是肯定不会跨session的(数据库⾥⾯的session), 另外,由于kettle是并⾏执⾏的,所以不可能把⼀个数据库连接打开很长时间不放,这样可能会造成锁出现,虽然不⼀定是死锁,但是对性能还是影响太⼤了。ETL中的事务对性能影响也很⼤,所以不应该设计⼀种依赖与事务⽅式的ETL执⾏顺序,毕竟这不是OLTP,因为你可能⼀次需要提交的数据量是⼏百GB都有可能,任何⼀种数据库维持⼀个⼏百GB的回滚段性能都是会不⼤幅下降的.
4. 我真的需要transaction 但⼜不想要⼀个很复杂的设计,能不能提供⼀个简单⼀点的⽅式
Kettle 在3.0.2GA版中将推出⼀种新功能,在⼀个table output 步骤中有⼀个Miscellaneous 选项卡,其中有⼀个Use unique connections 的选项,如果你选中的话就可以得到⼀个transaction 的简单版,
由于是使⽤的单数据库连接,所以可以有错误的时候回滚事务,不过要提醒⼀点是这种⽅式是以牺牲⾮常⼤的性能为前提条件的,对于太⼤的数据量是不适合的(个⼈仍然不建议使⽤这种⽅式)
5. temporary 表如何使⽤
我要在ETL过程中创建⼀个中间表,当某个条件成⽴的时候,我要把中间表的数据进⾏转换,当另⼀条件成⽴的时候我要对中间表进⾏另⼀个操作,我想使⽤数据库的临时表来操作,应该⽤什么步骤。
⾸先从temp 表的⽣命周期来分,temp分为 事务临时表和会话临时表,前⾯已经解释过了,kettle是没有所谓事务的概念的,所以⾃然也没有所谓的事务临时表。Kettle的每个步骤管理⾃⼰的数据库连接,连接⼀结束,kettle也就⾃然丢掉了这个连接的session 的handler , 没有办法可以在其他步骤拿回这个session 的handler , 所以也就不能使⽤所谓的会话临时表,当你尝试再开⼀个连接的时候,你可以连上这个临时表,但是你想要的临时表⾥⾯的数据都已经是空的(数据不⼀定被清除了,但是你连不上了),所以不要设计⼀个需要使⽤临时表的转换
之所以会使⽤临时表,其实跟需要 ”事务” 特性有⼀点类似,都是希望在ETL过程中提供⼀种缓冲。临时表很多时候都不是某⼀个源表的全部数据的镜像,很多时候临时表都是很⼩⼀部分结果集,可能经过了某种计算过程,你需要临时表⽆⾮是基于下⾯三个特性:
1. 表结构固定,⽤⼀个固定的表来接受⼀部分数据。
2. 每次连接的时候⾥⾯没有数据。你希望它接受数据,但是不保存,每次都好像执⾏了truncate table 操作⼀样
3. 不同的时候连接临时表⽤同⼀个名字,你不想使⽤多个连接的时候⽤类似与temp1 , temp2 , temp3 , temp4 这种名字,应为它们表结构⼀样。
既然临时表不能⽤,应该如何设计ETL过程呢?(可以⽤某种诡异的操作搞出临时表,不过不建议这样做罢了)
如果你的ETL过程⽐较的单线程性,也就是你清楚的知道同⼀时间只有⼀个这样的表需要,你可以创建⼀个普通的表,每次连接的时候都执⾏truncate 操作,不论是通过table output 的truncate table 选项,还是通过⼿⼯执⾏truncate table sql 语句(在execute sql script 步骤)都可以达到⽬的(基于上⾯的1,2 特性)
如果你的ETL操作⽐较的多线程性,同⼀时间可能需要多个表结构⼀样并且⾥⾯都是为空的表(基于上⾯1,2,3特性),你可以创建⼀个 “字符串+序列”的模式,每次需要的时候,就创建这样的表,⽤完之后就删除,因为你⾃⼰不⼀定知道你需要多少个这种类型的表,所以删除会⽐truncate 好⼀些。
下⾯举个例⼦怎么创建这种表:
你可以使⽤某种约定的表名⽐如department_temp 作为department 的临时表。或者
把argument 传到表名,使⽤ department_${argument} 的语法,
如果你需要多个这种表,使⽤⼀个sequence 操作+execute sql script 操作,execute sql script 就下⾯这种模式
Create table_?(…………..)
在表的名字上加参数,前⾯接受⼀个sequence 或类似的输⼊操作.
大数据etl工具有哪些 需要注意的是这种参数表名包括database table input 或者execute sql script ,只要是参数作为表名的情况前⾯的输⼊不能是从数据库来的,应为没有办法执⾏这种preparedStatement语句,从数据库来的值后⾯的操作是 “值操作” ,⽽不是字符串替换,只有argument 或者sequence 操作当作参数才是字符串替换. (这⼀点官⽅FAQ也有提到)
6. update table 和execute sql script ⾥⾯执⾏update 的区别
执⾏update table 操作是⽐较慢的,它会⼀条⼀条基于compare key 对⽐数据,然后决定是不是要执⾏update sql , 如果你知道你要怎么更新数据尽可能的使⽤execute sql script 操作,在⾥⾯⼿写upda
te sql (注意源数据库和⽬标数据库在哪),这种多⾏执⾏⽅式(update sql)肯定⽐单⾏执⾏⽅式(update table 操作)快的多。
另⼀个区别是execute sql script 操作是可以接受参数的输⼊的。它前⾯可以是⼀个跟它完全不关的表⼀个sql :
select field1, field2 field3 from tableA
后⾯执⾏另⼀个表的更新操作:
update tableB set field4 = ? where field5=? And field6=?
然后选中execute sql script 的execute for each row .注意参数是⼀⼀对应的.(field4 对应field1 的值,
field5 对应field2 的值, field6 对应field3 的值)
7. kettle的性能
kettle本⾝的性能绝对是能够应对⼤型应⽤的,⼀般的基于平均⾏长150的⼀条记录,假设源数据库,⽬标数据库以及kettle都分别在⼏台机器上(最常见的桌⾯⼯作模式,双核,1G内存),速度⼤概都
可以到5000 ⾏每秒左右,如果把硬件提⾼⼀些,性能还可以提升 ,但是ETL 过程中难免遇到性能问题,下⾯⼀些通⽤的步骤也许能给你⼀些帮助.
尽量使⽤数据库连接池
尽量提⾼批处理的commit size
尽量使⽤缓存,缓存尽量⼤⼀些(主要是⽂本⽂件和数据流)
Kettle 是Java 做的,尽量⽤⼤⼀点的内存参数启动Kettle.
可以使⽤sql 来做的⼀些操作尽量⽤sql
Group , merge , stream lookup ,split field 这些操作都是⽐较慢的,想办法避免他们.,能⽤sql 就⽤sql
插⼊⼤量数据的时候尽量把索引删掉
尽量避免使⽤update , delete 操作,尤其是update , 如果可以把update 变成先delete ,后insert .
能使⽤truncate table 的时候,就不要使⽤delete all row 这种类似sql
合理的分区
如果删除操作是基于某⼀个分区的,就不要使⽤delete row 这种⽅式(不管是delete sql 还是delete 步骤),直接把分区drop 掉,再重新创建
尽量缩⼩输⼊的数据集的⼤⼩(增量更新也是为了这个⽬的)
尽量使⽤数据库原⽣的⽅式装载⽂本⽂件(Oracle 的sqlloader , mysql 的bulk loader 步骤)
尽量不要⽤kettle 的calculate 计算步骤,能⽤数据库本⾝的sql 就⽤sql ,不能⽤sql 就尽量想办法⽤procedure , 实在不⾏才是calculate 步骤.
要知道你的性能瓶颈在哪,可能有时候你使⽤了不恰当的⽅式,导致整个操作都变慢,观察kettle log ⽣成的⽅式来了解你的ETL操作最慢的地⽅。
远程数据库⽤⽂件+FTP 的⽅式来传数据 ,⽂件要压缩。(只要不是局域⽹都可以认为是远程连接)
8. 描述物理环境
源数据库的操作系统,硬件环境,是单数据源还是多数据源,数据库怎么分布的,做ETL的那台机器
放在哪,操作系统和硬件环境是什么,⽬标数据仓库的数据库是什么,操作系统,硬件环境,数据库的字符集怎么选,数据传输⽅式是什么,开发环境,测试环境和实际的⽣产环境有什么区别,是不是需要⼀个中间数据库(staging 数据库) ,源数据库的数据库版本号是多少,测试数据库的版本号是多少,真正的⽬标数据库的版本号是多少……. 这些信息也许很零散,但是都需要⼀份专门的⽂档来描述这些信息,⽆论是你遇到问题需要别⼈帮助的时候描述问题本⾝,还是发现测试环境跟⽬标数据库的版本号不⼀致,这份专门的⽂档都能提供⼀些基本的信息
9. procedure
为什么我不能触发procedure?
这个问题在官⽅FAQ⾥⾯也有提到,触发procedure 和 http client 都需要⼀个类似与触发器的条件,你可以使⽤generate row 步骤产⽣⼀个空的row ,然后把这条记录连上procedure 步骤,这样就会使这条没有记录的空⾏触发这个procedure (如果你打算使⽤⽆条件的单次触发) ,当然procedure 也可以象table input ⾥⾯的步骤那样传参数并且多次执⾏.
另外⼀个建议是不要使⽤复杂的procedure 来完成本该ETL任务完成的任务,⽐如创建表,填充数据,创建物化视图等等.
10. 字符集
Kettle使⽤Java 通常使⽤的UTF8 来传输字符集,所以⽆论你使⽤何种数据库,任何数据库种类的字符集,kettle 都是⽀持的,如果你遇到了字符集问题,也许下⾯这些提⽰可以帮助你:
1. 单数据库到单数据库是绝对不会出现乱码问题的,不管原数据库和⽬标数据库是何种种类,何种字符集
2. 多种不同字符集的原数据库到⼀个⽬标数据库,你⾸先需要确定多种源数据库的字符集的最⼤兼容字符集是什么,如果你不清楚,最好的办法就是使⽤UTF8来创建数据库.
3. 不要以你⼯作的环境来判断字符集:现在某⼀个测试⼈员⼿上有⼀个oracle 的基于xxx 字符集的已经存在的数据库,并且⾮常不幸的是xxx 字符集不是utf8 类型的,于是他把另⼀个基于yyy字符集的oracle 数据库要经过某⼀个ETL过程转换到oracle , 后来他发现⽆论怎么样设置都会出现乱码,这是因为你的数据库本⾝的字符集不⽀持,⽆论你怎么设置都是没⽤的. 测试的数据库不代表最后产品运⾏的数据库,尤其是有时候为了省事把多个不同的项⽬的不相关的数据库装在同⼀台机器上,测试的时候⼜没有分析清楚这种环境,所以也再次强调描述物理环境的重要性.
4. 你所看到的不⼀定代表实际储存的:mysql 处理字符集的时候是要在jdbc 连接的参数⾥⾯加上字符集参数的,⽽oracle 则是需要服务器端和客户端使⽤同⼀种字符集才能正确显⽰,所以你要明确你所看到的字符集乱码不⼀定代表真的就是字符集乱码,这需要你检查在转换之前的字符集是否会出现乱
码和转换之后是否出现乱码,你的桌⾯环境可能需要变动⼀些参数来适应这种变动
5. 不要在⼀个转换中使⽤多个字符集做为数据源.
11. 预定义时间维
Kettle提供了⼀个⼩⼯具帮助我们预填充时间维,这个⼯具在kettle_home / samples / transformations / General – populate date dimension. 这个⽰例产⽣的数据不⼀定能满⾜各种需要,不过你可以通过修改这个⽰例来满⾜⾃⼰的需求.
12. SQL tab 和 Options tab
在你创建⼀个数据库连接的时候除了可以指定你⼀次需要初始化的连接池参数之外(在Pooling 选项卡下⾯),还包括⼀个Options 选项卡和⼀个 SQL 选项卡, Options 选项卡⾥⾯主要设置⼀些连接时的参数,⽐如autocommit 是on 还是off , defaultFetchSize ,useCursorFetch (mysql 默认⽀持的),oracle 还⽀持⽐如defaultExecuteBatch , oracle.jdbc.StreamBufferSize,
oracle.jdbc.FreeMemoryOnEnterImplicitCache ,你可以查阅对应数据库所⽀持的连接参数,另外⼀个⼩提⽰:在创建数据库连接的时候,选择你的数据库类型,然后选到Options 选项卡,下⾯有⼀个Show help text on options usage , 点击这个按钮会把你带到对应各个数据库的连接参数的官⽅的⼀
个参数列表页⾯,通过查询这个列表页⾯你就可以知道那种数据库可以使⽤何种参数了.
对于SQL 选项卡就是在你⼀连接这个Connection 之后,Kettle 会⽴刻执⾏的sql 语句,个⼈⽐较推荐的⼀个sql 是执⾏把所有⽇期格式统⼀成同⼀格式的sql ,⽐如在oracle ⾥⾯就是:
alter session set nls_date_format = xxxxxxxxxxxxx
alter session set nls_xxxxxxxxx = xxxxxxxxxxxx
这样可以避免你在转换的时候⼤量使⽤to_date() , to_char 函数⽽仅仅只是为了统⼀⽇期格式,对于增量更新的时候尤其适⽤.
13. 数据复制
有的时候可能我们需要的是类似数据复制或者⼀个备份数据库,这个时候你需要的是⼀种数据库私有的解决⽅案,Kettle 也许并不是你的第⼀选择,⽐如对于Oracle 来说,可能rman , oracle stream , oracle replication 等等, mysql 也有mysql rmaster / slave 模式的replication 等私有的解决⽅法,如果你确定你的需求不是数据集成这⽅⾯的,那么也许kettle 并不是⼀个很好的⾸选⽅案,你应该咨询⼀下专业的DBA⼈⼠也会会更好.
14. 如何控制版本变更
Kettle 的每⼀个transformation 和job 都有⼀个version 字段(在你保存的时候), 不过这个功能还不实⽤,如果你需要版本控制的话,还是建议你将transformation 和job 转换成⽂本⽂件保存,然后⽤svn 或cvs 或任意你熟悉的版本控制系统将其保存,kettle 将在下⼀个版本加⼊版本控制的功能(做的更易⽤).
15. ⽀持的数据源
Kettle ⽀持相当⼴的数据源,⽐如在数据库⾥⾯的⼀些不太常见的Access , MaxDB (SAP DB) , Hypersonic , SAP R/3 system , Borland Interbase , Oracle RDB , Teradata和3.0新加⼊的Sybase IQ .
另外还包括Excel , CSV , LDAP ,以及OLAP Server Mondrian , ⽬前⽀持Web Service 不过暂时还不⽀持SOAP.
16. 调试和测试
当ETL转换出现不可预知的问题时,或是你不清楚某个步骤的功能是什么的情况下,你可能需要创建⼀个模拟环境来调适程序,下⾯⼀些建议可能会有所帮助:
尽量使⽤generate row 步骤或者固定的⼀个⽂本⽂件来创建⼀个模拟的数据源
模拟的数据源⼀定要有代表性,数据集⼀定尽量⼩(为了性能考虑)但是数据本⾝要⾜够分散.
创建了模拟的数据集后你应该清楚的知道你所要转换之后的数据时什么样的.
17. 错误处理
在ETL任务中由于数据问题出现转换错误是⼀件⾮常正常的事情,你不应该设计⼀个依赖于临时表或者拥有事务特点的ETL过程,⾯对数据源质量问题的巨⼤挑战,错误处理是并不可少的,kettle同样提供⾮常⽅便的错误处理⽅式,在你可能会出错的步骤点击右键选择Define Error handing , 它会要求你指定⼀个处理error 的步骤,你可以使⽤⽂本⽂件或者数据库的表来储存这些错误信息,这些错误信息会包含⼀个id 和⼀个出错的字段,当你得到这些错误信息之后就需要你⾃⼰分析出错的原因了,⽐如违反主键约束可能是你⽣成主键的⽅式有错误或者本⾝的数据有重复,⽽违反外键约束则可能是你依赖的⼀些表⾥⾯的数据还没有转换或者外键表本⾝过滤掉了这些数据. 当你调整了这些错误之后,确定所有依赖的数据都被正确的处理了.kettle user guide ⾥⾯有更详细的解释,⾥⾯还附带了⼀个使⽤javascript 来处理错误的⽰例,这种⽅式可以作为处理简单数据质量的⽅式.
18. ⽂档
Kettle 提供了丰富的⽂档和使⽤⼿册,⼩到⼀个数据库连接怎么连,⼤到⼀个功能怎么实现,所有的
参数列表,对话框的每⼀个输⼊输出代表什么意思都有解释,所以当你遇到问题你应该第⼀时间翻阅这些⽂档,也许上⾯已经告诉你怎么做了. 另外kettle 还有⼀个⾮常活跃的社区,你可以到上⾯提问,但是记住在你提问之前先搜索⼀下论坛看有没有类似的问题已经问过了,如果没有记得描述清楚你的问题
总结
本系列⽂章主要讨论了如何使⽤kettle 来处理数据仓库中的缓慢增长维,动态ETL如何设计,增量更新的⼀些设计技巧,在应⽤程序中如何集成kettle 以及在使⽤kettle 时的⼀些常见问题. 如果你正在寻⼀个⼯具来帮助你解决数据库的集成问题或是你打算建⽴⼀个商业智能项⽬的数据仓库,那么kettle是⼀个不错的选择,你不⽤⽀付任何费⽤就可以得到很多很多数据集成的特性,⼤量⽂档和社区⽀持. 难道这些不就是你希望从⼀个商业⼯具上的到的吗?还在等什么 ,开始你的数据集成之旅吧。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论