Oracle优化——星型联结转换(star_transformation_enabled)

本文深入探讨了Oracle数据库中的星型联结转换技术,旨在提升SQL查询性能。结合位图联结索引的最佳实践,帮助读者掌握数据库性能调优的关键策略。

参见 Oracle性能优化求生指南。

另外请了解位图联结索引,此类问题的最佳实践。

这是一个星型联结的例子,sales为事实表,其它为维度表。Where条件全部都作用在维度表上面。
SH@ prod> select quantity_sold , amount_sold from sales s join products p using ( prod_id )
  2  join times using ( time_id ) join customers c using ( cust_id )
  3  where week_ending_day = '29-Nov-2008' 
  4  and prod_name = '1.44MB External 3.5'' Diskette' 
  5  and cust_year_of_birth = 1965 ;

no rows selected


Execution Plan
----------------------------------------------------------
Plan hash value: 3891315047

--------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                             | Name             | Rows  | Bytes | Cost (%CPU)| Time     | Pstart| Pstop |
--------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                      |                  |     1 |    80 |    30   (0)| 00:00:01 |       |       |
|   1 |  NESTED LOOPS                         |                  |       |       |            |          |       |       |
|   2 |   NESTED LOOPS                        |                  |     1 |    80 |    30   (0)| 00:00:01 |       |       |
|   3 |    NESTED LOOPS                       |                  |     4 |   284 |    26   (0)| 00:00:01 |       |       |
|   4 |     MERGE JOIN CARTESIAN              |                  |     1 |    46 |    21   (0)| 00:00:01 |       |       |
|*  5 |      TABLE ACCESS FULL                | TIMES            |     1 |    16 |    18   (0)| 00:00:01 |       |       |
|   6 |      BUFFER SORT                      |                  |     1 |    30 |     3   (0)| 00:00:01 |       |       |
|*  7 |       TABLE ACCESS FULL               | PRODUCTS         |     1 |    30 |     3   (0)| 00:00:01 |       |       |
|   8 |     TABLE ACCESS BY GLOBAL INDEX ROWID| SALES            |     9 |   225 |     5   (0)| 00:00:01 | ROWID | ROWID |
|*  9 |      INDEX RANGE SCAN                 | SALES_CONCAT_IDX |     9 |       |     2   (0)| 00:00:01 |       |       |
|* 10 |    INDEX UNIQUE SCAN                  | CUSTOMERS_PK     |     1 |       |     0   (0)| 00:00:01 |       |       |
|* 11 |   TABLE ACCESS BY INDEX ROWID         | CUSTOMERS        |     1 |     9 |     1   (0)| 00:00:01 |       |       |
--------------------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   5 - filter("TIMES"."WEEK_ENDING_DAY"=TO_DATE(' 2008-11-29 00:00:00', 'syyyy-mm-dd hh24:mi:ss'))
   7 - filter("P"."PROD_NAME"='1.44MB External 3.5'' Diskette')
   9 - access("S"."PROD_ID"="P"."PROD_ID" AND "S"."TIME_ID"="TIMES"."TIME_ID")
  10 - access("S"."CUST_ID"="C"."CUST_ID")
  11 - filter("C"."CUST_YEAR_OF_BIRTH"=1965)


Statistics
-----------------------------------------------------
<think>我们正在讨论Kettle中的子转换(sub-transformation)实现。用户要求提供sub_transformation.ktr的具体案例或使用方法。根据之前的对话历史,我们已经介绍了子转换的基本概念、实现方式和示例代码。现在用户希望看到更具体的案例。引用[1]提到了在Linux中通过命令行执行Kettle作业和转换的方法,这对于我们展示如何调用子转换可能有帮助。引用[2]展示了一个简单的转换Transformation)的SQL插入示例,我们可以将其作为子转换的内容。引用[3]和[引用4]则提供了命令行参数的一些细节,特别是如何避免连接资源库(repository)而执行本地文件。子转换通常被主转换通过“TransformationExecutor”步骤调用。下面我们将构建一个具体案例:案例描述:假设我们有一个主转换(main_trans.ktr),它需要调用一个子转换(sub_transformation.ktr)来处理数据。子转换负责将传入的数据插入到数据库表中。步骤:1.创建子转换(sub_transformation.ktr):在子转换中,我们定义:-输入:从主转换传递过来的字段(例如:account_name,customer_id)-处理:使用“表输出”步骤将数据插入到数据库的account表中。子转换的步骤可能包括:a.获取输入(通过“TransformationExecutor”步骤传递过来的字段)b.表输出:执行SQL插入(如引用[2]所示)2.主转换(main_trans.ktr):主转换中,我们可能有数据生成步骤(例如:生成一些测试数据),然后调用子转换。主转换的步骤:a.生成数据:使用“生成记录”步骤创建一些记录(比如account_name和customer_id)。b.调用子转换:使用“TransformationExecutor”步骤,指定子转换的路径(如sub_transformation.ktr),并映射字段。3.命令行执行:我们可以使用Pan来执行主转换(因为主转换是一个ktr文件)。命令如引用[1]和[3]所示:/home/kettle/data-integration/pan.sh-file=/path/to/main_trans.ktr-norep-logfile=main_log.log注意:如果子转换和主转换在同一目录下,可以直接指定子转换的文件名。否则,需要正确指定路径。具体示例代码(伪代码形式,因为Kettle转换以XML存储,但我们可以描述步骤):子转换(sub_transformation.ktr)结构:-输入步骤(通常是一个虚拟的步骤,用于接收来自主转换的数据)-表输出步骤:配置数据库连接,目标表为account,字段映射(account_name,customer_id)主转换(main_trans.ktr)结构:-生成记录步骤:生成5行记录,每行有两个字段:account_name(值分别为account1,account2,...)和customer_id(固定为1)。-TransformationExecutor步骤:转换:选择sub_transformation.ktr输入字段映射:将生成记录步骤的account_name和customer_id字段映射到子转换的同名字段。注意:在实际操作中,我们可以在Kettle的Spoon图形界面中设计这些转换。由于用户要求具体案例,我们将重点放在主转换如何调用子转换以及子转换如何实现上。下面我们给出一个更具体的示例,包括如何设置参数:假设子转换需要接收两个参数:ACCOUNT_NAME和CUSTOMER_ID(注意:在子转换中,我们可以使用参数而不是直接使用字段)。但通常,我们直接传递字段值。另一种常见做法:子转换从主转换接收一个数据流(即多行数据),然后在子转换中对每一行进行处理。因此,我们采用数据流传递的方式:主转换:步骤1:生成记录(生成5行数据,字段为account_name和customer_id)步骤2:TransformationExecutor转换文件名:sub_transformation.ktr将主转换中的字段account_name和customer_id传递给子转换的同名字段(注意:子转换中必须存在同名字段的输入)子转换:步骤1:获取数据(实际上,在子转换中,数据是由主转换流入的,所以子转换的第一个步骤可以是任何步骤,但通常我们会用一个“获取行”的步骤,但在Kettle中,当作为子转换被调用时,数据会直接流入子转换的第一个步骤)步骤2:表输出(配置好数据库连接,表名account,字段映射)注意:在子转换中,我们不需要特别的输入步骤,因为当主转换TransformationExecutor步骤调用子转换时,它会将数据流直接传递给子转换的第一个步骤。但是,为了清晰,我们可以在子转换中使用一个“Dummy”(哑步骤)作为起点,然后连接到表输出。关于参数传递:如果我们需要在子转换中使用参数(而不是数据流中的字段),则可以在主转换TransformationExecutor步骤中设置“参数”选项卡。例如,我们可以设置一个参数PARAM_CUSTOMER_ID,然后在子转换中使用${PARAM_CUSTOMER_ID}来引用。但本例中,我们传递的是数据流中的字段,所以不需要参数。因此,我们重点展示传递数据流的方式。由于无法直接展示Kettle的XML文件(.ktr文件),我们将用文字描述和伪代码。示例执行:执行主转换,它会生成5条记录,然后通过子转换插入到数据库。性能提示:如果数据量很大,可以在表输出步骤中调整提交记录数量(如每10000条提交一次)。相关问题:1.如何传递参数给子转换?2.子转换能否返回数据给主转换?3.如何处理子转换中的错误?现在,我们按照用户要求,提供sub_transformation.ktr的具体使用案例。</think>### 子转换(sub_transformation.ktr)具体实现案例 以下是一个完整的子转换使用案例,展示如何在 Kettle 中创建和调用 `sub_transformation.ktr` 文件: #### 案例场景 假设需要实现银行账户数据清洗: - **主转换**:从 CSV 文件读取原始账户数据 - **子转换**:负责数据清洗和验证逻辑(如去除空格、验证账户格式) - **最终输出**:清洗后的数据插入数据库 --- ### 1. 子转换实现 (`sub_transformation.ktr`) ```xml <!-- 子转换:数据清洗逻辑 --> <transformation> <step> <name>Trim Fields</name> <type>StringOperations</type> <fields> <field> <name>account_name</name> <trim_type>both</trim_type> <!-- 去除首尾空格 --> </field> </fields> </step> <step> <name>Validate Account</name> <type>UserDefinedJavaClass</type> <code><![CDATA[ if (account_name.length() < 5) { row.setError("账户名长度不足"); row.setReject(true); } ]]></code> </step> <step> <name>Output</name> <type>Dummy</type> <!-- 作为子转换输出点 --> </step> <hops> <!-- 步骤连接关系 --> <hop from="Trim Fields" to="Validate Account"/> <hop from="Validate Account" to="Output"/> </hops> </transformation> ``` **功能说明**: 1. `StringOperations`:去除账户名字段首尾空格 2. `UserDefinedJavaClass`:自定义验证逻辑(账户名长度需≥5字符) 3. 错误数据会被标记为 `reject`[^2] --- ### 2. 主转换调用子转换 ```xml <!-- 主转换:main_transformation.ktr --> <transformation> <!-- 1. 读取CSV文件 --> <step> <name>CSV Input</name> <type>CSVFileInput</type> <file>/data/raw_accounts.csv</file> <fields> <field><name>account_name</name></field> <field><name>customer_id</name></field> </fields> </step> <!-- 2. 调用子转换 --> <step> <name>Execute Sub-Trans</name> <type>TransformationExecutor</type> <transformation_path>/transformations/sub_transformation.ktr</transformation_path> <params> <param><name>input_account</name><field>account_name</field></param> </params> </step> <!-- 3. 处理子转换结果 --> <step> <name>Filter Rejects</name> <type>FilterRows</type> <condition>!IS_REJECT</condition> <!-- 过滤掉被拒绝的行 --> </step> <!-- 4. 写入数据库 --> <step> <name>DB Output</name> <type>TableOutput</type> <connection>MySQL_Prod</connection> <table>account</table> <fields> <field><name>account_name</name></field> <field><name>customer_id</name></field> </fields> </step> <hops> <hop from="CSV Input" to="Execute Sub-Trans"/> <hop from="Execute Sub-Trans" to="Filter Rejects"/> <hop from="Filter Rejects" to="DB Output"/> </hops> </transformation> ``` **关键配置**: - `TransformationExecutor`:指定子转换路径 `/transformations/sub_transformation.ktr` - 参数映射:将主转换的 `account_name` 字段映射到子转换的 `input_account` 参数 - 错误处理:通过 `IS_REJECT` 标志过滤无效数据[^2] --- ### 3. 命令行执行 ```bash # 执行主转换(使用Pan命令行工具) /home/kettle/data-integration/pan.sh \ -file=/transformations/main_transformation.ktr \ -norep \ # 不使用资源库 -param:input_file="/data/raw_accounts.csv" \ -logfile=/logs/account_etl.log ``` **参数说明**: - `-norep`:直接执行本地 KTR 文件(非资源库模式)[^4] - `-param`:动态传递输入文件路径 - `-logfile`:指定日志输出位置[^1][^3] --- ### 4. 执行流程说明 1. **主转换启动**:读取 CSV 文件(约10,000行) 2. **调用子转换**:每行数据传递给子转换进行清洗 - 有效数据:返回清洗后的账户名 - 无效数据:标记 `IS_REJECT=true` 3. **结果处理**:过滤拒绝数据,有效数据插入数据库 4. **性能统计**(示例日志): ``` 2023-08-15 14:30:22 - Sub-transformation executed: 9,876 rows processed 2023-08-15 14:30:25 - DB Output: 9,540 rows inserted (336 rejects filtered) ``` --- ### 子转换最佳实践 1. **参数化设计**: ```xml <!-- 子转换接收动态参数 --> <params> <param><name>min_length</name><default>5</default></param> </params> ``` 在主调用中覆盖:`<param><name>min_length</name><value>8</value></param>` 2. **错误处理增强**: ```java // 在子转换中添加错误日志 row.logError("Invalid account: " + account_name); ``` 3. **性能优化**: ```xml <!-- 调整批次大小 --> <step> <name>DB Output</name> <commit_size>5000</commit_size> </step> ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值