Professional Documents
Culture Documents
编写日期: 2010 年 5 月 1 日
Teradata 学习推荐资料:
TF v800 Read Book1.pdf
Teradata SQL.pdf
perl 编程 24 学时教程
。。。。。
内部资料,注意保密
Agenda
Teradata Client 安装
Teradata 架构
PI 、 SI 、 PPI 机制
数据重分布及 JOIN 机制
SQL 函数及开发经验
内部资料,注意保密
Teradata Client 安装
Teradata Client 安装
点击安装目录下 ,点击橙色高亮处操作。
内部资料,注意保密
Teradata Client 安装
Teradata Client 安装
点击安装目录下 ,点击橙色高亮处操作。
内部资料,注意保密
Teradata Client 安装
Teradata Client 安装
点击安装目录下 ,点击橙色高亮处操作。
内部资料,注意保密
Teradata Client 安装
Teradata Client 安装
点击安装目录下 ,点击橙色高亮处操作。
内部资料,注意保密
Teradata Client 安装
Teradata Client 安装
点击安装目录下 ,点击橙色高亮处操作。
内部资料,注意保密
Teradata Client 安装
Teradata Client 安装
点击安装目录下 ,点击橙色高亮处操作。
内部资料,注意保密
Teradata Client 安装
Teradata Client 安装
点击安装目录下 ,点击橙色高亮处操作。
内部资料,注意保密
Teradata Client 安装
选择安装的程序:(一般开发人员只安装这些就够了)
如果是为了学习 Terada, 进入安装组件选取时 , 一定不能选取有关 websphere 的相关选项。
点击 NEXT 直至完成安装。
内部资料,注意保密
Teradata Client 安装
配置 CLI
打开系统目录- system32 - Drivers - etc
(如 2003 系统: C:\WINNT\system32\drivers\etc )下的 hosts 文件
填写 Teradata 数据库的 CLI 接口地址:如
127.0.0.1 localtdcop1 dbccop1
10.1.18.79 cebuatcop1
10.1.18.80 cebuatcop2
10.1.18.81 cebuatcop3
10.1.18.82 cebuatcop4
说明:
第一部分为 Teradata 的 ip 地址,后面为任意名字和 cop1 、 cop2 的组合。
内部资料,注意保密
Teradata Client 安装
配置 ODBC
填
打开
选择DBTeradata
odbc
Source
数据源管理器、选择系统
、
驱动程序,点击【
Teradata Info 、Finish
Default
dsn 】按钮
页点击【添加】按钮
DataBase 、 Uername 、 Password 等选项点击【 ok 】按钮
完成。
内部资料,注意保密
Agenda
Teradata Client 安装
Teradata 架构
PI 、 SI 、 PPI 机制
数据重分布及 JOIN 机制
SQL 函数及开发经验
内部资料,注意保密
Teradata 体系架构 Physical View
内部资料,注意保密
Teradata RDBMS Architecture
PE PE PE PE PE PE PE PE
• Parsing Engine (PE)
• Access Module AMP AMP AMP AMP AMP AMP AMP AMP
Processor (AMP)
AMP AMP AMP AMP AMP AMP AMP AMP
内部资料,注意保密
Teradata Functional Overview
Channel-Attached Network-Attached
System System
Client Client
Applicatio Applicatio
n n
内部资料,注意保密
Channel-Attached Client Software Overview
内部资料,注意保密
Network-Attached Client Software Overview
内部资料,注意保密
The Parsing Engine
管理单独的会话层(可以到 120 个)
分析和优化 SQL 请求
将优化的计划发送给 AMP
ASCII/EBCDIC 之间的转化(如果需
要的话)
发送响应的结果给请求客户
内部资料,注意保密
Message Passing Layer
Notes:
AMP 与 PE 之间的信息传送
广播,点对点和多点通讯
合并结果集返回给 PE
让 Teradata 的并行处理成为可能
消息传递层是一个组合:
BYNET 软件
内部资料,注意保密
The Access Module Processor
Notes:
查找请求行
锁的管理
行排序
列聚合
Join 处理
输出转化和格式化
为客户端建立结果集
磁盘空间管理
统计
专用的协议
恢复处理
内部资料,注意保密
Disk Arrays
内部资料,注意保密
BYNET (for MPP)
内部资料,注意保密
AWS(adminstration Workstation)
内部资料,注意保密
Teradata Parallelism
Notes:
每个 PE 可以并行处理 120 个会话
每个会话可以操纵多条请求
MPL 可以并行处理所有的信息
每个 AMP 可以并行地执行多条请求
内部资料,注意保密
Linear Growth and Expandability
Notes:
Teradata 是一个线性扩展的
RDBMS 。
系统构成在需求增长时可以线性
扩展。
线性的可扩展性允许在不减少传
输量的情况下增加工作量
内部资料,注意保密
Teradata Storage Process
Notes:
PE 发出插入一行的请求
AMP 将行存储在相关的磁盘中
每个 AMP 管理一个逻辑或虚拟磁
盘映射到磁盘阵列多个物理磁盘
内部资料,注意保密
Teradata Retrieval Process
Notes:
PE 发送一个请求读取一行或多行
AMP 以并行访问方式查找并读取所需要的
数据行
MPL 将读取的数据行返回给 PE
PE 将结果数据返回到请求的客户端应用程
序
内部资料,注意保密
Multiple Tables on Multiple AMPs
Notes:
每个表中的某些行可以在每个
AMP 中找到
每个 AMP 可以有所有表中的行
在理想情况下,每个 AMP 将保
存大致相同数量的数据
内部资料,注意保密
Single-Node SMP
Notes:
一个节点一个或多个共享存储器的处理器组
成
AMP 通过磁盘矩阵控制器与虚拟磁盘相关联
内部资料,注意保密
Multi-Node MPP System
Notes:
多个节点可以构造成一个海量并行处理
系统( MPP )。
用来连接多个节点的物理信息传送层叫
BYNET 。
Teradata 系统是可以线性扩展的,当数
据库增大时,你可以增加节点。
内部资料,注意保密
Teradata Cliques
Clique 是一个具有失效保护能力的结点的集合
内部资料,注意保密
Fallback Clusters
FALLBACK 保护集群定义为独立的 AMP 容错单元
集群中的 FALLBACK 行必须在同一个集群中
集群中一个 AMP 失效仍然可以访问表中的数据
在同一集群中同时有两个 AMP 失效,数据库系统停掉
Primary
rows 62 8 27 34 22 50 5 78 19 14 1 38
Fallback 5 34 14 19 38 8 22 62 1 50 27 78
rows
Primary
rows 41 66 7 58 93 20 88 2 45 17 37 72
Fallback
rows 93 72 88 45 7 17 37 58 41 20 2 66
内部资料,注意保密
Fallback Clusters
Cluster 0 AMP 1 AMP 2 AMP 3 Cluster 2 AMP 4
Primary
rows 62 8 27 34 22 50 5 78 19 14 1 38
Fallback 34 22 50 62 8 27 14 1 38 5 78 19
rows
Cluster 3
Cluster 1 AMP 5 AMP 6 AMP 7 AMP 8
Primary
rows 41 66 7 58 93 20 88 2 45 17 37 72
Fallback 58 93 20 41 66 7 17 37 72 88 2 45
rows
Cluster 0 Cluster 1
内部资料,注意保密
Agenda
Teradata Client 安装
Teradata 架构
PI 、 SI 、 PPI 机制
数据重分布及 JOIN 机制
SQL 函数及开发经验
内部资料,注意保密
TeradataSQL Assistant
TeradataSQL Assistant
内部资料,注意保密
TeradataSQL Assistant
输入 SQL
数据 结果
库,
表结 SQL 历史
构
内部资料,注意保密
TeradataSQL Assistant
实行 SQL
实行并行
SQL
连接数据库
内部资料,注意保密
TeradataSQL Assistant
加数据库
内部资料,注意保密
TeradataSQL Assistant
数据浏览
显示建表 DDL
内部资料,注意保密
TeradataSQL Assistant
将 SQL 结果输出文
档
文档数据插入数据库
内部资料,注意保密
TeradataSQL Assistant
定义输
出 / 插入
的文档字
段间隔符
内部资料,注意保密
TeradataSQL Assistant
如果有 highlight ,
只提交 highlight 的
SQL
内部资料,注意保密
TeradataSQL Assistant
数字加千位逗
号
显示字段标题
还是名字
内部资料,注意保密
TeradataSQL Assistant
内部资料,注意保密
Teradata Administrator
创建、调整、删除、复制用户与数据库,权限的设置,数据库中具体对象的操
作等等,甚至还能通过它来递交 SQL 交易请求都可以通过它完成
内部资料,注意保密
Teradata Administrator
新建库、用户、表、
角色等 赋权功能选项
修改库、用户、
表、角色等
从某个空间
移走空间给
可执行查询申 另外个空间
请
数据库树形结
构对象列表 记录返回显示
区
内部资料,注意保密
Teradata Administrator
显示宏和存
储过程 返回表、视图、
宏、存储过程、
触发器等对象
相关信息列表
显示所有对象
显示表和索引
列表
显示该库
或用户下视图
该库和用户下对象
相关的权限管理
记录返回显示
显示该库 / 表下的子 区
库、表的空间情况
内部资料,注意保密
Teradata Administrator
显示该对象(表、
视图)的列信息
浏览数据 显示表的统计信息
表的 返回表或视图
的记录条数
总空间
对象 表空间在各
的权 AMP 分布情况
限
显示该对象(表、
视图、宏、函数等)
的定义语句
记录返回显
示区
内部资料,注意保密
Agenda
Teradata Client 安装
Teradata 架构
PI 、 SI 、 PPI 机制
数据重分布及 JOIN 机制
SQL 函数及开发经验
内部资料,注意保密
数据库环境
内部资料,注意保密
ETL AUTOMATION 服务器端目录架构图
/APP
录下才是各所属作业所对应的目录。
/APP/$SYS/$JOB/bin
/bin
自定义的函数包。
/etc
内部资料,注意保密
Perl 应用模板
脚本头注明
脚本内容、
开发人员、修改等
参数、变量
定义函数方法:
通过管道将要执行
的语句注入
主函数
内部资料,注意保密
Agenda
Teradata Client 安装
Teradata 架构
PI 、 SI 、 PPI 机制
数据重分布及 JOIN 机制
SQL 函数及开发经验
内部资料,注意保密
Perl 脚本开发、测试、 ETL 上线
Perl 脚本开发
推荐学习资料 perl 编程 24 学时教程
参数、变量定义
my $HOME; # 定义参数、变量名;
$HOME = " D:\\ETL "; # 参数、变量赋值;
my $HOME = "D:\\ETL";
my $CTAPDB = $ENV{"AUTO_CTAPDB"}; # 前端 CTAP 应用数据库
if ( !defined($CTAPDB) ) {
$CTAPDB= "TCTAP";
}
${table_name} 或 $table_name
数组
my @tabrow;
内部资料,注意保密
Perl 脚本开发、测试、 ETL 上线
注释 :
单行注释: #
多行注释: =pod … … =cut;
注意:如果是管道的内容注释,请遵循执行管道的程序语言。
内部资料,注意保密
Perl 脚本开发、测试、 ETL 上线
创建和调用子例程
sub subroutine_name {
statement1;
.
.
statmentx;
}
& subroutine_name ( )
或
subroutine_name ( );
内部资料,注意保密
Perl 脚本开发、测试、 ETL 上线
管道
open(STDERR, ">&STDOUT");
}
my $BTEQ_CMD_I5 =<<ENDOFINPUT;
.logon 127.0.0.1/etl,etl;
.IF ERRORCODE <> 0 THEN .QUIT 12; perlÄ£°å.txt
Perl 脚本测试
内部资料,注意保密
Perl 脚本开发、测试、 ETL 上线
ETL 上线
测试完成并提交相关测试报告文档后,根据项目
组的要求填写上线文档,完成上线
维护性上线: 要求记录修改的上线历史
批量上线:如果批量大,不一定保存该次上线历史
内部资料,注意保密
Perl 脚本开发、测试、 ETL 上线
新上线作业:
TST 系统 作业名 TST_JOB_E ETL 服务器: AUTO1
脚本 tst_job_e0200.pl
Mkdir D:\ETL\APP\TST\TST_JOB_E;
Mkdir D:\ETL\APP\TST\TST_JOB_E\bin;
配置 JOB 、作业源、作业依赖、作业触发
内部资料,注意保密
Perl 脚本开发、测试、 ETL 上线
Automation 操作演示 XXX_job_define
登录 automation
内部资料,注意保密
Perl 脚本开发、测试、 ETL 上线
Automation 操作演示 XXX_job_define
配置 JOB
内部资料,注意保密
Perl 脚本开发、测试、 ETL 上线
Automation 操作演示 XXX_job_define
配置 JOB Source
内部资料,注意保密
Perl 脚本开发、测试、 ETL 上线
Automation 操作演示 XXX_job_define
配置 JOB Dependency
内部资料,注意保密
Perl 脚本开发、测试、 ETL 上线
Automation 操作演示 XXX_job_define
配置 JOB stream
内部资料,注意保密
系统 ETL 上线 作业定义
内部资料,注意保密
系统 ETL 上线 作业依赖
内部资料,注意保密
系统 ETL 上线 作业触发
内部资料,注意保密
Perl 脚本开发、测试、 ETL 上线
作业调度和作业日志
重置作业状态
内部资料,注意保密
Perl 脚本开发、测试、 ETL 上线
作业调度和作业日志
强制重跑 ( 作业依
赖条件满足情
况下运行)
内部资料,注意保密
Perl 脚本开发、测试、 ETL 上线
作业调度和作业日志
立刻强制重跑 ( 不
判断作业依赖
条件)
内部资料,注意保密
Perl 脚本开发、测试、 ETL 上线
作业调度和作业日志
查看日志
内部资料,注意保密
Perl 脚本开发、测试、 ETL 上线
作业日志
点击 view log File 可以看明细日志, view Script File 可以看脚本,这里可以对脚本更改,
但严禁使用
内部资料,注意保密
Perl 脚本开发、测试、 ETL 上线
问题?
TST_JOB_A 数据重加载时,只要求重加载本身而不触发
下游作业,各种 ETL 工具都有什么办法?
Teradata 架构
PI 、 SI 、 PPI 机制
数据重分布及 JOIN 机制
SQL 函数及开发经验
内部资料,注意保密
思考一:
某系统的应用指标体系公式本是由基础指标按公式统计得
到,但其中有部分基础指标是外部手工录入,并且录入时间存在不确
定性。如何方便、准确、快速得到应用指标?
思考二:
某电信系统要做一个客户分析视图,分析客户的对电信产品
的消费行为,并对电信产品进行修改提供参考分析。要求分析的指标
:通话时长(国内、国际、港澳 台)、长途、本地、短信、彩
信、 3G 流量、手机报、手机支付、 12580 ( 114 )查询。。。。等
等,视图如何去组织?
内部资料,注意保密
参数变量声明
Procedure In 输入
Out 输出
REPLACE PROCEDURE DWMART_XXX.PROC_TEST(IN report_date DATE, OUT returnflag INTEGER)
BEGIN
INOUT 输入输出
DECLARE EXIT HANDLER FOR SQLEXCEPTION
参数变量声明
BEGIN
SET returnflag = 0;
END;
CREATE MUTLISET TABLE TEMP_XX as
.....
..
;
INSERT INTO TEMP_XX
...
;
DELETE FROM TB_XXX WHERE STATISTICS_DT=CAST(:report_date AS DATE FORMAT 'YYYYMMDD')
调存储过程
;
CALL
INSERT INTO TB_XXX
DWMART_XXX.PROC_TE
SELECT ST
STATISTICS_DT ( '20100501',returnflag )
,..
,..
FROM TEMP_XX
GROUP BY 1,2,...
; 变量赋值
SET returnflag = 1
; END;
内部资料,注意保密
Macro
CREATE MACRO new_dept
(dept INTEGER
,budget DEC(10,2) DEFAULT 0
,name CHAR(30)
,mgr INTEGER)
AS
( INSERT INTO department
(department_number
,department_name
,budget_amount
,manager_employee_number)
VALUES( :dept
,:name 运行宏 new_dept
,:budget
EXEC new_dept (505
,:mgr);
SELECT department_number (TITLE 'number')
,610000.00, 'Marketing Research',
1007);
,department_name (TITLE 'name')
,budget_amouunt (TITLE 'budget')
,manager_employee_number (TITLE 'manager')
FROM department
WHERE department_number = :dept;
);
内部资料,注意保密
View
REPLACE VIEW XXXX.VIE_SYS_XXX REPLACE VIEW XXXX.VIE_SYS_XXX
AS AS
LOCKING TABLE TB_XXX_A FOR ACCESS
LOCKING TABLE PDATA.TB_XXX_B FOR ACCESS
LOCKING TABLE PDATA.TB_XXX_C FOR ACCESS
SELECT SELECT
T1.COLUMN1 T1.COLUMN1
,.... ,....
,T2.COLUMN1 ,T2.COLUMN1
,... ,...
,T3.COLUMN1 ,T3.COLUMN1
,.... ,....
FROM PDATA.TB_XXX_A T1 FROM PDATA.TB_XXX_A T1
INNER JOIN PDATA.TB_XXX_B T2 INNER JOIN PDATA.TB_XXX_B T2
ON T1.COLUMNXX = T2.COLUMNXX ON T1.COLUMNXX = T2.COLUMNXX
AND T1.COLUMNXY = T2.COLUMNXY AND T1.COLUMNXY = T2.COLUMNXY
INNER JOIN PDATA.TB_XXX_C T3 INNER JOIN PDATA.TB_XXX_C T3
ON T1.COLUMNX = T3.COLUMNX ON T1.COLUMNX = T3.COLUMNX
WHERE T1.COLUMN1='XXXXX' WHERE T1.COLUMN1='XXXXX'
; ;
内部资料,注意保密
Table
Set MultiSet
不允许记录重复 允许记录重复
CREATE SET TABLE CREATE MULTISET TABLE
pmart.RPT_NM_GRP_PRE_WARN_MON,( pmart.RPT_NM_GRP_PRE_WARN_MON,(
CAL_Month INTEGER TITLE ' 统计月份 ' CAL_Month INTEGER TITLE ' 统计月份 '
,ORG_NUM CHAR(12) TITLE ' 集团编号 ' ,ORG_NUM CHAR(12) TITLE ' 集团编号 '
,City_ID CHAR(3) TITLE ' 地市标识 ' ,City_ID CHAR(3) TITLE ' 地市标识 '
,ORG_SUBS_GRP_NUM CHAR(10) TITLE ' 集团用户 ,ORG_SUBS_GRP_NUM CHAR(10) TITLE ' 集团用户
群编号 ' 群编号 '
,ORG_Title VARCHAR(200) TITLE ' 集团名称 ' ,ORG_Title VARCHAR(200) TITLE ' 集团名称 '
,ORG_Level CHAR(2) TITLE ' 集团级别 ' ,ORG_Level CHAR(2) TITLE ' 集团级别 '
,STAT_Item_Code CHAR(2) TITLE ' 统计项 ' ,STAT_Item_Code CHAR(2) TITLE ' 统计项 '
,STAT_Value DECIMAL(18,2) TITLE ' 统计值 ' ,STAT_Value DECIMAL(18,2) TITLE ' 统计值 '
) PRIMARY INDEX (ORG_NUM); ) UNIQUE PRIMARY INDEX (ORG_NUM);
内部资料,注意保密
永久表 设计原则:
1 、调整 PI ,在保留一定数据分布均匀度的基础
CREATE MULTISET TABLE tctap.tap_c_kpi_assess_2 ,NO FALLBACK , 上,把 PI 字段从 N 个减少为 3 个,提高数据查
NO BEFORE JOURNAL, 询速度。
NO AFTER JOURNAL,
2 、增加 PPI ,提高数据插入性能与查询性能。
CHECKSUM = DEFAULT
(
3 、增加 USI ,而不是把 Multiset 改为 Set ;虽
KPI_ID CHAR(8) CHARACTER SET LATIN CASESPECIFIC TITLE 'KPI 标识 ' NOT NULL 然这两种方式都能保证数据记录的唯一性,但是
,FREQ_ID CHAR(2)) CHARACTER SET LATIN CASESPECIFIC TITLE ' 频度代码 ' NOT NULL 前者效率会更高。
,DATA_DATE INTEGER TITLE ' 指标日期 ' NOT NULL
4 、增加统计信息,有助于系统优化 SQL 查询。
,DIM_VALUE_ID1 CHAR(8) CHARACTER SET LATIN CASESPECIFIC TITLE ' 维度 1' NOT NULL DEFAULT 'Z'
,DIM_VALUE_ID2 CHAR(8) CHARACTER SET LATIN CASESPECIFIC TITLE ' 维度 2' NOT NULL DEFAULT 'Z'
,DIM_VALUE_ID3 CHAR(8) CHARACTER SET LATIN CASESPECIFIC TITLE ' 维度 3' NOT NULL DEFAULT 'Z'
,...
,DIM_VALUE_ID18 CHAR(8) CHARACTER SET LATIN CASESPECIFIC TITLE ' 维度 18' NOT NULL DEFAULT 'Z'
,DIM_VALUE_ID19 CHAR(8) CHARACTER SET LATIN CASESPECIFIC TITLE ' 维度 19' NOT NULL DEFAULT 'Z'
,DIM_VALUE_ID20 CHAR(8) CHARACTER SET LATIN CASESPECIFIC TITLE ' 维度 20' NOT NULL DEFAULT 'Z'
,DIM_VALUE_IDn CHAR(8) CHARACTER SET LATIN CASESPECIFIC TITLE ' 维度 n' NOT NULL DEFAULT 'Z'
,KPI_ASSESS_TYPE_ID CHAR(4) CHARACTER SET LATIN CASESPECIFIC TITLE 'KPI 目标类型 ID' NOT NULL
,KPI_ASSESS_RESULT_ID CHAR(2) CHARACTER SET LATIN CASESPECIFIC TITLE 'KPI 目标值返回值 ID' NOT NULL
,KPI_ASSESS_VALUE DECIMAL(18,2) TITLE 'KPI 目标值 ')
PRIMARY INDEX ( DATA_DATE ,KPI_ID , DIM_VALUE_ID1)
PARTITION BY RANGE_N(DATA_DATE BETWEEN 20000101 AND 20191231)
UNIQUE INDEX (KPI_ID,FREQ_ID,DATA_DATE,DIM_VALUE_ID1,DIM_VALUE_ID2,DIM_VALUE_ID3,...,DIM_VALUE_ID18,
DIM_VALUE_ID19,DIM_VALUE_ID20,DIM_VALUE_IDn,KPI_ASSESS_TYPE_ID,KPI_ASSESS_RESULT_ID);
COLLECT STATISTICS ON tctap.tap_c_kpi_assess_2 COLUMN ( DATA_DATE ,KPI_ID , DIM_VALUE_ID1);
COLLECT STATISTICS ON tctap.tap_c_kpi_assess_2 COLUMN ( DATA_DATE );
COLLECT STATISTICS ON tctap.tap_c_kpi_assess_2 COLUMN (KPI_ID,FREQ_ID,DATA_DATE,DIM_VALUE_ID1,DIM_VALUE_ID2,DIM_VALUE_ID3,...
,DIM_VALUE_ID18,DIM_VALUE_ID19,DIM_VALUE_ID20,DIM_VALUE_IDn,KPI_ASSESS_TYPE_ID,KPI_ASSESS_RESULT_ID);
COLLECT STATISTICS ON tctap.tap_c_kpi_assess_2 COLUMN (KPI_ID);
内部资料,注意保密
可变临时表
建表语句:
CREATE VOLATILE MULTISET TABLE vt_RETAIN_ANLY_MON (
col1 …,
col2…
) PRIMARY INDEX (PI_Cols)
; ON COMMIT PRESERVE ROWS;
复制表结构:
CREATE MULTISET VOLATILE TABLE VT_APP_AGG_INDEX_H
AS DWMart_DOA.DOA_APP_AGG_INDEX_H
WITH DATA(NO DATA)
ON COMMIT PRESERVE ROWS
;
CREATE VOLATILE MULTISET TABLE VT_RETAIN_ANLY_MON AS
( SELECT col1,col2, …
FROM …
WHERE … GROUP BY ….
) WITH DATA PRIMARY INDEX (PI_Cols)
ON COMMIT PRESERVE ROWS;
内部资料,注意保密
全局临时表
建表语句
CREATE GLOBAL TEMPORARY TABLE gt_deptsal
(deptno SMALLINT
,avgsal DEC(9,2)
,maxsal DEC(9,2)
,minsal DEC(9,2)
,sumsal DEC(9,2)
,empcnt SMALLINT)
FROM
FROM scott.emp
GROUP BY deptno)tmp
内部资料,注意保密
固化临时表
• 固化临时表,就是把查询结果存放到一张物理表。
• 共下次分析或他人使用。
• Session 断开之后,仍然可以使用。
• 在性能优化中也常被用到的一种做法。
• 示例 1 :
CREATE MULTISET TABLE tttemp.TMP_BOSS_VOIC AS (
SELECT ***
FROM pview.vw_net_gsm_nl
) WITH NO DATA PRIMARY INDEX (subs_id)
;
INSERT INTO tttemp.TMP_BOSS_VOIC
SELECT *** FROM pview.vw_net_gsm_nl WHERE ****;
• 示例 2 :
CREATE MULTISET TABLE tttemp.TMP_BOSS_VOIC AS (
SELECT *** FROM pview.vw_net_gsm_nl WHERE ***
) WITH DATA PRIMARY INDEX (subs_id);
• 示例 3 : ( 复制表,数据备份)
CREATE MULTISET TABLE tttemp.TMP_BOSS_VOIC AS pdata.tb_net_gsm_nl
WITH DATA ;
内部资料,注意保密
修改表定义
常见的表定义修改操作:
> 增加字段
> 修改字段长度
建议的操作流程
1. Rename table db.tablex as db.tabley;
2. 通过 Show table 语句获得原表 db.tablex 的定义
3. 定义新表: db.tablex
4. Insert into db.tablex( 。。。 )
select 。。。 From db.tabley;
5. Drop table db.tabley;
Teradata 提供 ALTER TABLE 语句,可进行修改表定义但,不建议采用
ALTER TABLE 方式。
内部资料,注意保密
Update/Delete 操作
对于大表进行 Update/DELETE 操作,将耗费相当多的资源与相当长的时间。
Update/Delete 操作,需要事务日志 TJ ( Transient Journal )
以防意外中断导致数据受到破坏
在 Update/Delete 操作中途被 Cancel ,系统则需回滚,这将耗更多的资源与时
间!
UPDATE Customer DELETE FROM Trans
SET Credit_Limit = Credit_Limit * 1.20 ; WHERE Trans_Date < 990101;
内部资料,注意保密
Insert/select : the fast path
INSERT INTO New_Table
Parsing Engine Parsing Engine
SELECT * FROM Old_Table ;
内部资料,注意保密
Delete all : the fast path
DELETE FROM Old_Table ALL; Parsing Engine Parsing Engine
DELETE achieves its highest performance with use of the ALL option.
内部资料,注意保密
Agenda
Teradata Client 安装
Teradata 架构
PI 、 SI 、 PPI 机制
数据重分布及 JOIN 机制
SQL 函数及开发经验
内部资料,注意保密
Storing Rows
每个表的行被分配到所有的 AMP 中
每个 AMP 负责每个表中的行子集
理想的情况下,每个表将被均匀地分配到所有的 AMP 中去
均匀分配的表将使系统工作量得以均匀的分配
创建表的时候创建主索引
主索引可以由 1 列或多到 64 列组合而成。
具有同一 PI 值的所有数据行存放在同一个 AMP 中。
PI 的选择非常重要,它会影响到数据行的分布,进而影响到性能。
内部资料,注意保密
Primary Index Values
内部资料,注意保密
Accessing Via a Unique Primary Index
A UPI access is a one-AMP operation which may access at most a single row.
内部资料,注意保密
Accessing Via a Non-Unique Primary Index
内部资料,注意保密
Primary Keys and Primary Indexes
索引在概念上区别于键:
主键是关系模型的惯例,允许每一行被唯一确定。
主索引是 Teradata 的惯例,确定行怎样被存储和访问。
很大一部分的表使用相同的列作为主键和主索引。
在一个设计较好的数据库中,一些表也使用与主键不同的主索引。
必须唯一 可以是唯一或非唯一
确定每一行 用来放置或定位 AMP 中的每一行
值不能被改变 值可以被改变 (Delete + Insert)
不能为空值――需要一个值 可以为空值
不指示访问路径 定义最有效率的访问路径
为逻辑的正确性而选择的 为物理性能而选择的
内部资料,注意保密
Duplicate Rows
重复行是指一个行所有列的值与同一个表中其它的行完全相同。
因为一个主键唯一确定每一行,关系表在理想上不应该有重复的行。
通过建立一个 MULTISET 表而不是默认的 SET 表, Teradata 允许在特定情形下
存在重复行。
一个表必须被定义为 SET 或 MULTISET 。
检查不允许重复行存在 不检查允许重复行存在
If a UPI is selected on a SET table, the duplicate row check is replaced by a check
for duplicate index values.
如果 SET 表中选择 UPI ,重复行的检查被重复索引值的检查所替代。
内部资料,注意保密
Row Distribution Using a UPI – Case 1
Order
Notes:
• 主键的列经常被作为 UPI 使用。
• Order_Number 的主键值是唯一的(它是 PK )。
• Teradata 将在所有的 AMP 中均匀分配这些不同的索引
值。
• 结果是所有行在 AMP 中的分配是均衡的。
• 确保并行操作最高的效率。
o_# c_# o_dt o_# c_# o_dt o_# c_# o_dt o_# c_# o_dt
o_st o_st o_st o_st
7202 2 4/09 C 7325 2 4/13 O 7188 1 4/13 C 7324 3 4/13 O
7415 1 4/13 C 7103 1 4/10 O 7225 2 4/15 C 7384 1 4/12 C
7402 3 4/16 C
内部资料,注意保密
Row Distribution Using a NUPI – Case 2
Order
Notes:
• Customer_Number 可以作为 Order 表的首选访问列,是
一个好的索引候选列。
• Customer_Number 的值是非唯一的。
• 选择 Customer_Number ,所以是 NUPI.
• 有相同 PI 值的行分配到同一个 AMP 中
• 导致了行的不一致或倾斜分布 .
o_# c_# o_dt o_st o_# c_# o_dt o_st o_# c_# o_dt o_st
7325 2 4/13 O 7384 1 4/12 C 7402 3 4/16 C
7202 2 4/09 C 7103 1 4/10 O 7324 3 4/13 O
7225 2 4/15 C 7415 1 4/13 C
7188 1 4/13 C
内部资料,注意保密
Row Distribution Using a Highly Non-
Unique Primary Index (NUPI) – Case 3
Order Notes:
• Order_Status 的值是高度非唯一的,因而它是一个
NUPI 。
• 只有两种值存在,所以只有两个 AMP 用于这个表。
• 这个表在并行操作中不能很好地执行。
• 高度非唯一是糟糕的 PI 选择。
• 唯一性的程度对其效率很重要。
Data Table
Row ID Row data Summary
Row Hash Uniq Value
The MPL uses the DSW of
x '00000000'
1177 and uses this value to
locate bucket #1177 in the
RH Data x'1177 7C3C' 0000 0001 38 Hash Map.
hashing algorithm
{ 哈希算法设计是用来保证所有的唯一值在 AMP 中均匀分配。
不同的哈希算法应用于不同的国际字符集。
Row Hash
DSW or
Hash Bucket #
{ Row Hash 是索引值通过哈希算法得出来的一个 32 位的结果
Hash Map
{ 哈希图 (Hash Map) 在每个系统中是唯一配置的。
AMP #
{ 两个有相同数目 AMP 的系统有相同的哈希图 .
内部资料,注意保密
A Hashing Example
Order
Order Customer Order Order SELECT * FROM order
Number Number Date Status WHERE order_number = 7202;
PK
UPI 7202
7325 2 4/13 O
7324 3 4/13 O
7415 3 4/13 O
Hashing Algorithm
7415 1 4/13 C
7103 1 4/10 O
7225 2 4/15 C
7384 1 4/12 C
7402 3 4/12 C 691B 14AE
7188 1 4/13 C
7202 2 4/09 C
6 9 1 B
内部资料,注意保密
The Hash Map
(Hexadecimal) 6 9 1 B
HASH MAP
0 1 2 3 4 5 6 7 8 9 A B C D E F AMP 9
690 07 06 07 06 07 04 05 06 05 05 14 09 14 13 03 04
691 15 08 02 04 01 00 14 14 03 02 03 09 01 00 02 15
692 01 00 15 11 14 14 13 13 14 14 08 09 15 10 09 09
693 07 06 15 13 11 06 15 08 15 15 08 08 11 07 05 10 7202 2 4/09 C
694 04 12 11 13 05 10 07 07 03 02 11 04 01 00 11 13
695 11 11 12 10 03 02 06 13 01 00 06 05 07 06 05 12
Note: This partial Hash Map is based on a 16 AMP system and AMPs are shown in decimal format.
内部资料,注意保密
The Hash Map (Cont.)
SELECT
HASHROW (7202) AS "Hash Value"
,HASHBUCKET (HASHROW (7202)) AS "Bucket Num"
,HASHAMP (HASHBUCKET (HASHROW (7202))) AS "AMP Num"
,HASHBAKAMP (HASHBUCKET (HASHROW (7202))) AS "AMP Fallback Num" ;
SELECT HASHROW(Base_Index_Id ,Index_Attrib_Id ,Org_Id ,Currency_Cd ,
Statistics_Dt ) AS "Hash Value"
,COUNT(*)
FROM DWMart_DOA.DOA_BAS_AGG_INDEX_H
GROUP BY 1
ORDER BY 2 DESC
;
SELECT HASHAMP(HASHBUCKET(HASHROW(Base_Index_Id ,Index_Attrib_Id ,
Org_Id ,Currency_Cd ,Statistics_Dt ))) AS "AMP #"
,COUNT(*)
FROM DWMart_DOA.DOA_BAS_AGG_INDEX_H
GROUP BY 1
ORDER BY 2 DESC
;
内部资料,注意保密
Identifying Rows
Consideration #1
1254 7769 Data values input
哈希碰撞
A Row Hash = 32 bits = 4.2 billion 可能的值
(哈希冲突)
Hash Algorithm
因为可能的值有无穷多,一些值必须共享相同的 Row
10A2 2936 10A2 2936 Hash Synonyms
Hash
Consideration #2
(John) (Dave)
'Smith' 'Smith' NUPI Duplicates
一个主索引可以是非唯一的( NUPI )
Hash Algorithm
不同的行有相同的主索引值因而有相同的 Row Hash
0016 5557 0016 5557 Rows have
same hash
Conclusion:
一个 Row Hash 不足以唯一确定一行。
内部资料,注意保密
The Row ID
为了唯一确定一个行,系统增加了一个 32 位的唯一值:
Row Hash 和唯一值组合起来称为 Row-ID
Row hash 只用于主索引操作
整个 Row-ID 用于次索引操作
Row Hash Uniqueness Id
Row ID (32 bits) (32 bits)
每一个存储有一个
Row-ID 做前缀。 Row ID Row Data
内部资料,注意保密
Storing Rows
Assumptions:
Last_Name is defined as a NUPI.
All rows in this example hash to the same AMP.
Add a row for 'John Smith'
AMP 3
Data Table
Add a row for 'Sam Adams'
Row ID Row Data
'Adams' Hash Algorithm 1058 9829 Hash Map AMP #3 Row Hash Uniq Value Last_Name First_Name Etc.
0016 5557 0000 0001 Smith John
内部资料,注意保密
Locating a Row On An AMP Using a PI
Locating a row on an AMP AMP #3
requires three input elements: M Cyl 1 Cyl 2 Cyl 3 Cyl 4 Cyl 5 Cyl 6 Cyl 7
a Index Index Index Index Index Index Index
1. The Table ID s
#
2. The Row Hash of the PI t er
lind PI Value
3. The PI value itself e Cy
r DATA
BLOCK
I
Table ID Data Row
Data Row
n
Row Hash d
e
x
次索引是访问表里的行的一种可替换的方法。
一个表可以有 0 到 32 条次索引。
次索引:
- 不影响表的分配
- 在磁盘空间和维护方面增加系统开销
- 在需要的时候可以被动态删除或增加
- 是选择用来提高表的性能
内部资料,注意保密
Choosing a Secondary Index
A Secondary Index may be defined ...
在表建立时 (CREATE TABLE)
在表建立以后 (CREATE INDEX)
最多使用 16 列 (V2R4.1); 64 列 (V2R5.0)
USI NUSI
如果次索引选择的列是唯一的,称为 USI (唯 如果次索引选择是非唯一的,称为 NUSI (非
一次索引) 唯一次索引)
通过一个 USI 访问行需要 2 次 AMPs 操 通过一个 NUSI 访问行需要全部的 AMP
作
内部资料,注意保密
Unique Secondary Index (USI) Access
Message Passing Layer
Create USI
CREATE UNIQUE INDEX AMP 1 AMP 2 AMP 3 AMP 4
(Cust) ON Customer;
USI Subtable USI Subtable USI Subtable USI Subtable
Access via USI RowID Cust RowID RowID Cust RowID RowID Cust RowID RowID Cust RowID
244, 1 74 884, 1 135, 1 98 555, 6 288, 1 31 638, 1 175, 1 37 107, 1
SELECT * 505, 1 77 639, 1 296, 1 84 536, 5 339, 1 40 640, 1 489, 1 72 717, 2
FROM Customer 744, 4 51 915, 9 602, 1 56 778, 7 372, 2 45 471, 1 838, 4 12 147, 2
757, 1 27 388, 1 969, 1 49 147, 1 588, 1 95 778, 3 919, 1 62 822, 1
WHERE Cust = 56;
内部资料,注意保密
Non-Unique Secondary Index (NUSI) Access
Message Passing Layer
Create NUSI
CREATE INDEX (Name) ON AMP 1 AMP 2 AMP 3 AMP 4
Customer;
PE
Customer NUSI Value = 'Adams'
Table ID = 100 AMP 1 AMP 2 AMP 3 AMP 4
Hashing
Algorithm
Base Table Base Table Base Table Base Table
RowID Cust Name Phone RowID Cust Name Phone RowID Cust Name Phone RowID Cust Name Phone
Table ID Row Hash NUSI Value NUSI NUPI NUSI NUPI NUSI NUPI NUSI NUPI
107, 1 37 White 555-4444 471, 1 45 Adams 444-6666 147, 1 49 Smith 111-6666 639, 1 77 Jones 777-6666
100 567 Adams 536, 5 84 Rice 666-5555 555, 6 98 Brown 333-9999 147, 2 12 Young 777-4444 778, 3 95 Peters 555-7777
638, 1 31 Adams 111-2222 717, 2 72 Adams 666-7777 388, 1 27 Jones 222-8888 778, 7 56 Smith 555-7777
640, 1 40 Smith 222-3333 884, 1 74 Smith 555-6666 822, 1 62 Black 444-5555 915, 9 51 Marsh 888-2222
to MPL
内部资料,注意保密
PI vs SI
Index Feature Primary Secondary
Required? Yes No
Number per Table 1 0 - 32
Max Number of Columns (V2R4.1) 16 16
Max Number of Columns (V2R5) 64 64
Unique or Non-unique Both Both
Affects Row Distribution Yes No
Created/Dropped Dynamically No Yes
Improves Access Yes Yes
Multiple Data TypesYes Yes
Separate Physical Structure No Sub-table
Extra Processing Overhead No Yes
May be Partitioned (V2R5) Yes No
内部资料,注意保密
Full Table Scans
表里的每行都需要被读取
- 每行都只被访问一次
- 所有的 AMP 并行地扫描表的一部分
- 如果主索引可以导致均匀分配,则全表扫描会非常有效率
全表扫描使用在:
- 查询没有使用索引的时候
- 索引被用在不等值的查询中
Customer
Cust_ID Cust_Name Cust_Phone
USI NUPI
内部资料,注意保密
Logical Example of NPPI versus PPI
RH O_# O_Date RH O_# O_Date RH O_# O_Date RH O_# O_Date
4 AMPs with '01' 1028 06/03 '06' 1009 06/01 '04' 1008 06/01 '02' 1024 06/02
Orders Table defined '03' 1016 06/02 '07' 1017 06/02 '05' 1048 06/04 '08' 1006 06/01
with NPPI. '12' 1031 06/03 '10' 1034 06/03 '09' 1018 06/02 '11' 1019 06/02
'14' 1001 06/01 '13' 1037 06/04 '15' 1042 06/04 '18' 1041 06/04
'17' 1013 06/02 '16' 1021 06/02 '19' 1025 06/03 '20' 1005 06/01
'23' 1040 06/04 '21' 1045 06/04 '24' 1004 06/01 '22' 1020 06/02
'28' 1032 06/03 '26' 1002 06/01 '27' 1014 06/02 '25' 1036 06/03
'30' 1038 06/04 '29' 1033 06/03 '32' 1003 06/01 '31' 1026 06/03
'35' 1007 06/01 '34' 1029 06/03 '33' 1039 06/04 '38' 1046 06/04
'39' 1011 06/01 '36' 1012 06/01 '40' 1035 06/03 '41' 1044 06/04
'42' 1047 06/04 '36' 1043 06/04 '44' 1022 06/02 '43' 1010 06/01
'48' 1023 06/02 '45' 1015 06/02 '47' 1027 06/03 '46' 1030 06/03
'03' 1016 06/02 '07' 1017 06/02 '09' 1018 06/02 '02' 1024 06/02
'17' 1013 06/02 '16' 1021 06/02 '27' 1014 06/02 '11' 1019 06/02
'48' 1023 06/02 '45' 1015 06/02 '44' 1022 06/02 '22' 1020 06/02
'01' 1028 06/03 '10' 1034 06/03 '19' 1025 06/03 '25' 1036 06/03
'12' 1031 06/03 '29' 1033 06/03 '40' 1035 06/03 '31' 1026 06/03
'28' 1032 06/03 '34' 1029 06/03 '47' 1027 06/03 '46' 1030 06/03
'23' 1040 06/04 '13' 1037 06/04 '05' 1048 06/04 '18' 1041 06/04
'30' 1038 06/04 '21' 1045 06/04 '15' 1042 06/04 '38' 1046 06/04
内部资料,注意保密
'42'
1047 06/04 '36' 1043 06/04 '33' 1039 06/04 '41' 1044 06/04
Agenda
Teradata Client 安装
Teradata 架构
PI 、 SI 、 PPI 机制
数据重分布及 JOIN 机制
SQL 函数及开发经验
内部资料,注意保密
Join 之前的重分布
PI PI
T2 T2
Subs_id B C Subs_id B C
用户资料表 PI PI
100 725 002 200 725 002
内部资料,注意保密
Join 之前的重分布
Join 的列都是在一个表上是 PI ,另外一个表上不是 PI 是 PI 的表不需要重分布 .
SELECT ...
FROM 用户资料表 T1
INNER JOIN 客户资料表
ON T1.Cust_id = AMP1 AMP2
T2.Cust_id;
Subs_id Cust_id Subs_id Cust_id
用户资料表 PI PI
100 214 200 214
T2 T2
Cust_id B C Cust_id B C
客户资料表 PI PI
214 725 002 408 133 009
内部资料,注意保密
Join 之前的重分布
AMP1 AMP2
Subs_id Cust_id Subs_id Cust_id
用户资料表
PI PI
100 214 200 214
100 408
T2 T2
Cust_id B C Cust_id B C
客户资料表
PI PI
214 725 002 408 133 009
内部资料,注意保密
重分布的问题
大表的代码字段与小表的 PI 字段
SELECT city_name
, COUNT(DISTINCT subs_id)
FROM TB_Ofr_Subs A
JOIN TB_CDE_City B
ON A.city_id = B.city_id
如果选择重分布的策略,意味着将所有的用户按照地市重分布到所有的 AMP
上
系统总共 130 个 AMP 、总共 13 个市
内部资料,注意保密
Join 之前的复制小表到所有的 AMP
AMP1 AMP2
City_id City_name City_id
地市代码表 City_name
PI
PI
100 A市
200 A市
100 A市
100 A市
200 B市
200 B市
T2 T2
Cust_id City_id Cust_id City_id
用户资料表
PI PI
214 200 408 100
内部资料,注意保密
复制小表到 Spool 空间
Table 1M 1M 1M 1M 1M 1M 1M 1M
rows rows rows rows rows rows rows rows
Table 1M 1M 1M 1M 1M 1M 1M 1M
rows rows rows rows rows rows rows rows
SPOOL
( 表被复制到所有的 AMP 上 )
8M 8M 8M 8M 8M 8M 8M 8M
rows rows rows rows rows rows rows rows
内部资料,注意保密
数据已经到了一个 AMP 上,关联怎么做???
内部资料,注意保密
关联策略 Merge Join
适用情况: Join Join
两个表的数据量都比较大时 Column Column
Hash Hash
例如 100 万 × 30 万
A3 Data A3 Data
B8 Data A3 Data
C4 Data A3 Data
B7 Data
用来 Join 的记录必须位于相同的 AMP 上
B7 Data
• Merge Join 仅仅读取每个表一次 . C4 Data
• 对于等值条件的 Join ,优化器经常会选用 Merge Join. C4 Data
• 通常情况下比 product join 的效率更高 .
Merge join 处理流程 :
• 找到一个小表 .
• 如果需要 :
– 将一个或者两个表要用到的数据都放在 Spool 空间里 .
– 基于 Join 列的 hash 值将记录重分布到相应的 AMP.
– 根据 Join 列的 hash 顺序对 spool 里面的记录进行排序 .
内部资料,注意保密
关联策略 Nested Joins
Employee Department
Example:
Enum Name Dept Dept Name
SELECT E.Name PK FK PK
,D.Name UPI UPI
FROM Employee E 1 BROWN 200 150 PAYROLL
INNER JOIN Department D 2 SMITH 310 200 FINANCE
3 JONES 310 310 MFG.
ON E.Dept = D.Dept
4 CLAY 400 400 EDUCATION
WHERE E.Enum = 5; 5 PETERS 150
6 FOSTER 400
7 GRAY 310
8 BAKER 310
内部资料,注意保密
关联策略 Product Join
Data
Data
Data Data Rows must be on the
Data Data same AMP to be joined.
Data Data
Data
Data
• 不对记录做排序
• 如果内存里面放不下的时候需要多次读取某张表 .
适用情况:
• Table1 的每条记录要与 Table2 的每条记录进行比对 . 大表非 PI 字段对小表
例如 30 万 × 50
• 满足条件的记录会被放到 spool 空间中 .
• 之所以会被称作 Product Join 是因为 :
总共的比较次数 = Table 1 的记录条数 * Table 2 的记录条数
• 当内存里面不能存放某一个表的所有数据的时候,这种比较会变得非常的消耗资源,因为总是需要内外
存的交换。
• 如果没有 where 条件, Product Join 通常会产生无意义的结果 .
• Product Join 处理步骤 :
• 找到小表并在 Spool 空间中复制到所有 AMP 上 .
• 在每个 AMP 上, Spool 空间里的小表的每一行和大表在该 AMP 上的每一行做 Join.
内部资料,注意保密
关联策略 Hash Join
Join Column
Hash
Join Column C4 Data
Hash
A3 Data
A3 Data
C6 Data
B8 Data
F6 Data
C4 Data
B7 Data
Cache Memory C4 Data
A3 Data
这种 join 将减少大表的排序、重分布或者拷贝 .
EXPLAIN 将会看见类似于“ Single Partition Hash Join” 的术语 .
内部资料,注意保密
Merge Join (e.g.)
1 )关联表 PI 相同
SELECT
a.acyc_id,
COALESCE(c.city_code,'*'),
COALESCE(c.cmcc_brand_code,'*'),
COALESCE(c.user_id,'*')
FROM dwpmdvw.vw_smsdetail_mon a
LEFT JOIN dwpmdvw.vw_user_info_mon c
ON a.user_id=c.user_id
WHERE a.acyc_id='200611'
2 ) PI 不同
SELECT
COALESCE(a.city_code,'*'),
COALESCE(a.cmcc_brand_code,'*'),
COALESCE(a.user_id,'*')
FROM dwpmdvw.vw_user_info_mon a
LEFT JOIN dwpdata.tf_f_customer b
ON a.cust_id=b.cust_id
WHERE a.acyc_id='200611' AND b.eparchy_code = '0913'
内部资料,注意保密
如何确认自己的查询效率很高
Explain SQL 语句
内部资料,注意保密
Merge Join (Matching Primary Indexes)
QUERY
EXPLAIN Employee Employee_Number Emp_Phone
SELECT Last_Name, First_Name, (26,000 rows) (52,000 rows)
Area_Code, Phone_Number,
Extension
FROM Employee E Last_Name First_Name Area_Code
INNER JOIN Emp_Phone P Phone_Number
ON E.Employee_Number = P.Employee_Number Extension
ORDER BY 1, 2;
EXPLANATION V2R6.1
EXPLAIN
------------------------------------------------------------------------------------------------------------------------------------------------------
1) First, we lock a distinct TFACT."pseudo table" for read on a RowHash to prevent global deadlock for TFACT.P.
2) Next, we lock a distinct TFACT."pseudo table" for read on a RowHash to prevent global deadlock for TFACT.E.
3) We lock TFACT.P for read, and we lock TFACT.E for read.
4) We do an all-AMPs JOIN step from TFACT.E by way of a RowHash match scan with no residual conditions, which is
joined to TFACT.P. TFACT.E and TFACT.P are joined using a merge join, with a join condition of
("TFACT.E.Employee_Number = TFACT.P.Employee_Number"). The input table TFACT.E will not be cached in
memory, but it is eligible for synchronized scanning. The result goes into Spool 1 (group_amps), which is built locally
on the AMPs. Then we do a SORT to order Spool 1 by the sort key in spool field1. The result spool file will not be
cached in memory. The size of Spool 1 is estimated with low confidence to be 52,000 rows. The estimated time for
this step is 0.72 seconds.
5) Finally, we send out an END TRANSACTION step to all AMPs involved in processing the request.
-> The contents of Spool 1 are sent back to the user as the result of statement 1. The total estimated time is 0.72
seconds.
内部资料,注意保密
Hash Join
QUERY
EXPLAIN Employee Dept_Number Department
SELECT Last_Name, (26,000 rows) (1403 rows)
First_Name,
Dept_Name
FROM Employee E Last_Name First_Name Dept_Name
INNER JOIN Department D
ON E.Dept_Number =
D.Dept_Number;
EXPLANATION V2R6.1 EXPLAIN
-----------------------------------------------------------------------------------------------------------------------------------------------------
:
4) We do an all-AMPs RETRIEVE step from TFACT.E by way of an all-rows scan with a condition of ("NOT
(TFACT.E.Dept_Number IS NULL)") into Spool 2 (all_amps), which is redistributed by hash code to all AMPs. The
input table will not be cached in memory, but it is eligible for synchronized scanning. The size of Spool 2 is
estimated with high confidence to be 26,000 rows. The estimated time for this step is 0.52 seconds.
5) We do an all-AMPs JOIN step from TFACT.D by way of an all-rows scan with no residual conditions, which is joined
to Spool 2 (Last Use) by way of an all-rows scan. TFACT.D and Spool 2 are joined using a single partition hash join,
with a join condition of ("Dept_Number = TFACT.D.Dept_Number"). The result goes into Spool 1 (group_amps),
which is built locally on the AMPs. The result spool file will not be cached in memory. The size of Spool 1 is
estimated with low confidence to be 26,000 rows. The estimated time for this step is 0.33 seconds.
6) Finally, we send out an END TRANSACTION step to all AMPs involved in processing the request.
-> The contents of Spool 1 are sent back to the user as the result of statement 1. The total estimated time is 0.85
seconds.
内部资料,注意保密
Product Join
Dept_Number
Employee Department
(26,000 rows) Employee_Number (1403 rows)
Dept_Mgr_Number
Employee_Number Last_Name First_Name Dept_Name
QUERY
EXPLAIN
SELECT D.Dept_Name,
E.Employee_Number,
E.Last_Name,
E.First_Name
FROM Employee E
INNER JOIN Department D
ON E.Dept_Number = D.Dept_Number
OR E.Employee_Number = D.Dept_Mgr_Number
ORDER BY 1, 2, 3, 4;
内部资料,注意保密
n-Table Joins
• All n-Table joins are reduced to a series of two-table joins.
• The Optimizer attempts to determine the best join order.
• Collected Statistics on Join columns help the Optimizer choose wisely.
SELECT …. FROM Table_A, Table_B, Table_C, Table_D WHERE . . . ;
SPOOL
FILE
Teradata 架构
PI 、 SI 、 PPI 机制
数据重分布及 JOIN 机制
SQL 函数及开发经验
内部资料,注意保密
Teradata 帮助系统
HELP 命令
SHOW 命令
EXPLAIN 命令
在 TYPE 栏中,可能的输出说明如下:
类型 说明
I INTEGER
I1 BYTEINT
I2 SMALLINT
DA DATE
D DECIMAL
CV CHARACTER VARIABLE (VARCHAR)
CF CHARACTER FIXED (CHAR)
内部资料,注意保密
逻辑表达式运算符
标准的逻辑表达式运算符种类如下所示:
运算符种类 符号 含义
比较运算符 = 等于
<> 不等于
> 大于
< 小于
>= 大于或等于
<= 小于或等于
[NOT] BETWEEN <a> 介于 a 和 b 之间或不介于 a 和 b 之间
AND <b>
[NOT] IN [NOT] IN 属于或不属于某个集合
IS [NOT] NULL IS [NOT] NULL 一个数值是空值或不是空值
[NOT] EXISTS [NOT] EXISTS 一个查询至少返回一行或不返回任何行
LIKE LIKE 与某个数或值匹配
内部资料,注意保密
LIKE 中限定词的使用:
利用一些限定词可以扩充 LIKE 在字符串匹配方面的功能。可以使用的限定词包含:
限定词 含义
ANY 与一个或多个数值匹配
SOME (ANY 的同义词 ) 同上
ALL 与列举的所有数值匹配
例如:查询员工姓中任意位置有字母’ E’ 如果改变一下上面的问题,要求查找员工姓
和’ S’ 的员工,可以使用下面的 SQL 中任意位置有字母’ E’ 或者’ S’ 的员
语句。
工,则应使用 ANY 或 SOME 。
SELECT first_name
SELECT first_name
,last_name
,last_name
FROM employee
FROM employee
WHERE last_name LIKE ALL ('%E
WHERE last_name LIKE ANY ('%E
%','%S%');
%','%S%');
内部资料,注意保密
大小写敏感
SELECT UPPER('sc');
SELECT LOWER('Sc');
SELECT 'Sc'(UPPERCASE);
内部资料,注意保密
Teradata / Oracle 常用语法比较
Oracle Teradata
nvl(f1,f2,…) coalesce(f1,f2…)
End
select cast (cast(dt1 as date format
to_char(d1,'YYYYMMDD')
'YYYYMMDD') as char(8))
SELECT CAST((20100520-19000000) AS DATE FORMAT
to_date(20040815,'YYYYMMDD')
'YYMMDD')
select cast ( '20040815' as date format
'YYYYMMDD')
to_date('20040815','YYYYMMDD')
select cast ( '20040815 212301' as
timestamp(0) format 'YYYYMMDDbHHMISS')
nvl(f1,0) zeroifnull(f1)
nvl(f1,0) nullif(f1,0)
select … from A left ( outer ) join B on
select … from A, B where A.f1 = B.f2 (+)
A.f1 = B.f2
内部资料,注意保密
Teradata / Oracle 常用语法比较( cont. )
INTEGER INTEGER
CHAR CHAR
VARCHAR2 VARCHAR
NUMBER(M,N) DECIMAL(M+N,N)
DATE : 只存日子
INTEGER : 200102
DATE TIMESTAMP(6) : 存日子,时间,秒数到小数后六个
位(极不常用,不推荐使用。)
TIMESTAMP : TIMESTAMP(6) (如果不给小数位,
系统会自动给六个位)
CHARACTERS() 简写成 CHARACTER() 、 CHARS() 或者
length()
CHAR() 不能统计数字型
trunc(to_date('20090323','YYYYMMDD'),'month')
trunc(23.53,1)
ROUND((200392/ 10000),2) cast(200392/10000.00 as decimal(10,2))
SELECT (DATE'2010-05-01')-(DATE'2010-10-01')
select months_between (date'2010-5-1', MONTH(4) AS m
date'2010-10-1') from dual SELECT (DATE'2010-05-01')-(DATE'2010-10-01')
DAY(4) AS d
select add_months (date'2010-4-30',1) from dual select add_months (date'2010-04-30',1)
2009-05-31 2010-05-30
内部资料,注意保密
TRIM 函数
语法 意义
SQL: 输出:
Teradata 没 replace 函数
内部资料,注意保密
SQL 变量
SELECT DATABASE; 显示当前数据库
DBC
DBC
2010-05-21 , 2010-05-21
2010-05-21 08:44:10
内部资料,注意保密
日期 (DATE) 的操作
取当前天:
SELECT CAST( CURRENT_DATE AS DATE FORMAT 'YYYYMMDD')
取当前天的前一天,后一天
SELECT CAST( CURRENT_DATE -1 AS DATE FORMAT 'YYYYMMDD')
SELECT CAST( CURRENT_DATE + 1 AS DATE FORMAT 'YYYYMMDD')
取前 ( 后 ) 一个月的同一天
SELECT ADD_MONTHS(CURRENT_DATE , -1)
SELECT ADD_MONTHS(CURRENT_DATE , 1)
若 current_date 为 20100331,20100331,'20090229' 结果是什么?
SELECT ADD_MONTHS(DATE'2009-02-28',-12)
SELECT ADD_MONTHS(DATE'2009-02-28',1)
取当前天所在月的第一天
SELECT SUBSTR(CAST(CURRENT_DATE AS DATE FORMAT 'YYYYMMDD'),1,6) || '01';
取当前天所在月的最后一天
SELECT CAST( SUBSTR(CAST( ADD_MONTHS(CURRENT_DATE,1) AS DATE FORMAT 'YYYYMMDD'),1,6) ||
'01'AS DATE FORMAT 'YYYYMMDD') -1
日期相减
SELECT ( DATE '2007-03-01' - DATE '2004-01-01') day(4);
SELECT (DATE'2007-03-01'- DATE'2004-01-01') month(4) ;
时间相减
SELECT (CAST(endtime AS TIMESTAMP) - CAST(starttime AS TIMESTAMP) ) MINUTE(4) AS m ;
SELECT (CAST(endtime AS TIMESTAMP) - CAST(starttime AS TIMESTAMP) ) SECOND(4) AS m ;
内部资料,注意保密
日期 (DATE) 的操作 (cont.)
SELECT EXTRACT(YEAR FROM DATE);
SELECT EXTRACT(MONTH FROM DATE + 30);
SELECT EXTRACT(DAY FROM DATE + 2);
SELECT EXTRACT(HOUR FROM TIME);
SELECT EXTRACT(MINUTE FROM TIME);
SELECT EXTRACT(SECOND FROM TIME);
SELECT ADD_MONTHS(DATE,2);
SELECT ADD_MONTHS(DATE,12*8);
SELECT ADD_MONTHS(‘2002-03-19’,12);
内部资料,注意保密
系统日历: sys_calendar.calendar
时间范围:
1900-01-01 至 2100-12-31
包括:
年 / 季 / 度 / 月 / 周 / 天的信息
day_of_week
day_of_month
day_of_year
month_of_year
quarter_of_year
……
内部资料,注意保密
IN & EXISTS
从逻辑上看, IN 与 EXISTS 是一样的。 IN 子句在外部查询中比较子查询返
回的值,并过滤掉行; EXISTS 子句在子查询内部比较那些值并过滤掉行。
在 teradata 数据库中,一个 NULL 值意味着未知,因此,对一个 NULL 值的
任何比较或操作也都是无效的,而任何返回 NULL 的测试也都被忽略了。
在出现 NULL 值的情况下, 使用 IN 与 EXISTS 查询的结果是一样的。
在出现 NULL 值的情况下, 使用 NOT IN 与 NOT EXISTS 查询的结果是不一
样的。
鉴于以上两种情况,为了保证结果集的完整性,在使用 IN,EXISTS, NOT
IN,NOT EXISTS 的时候,建议使用 coalesce 函数。
一般来讲,使用 EXISTS 的效率高于 IN ,使用 NOT EXISTS 的效率高于 NOT
IN 。
内部资料,注意保密
Examples using In & Exists
T1.col1 T2.col2 T3.col3
内部资料,注意保密
Coalesce
select coalesce(f1,f2,f3)
f1 f2 f3 Result
A B C A
<NULL> B C B
<NULL> <NULL> C C
<NULL> <NULL> <NULL> NULL
zeroifnull: 时,返回空值
Select zeroifnull(brand_id)
=select coalesce(brand_id,0)
内部资料,注意保密
Rank & Row_Number()
SELECT sales_person
,sales_region
,sales_amount
FROM sales_table
QUALIFY rank_sales= 1;
内部资料,注意保密
PI ( Primary Index 主索引)的选择
PI 影响数据的存储与访问,其选择标准:
不同值尽量多的字段 (More Unique Values)
使用频繁的字段 : 包括值访问和连接访问
少更新
PI 字段不宜太多
最好是手动指定 PI
例子:
CREATE MULTISET TABLE dwPada.TB_XXX_M(
CAL_Month INTEGER TITLE ' 统计月份 ',
City_ID CHAR(4) TITLE ' 地市标识 ',
Channel_ID CHAR(8) TITLE ' 渠道标识 ', Subs_ID:
Subs_id CHAR(12) TITLE ‘ 用户标识 ', 频繁使用
。。。。 Unique Value 多
) PRIMARY INDEX ( subs_id);
例子:
CREATE MULTISET TABLE tttemp.VT_XXX_M as (
SELECT * FROM dwPada.TB_XXX_M 如果不指定 PI ,
WHERE CAL_MONTH = 200802 AND ***
系统默认为 :Cal_Month
)WITH DATA PRIMARY INDEX ( subs_id);
内部资料,注意保密
PI ( Primary Index 主索引)的选择 (cont.)
DDL:
CREATE MULTISET TABLE DWPDATA.TB_XXX_M(
以下 SQL , PI 是否起作用?:
CAL_Month INTEGER TITLE ' 统计月份 ', 1. 值访问
City_ID CHAR(4) TITLE ' 地市标识 ', Select *
Channel_ID CHAR(8) TITLE ' 渠道标识 ', From DWPDATA.TB_XXX_M
Mont_SVC_Type_Cod CHAR(3) TITLE ‘XXX', Where City_ID = ‘070010’
Mont_SVC_CAT_MicroCls_Cod CHAR(3) TITLE ‘XXX1, and Channel_ID= ‘0100’
Mont_SVC_CHRG_Type_Cod CHAR(2) TITLE ‘XXX2', and cal_month = 200707
THR_Brand_Cod CHAR(1) TITLE ‘XXX6',
Mont_Consume_Level_Cod CHAR(2) TITLE ‘XXX3',
2. 连接访问
Consume_Level_Cod CHAR(2) TITLE ‘XXX4',
Select *
。。。。
) From DWPDATA.TB_XXX_M A
PRIMARY INDEX ( LEFT JOIN DWVIEW.VW_XXX_CD B
CAL_Month ,City_ID ,Channel_ID ,Mont_SVC_Type_Cod , ON A. Channel_ID = B. Channel_ID
Mont_SVC_CAT_MicroCls_Cod ,Mont_SVC_CHRG_Type_Cod and A. City_ID = b. City_ID
,THR_Brand_Cod ,Mont_Consume_Level_Cod ,Consume_Level_Cod LEFT JOIN DWVIEW.VW_XXX_TYPE C
); ON A. City_ID = C. City_ID
内部资料,注意保密
PPI 的使用
PPI ( Partition Primary Index ,分区索引),把具有相同分区值的数据聚簇存放在一起;
类似于 SQL Server 的聚簇索引( Cluster Index ), Oracle 的聚簇表( Cluster Table )。
用表分区字段作过滤条件
直接比较 = > <=
不用分区字段作运算
大大加快速度
内部资料,注意保密
PPI 的使用( cont. )
应该修改为
T1. tx_date<=CAST('20070930'AS DATE FORMAT 'YYYYMMDD')
AND T1.tx_date>=CAST('20070901' AS DATE FORMAT 'YYYYMMDD')
内部资料,注意保密
PPI 的使用( cont. )
脚本: tb_030040270.pl
/* 删除当月 */ -- 2 小时
del BASS1.tb_03004 where proc_dt = '200709‘
;
在 proc_dt 建立 PPI
insert into BASS1.tb_03004 -- 7 小时
。。。。
sel ...
from pview.vw_evt_cust_so cust
where acpt_date<='20071007' and
acpt_date>=cast('200710'||'01' as date)
PPI 字段从 Load_Date
调整为 acpt_date
cast(‘200710’||‘01’ as date) 写法错误, PPI 不起作用
日期的正确写法 :
Cast(‘20071001’ as date format ‘YYYYMMDD’)
内部资料,注意保密
数据类型
注意非日期字段与日期字段 char & date 的转换与关
联:
如果数据类型一致可以直接使用;
在 CASE WHEN or COALESCE 一定要使用显式的类型
转换 (CAST)
CASE WHEN A = B THEN DATE1 ELSE ‘20061031’ END
应写成
CASE WHEN A = B THEN DATE1 ELSE CAST(‘20061031’ AS
DATE) END
数值运算时,确保运算过程中不丢失计算精度。
CAST(100/3 AS DEC(5,2)) 应该写成 CAST(100/3.00 AS
DEC(5,2))
内部资料,注意保密
目标列的选择
减少目标列,可以少消耗 SPOOL 空间,从而提高 SQL 的效率
当系统任务繁忙,系统内存少的时候,效果尤为明显。
举例:
Xx 明细表 ( 视图访问 ) , dwview.vw_xx_det
共有 73 字段,以下 SQL 供返回 1.6 亿条记录
左边的 SQL ,记录最长为: 698 字节,平均 399 字节
右边的 SQL ,记录最长为: 59 字节, 平均 30 字节
两者相差 400 多 GB 的 SPOOL 空间, IO 次数也随着相差甚大!
SELECT
SUBS_ID
SELECT * SPOOL 空间估计: 42 GB
,MSISDN
FROM dwview.vw_xx_det ,Begin_Date
WHERE PROC_DATE ,Begin_Time
,Call_DUR
BETWEEN ‘20070701’ ,CHRG_DUR
AND ‘20070731’ FROM dwview.vw_xx_det
SPOOL 空间估计: 497 GB WHERE PROC_DATE BETWEEN ‘20070701’
AND ‘20070731’
内部资料,注意保密
Where 条件的限定
根据 Where 条件先进行过滤数据集,再进行连接 (JOIN) 等操作
这样,可以减少参与连接操作的数据集大小,从而提高效率
内部资料,注意保密
用 Case When 替代 UNION
sel city_id,channel_id,cust_brand_id,sum(stat_values) as stat_values
from (
......
select t.city_id
,coalesce(v.channel_id,b.channel_id,'-') as channel_id
,cust_brand_id
,sum(case when SMS_SVC_Type_Level_SECND = '017'
and Call_Type_Code in ('00','10','01','11') then sms_quan
else 0 END) as stat_values
from dwview.vw_xxxxxa t 两个子查询的表连接部分完全
left join vt_xxxxxb v 一样
on t.subs_id=v.subs_id
left join dwview.vw_xxxxxc b
两个子查询除了取数据条件,
on t.city_id=b.City_ID 其它都一样。
where cal_date='20070914'
group by 1,2,3
Union all 是多余的,它需要重
复扫描数据,进行重复的 JOIN
union all
select t.city_id
,coalesce(v.channel_id,b.channel_id,'-') as channel_id
,cust_brand_id ,sum(sms_quan) as stat_values 可以用 Case when 替代 union
from dwview.vw_xxxxxa t
left join vt_xxxxxb v
on t.subs_id=v.subs_id
left join dwview.vw_xxxxxc b
on t.city_id=b.City_ID
where cal_date='20070914‘ and SMS_SVC_Type_Level_SECND like '02%'
and SMS_SVC_Type_Level_SECND not in ('021','022')
group by 1,2,3
......
)tmp
Group by 1,2,3 内部资料,注意保密
用 Case When 替代 UNION (cont.)
sel city_id,channel_id,cust_brand_id,sum(stat_values) as stat_values
from (
select t.city_id
,coalesce(v.channel_id,b.channel_id,'-') as channel_id
,cust_brand_id
,sum(CASE WHEN SMS_SVC_Type_Level_SECND = '017'
and Call_Type_Code in ('00','10','01','11')
THEN sms_quan
WHEN SMS_SVC_Type_Level_SECND like '02%'
and SMS_SVC_Type_Level_SECND not in ('021','022')
THEN sms_quan
ELSE 0
END ) as stat_values
from dwview.vw_xxxxxa t
left join vt_xxxxxb v
on t.subs_id=v.subs_id SQL 优化重写
left join dwview.vw_xxxxxc b
on t.city_id=b.City_ID
where cal_date='20070914'
......
)tmp
Group by 1,2,3
内部资料,注意保密
用 OR 替代 UNION
select t.city_id
,coalesce(v.channel_id,b.channel_id,'-') as channel_id
,cust_brand_id
,sum( sms_quan) as stat_values
from dwview.vw_xxxxxa t
left join vt_xxxxxb v SQL 优化重写
on t.subs_id=v.subs_id
left join dwview.vw_xxxxxc b
on t.city_id=b.City_ID
where cal_date='20070914‘
and (( SMS_SVC_Type_Level_SECND = '017
and Call_Type_Code in (‘00’,‘10’,‘01’,‘11’) )
OR (SMS_SVC_Type_Level_SECND like '02%'
and SMS_SVC_Type_Level_SECND not in ('021','022') )
)
Group by 1,2,3
内部资料,注意保密
去掉多余的 Distinct 与 Group by
sel t.operator ,t.acpt_channel_id ,t.acpt_city_id
,t.subs_id ,t.acpt_date as evt_date
From (
sel operator, ACPT_Channel_ID, acpt_city_id,subs_id,
acpt_date
既然 t 查询外层有 group by 操作去
from pview.vw_cust_xxx cust 重,那么子查询内的 Group by 去
where acpt_date ='20071007' and so_meth_code 重是多余的。
in('0','1','2') and PROC_STS_Code ='-1'
而且,两个子查询 group by 后再用
group by 1,2,3,4,5
去重 union all ,就可能再产生重复记录,
union all 那么 group by 也失去意义了。
sel operator_num as operator,
ACPT_Channel_ID, acpt_city_id, subs.subs_id, 解决方法:
charge_date as acpt_date 把 t 查询内部的两个 group by 去掉
from pview.vw_xxx_a sub 去重 即可
join pview.vw_xxx_b bus
on subs.msisdn=bus.msisdn 类似的 Distinct 问题,可效仿解决。
where charge_date ='20071007'
group by 1,2,3,4,5
)t
group by 1,2,3,4,5; 去重
内部资料,注意保密
Group by vs. Distinct
Distinct 是去除重复的操作
Group by 是聚集操作
某些情况下,两者可以起到相同的作用。
两者的执行计划不一样,效率也不一样
建议:使用 Group by
内部资料,注意保密
Union vs. Union all
Union 与 Union all 的作用是将多个 SQL 的结果进行合并。
Union 将自动剔除集合操作中的重复记录;需要耗更多资源。
Union all 则保留重复记录,一般建议使用 Union all 。
第一个 SELECT 语句,决定输出的字段名称,标题,格式等
要求所有的 SELECT 语句:
1) 必须要有同样多的表达式数目;
2) 相关表达式的域必须兼容
select * select *
from (select 'a') T1(col1) from (select 'bc')T3(col3)
union union all
select * select *
from (select 'bc')T2(col2) from (select 'a') T1(col1) col3
union all ----------
col1 select * 'a‘
from (select 'bc')T2(col2)
---------- ‘bc‘
'a‘ ‘bc'
‘b'
内部资料,注意保密
先 Group by 再 join
运行时间 11 小时
Select
case when b.CUST_Brand_ID is null then '5020'
when b.CUST_Brand_ID in('2000','5010') then '5020' 记录数情况:
else b.CUST_Brand_ID end
,sum(COALESCE(b.Bas_CHRG_DUR_Unit,0)) as
t: 580 万, b: 9400 万 , c:8, d:8
Thsy_Accum_New_SUBS_CHRG_DUR
, sum(case when b.call_type_code ='20' then
b.Bas_CHRG_DUR_Unit else 0 END)
from 主要问题:
VT_t t 假如连接顺序为:
inner join VT_b b ( (b join c) join d) join t)
on t.Subs_ID=b.Subs_ID 则是
left join
( (9400 万 join 8) join 8) join 580 万 )
PVIEW.vw_c c
on b.Long_Type_Level_SECND=
数据分布时间长 (IO 多 ) ,连接次数多
c.Long_Type_Level_SECND
left join 解决方法:
PVIEW.vw_d d 先执行 (t join b) ,然后 groupby ,再 join c , d
on b.Roam_Type_Level_SECND=
d.Roam_Type_Level_SECND
group by 1;
内部资料,注意保密
先 Group by 再 join (cont.)
40 秒
Select case when b.CUST_Brand_ID is null then '5020'
when b.CUST_Brand_ID in('2000','5010') then '5020'
记录数情况:
else b.CUST_Brand_ID end
t: 580 万, b: 9400 万 , c:8, d:8
,sum(COALESCE(b.Bas_CHRG_DUR_Unit,0)) as 处理过程:
Thsy_Accum_New_SUBS_CHRG_DUR 先执行 (t join b) ,然后 groupby ,再 join c ,
, sum(case when b.call_type_code ='20' then b.Bas_CHRG_DUR_Unit else 0
END)
d
from
结果:
(select CUST_Brand_ID, call_type_code,
Long_Type_Level_SECND, Roam_Type_Level_SECND,
1 、 VT_T join VT_b
sum(Bas_CHRG_DUR_Unit) Bas_CHRG_DUR_Unit,
PI 相同, merge join ,只需 10 秒
count(*) quan
from VT_t 2 、经过 group by , b 表只有 332 记录
where subs_id in (select subs_id
from VT_b) 3 、 b join c join d , 就是:
332 × 8 × 8
group by 1,2,3,4 ) b
left join PVIEW.vw_c c 4 、最终结果: 5 记录,共 40 秒
on b.Long_Type_Level_SECND=
c.Long_Type_Level_SECND
left join
PVIEW.vw_MID_CDE_ROAM_TYPE_LVL d
on b.Roam_Type_Level_SECND=
d.Roam_Type_Level_SECND
group by 1;
内部资料,注意保密
先 Group by 再 join ( cont. )
先汇总再连接,可以减少参与连接的数据集大小,减少比较次数,从而提
高效率。
以下面 SQL 为例,假设历史表( History )有 1 亿条记录
左边的 SQL ,需要进行 1 亿 × 90 次比较
右边的 SQL ,则只需要 1 亿 × 2 次比较
SELECT SELECT
H.product_id
H.product_id , SUM(H.account_num)
,sum(H.account_num) FROM History H ,
FROM History H , (SELECT
min(calendar_date) min_date
Calendar DT
,max(calendar_date) max_date
WHERE H.sale_date = DT.calendar_date FROM Calendar
AND DT.quarter = '3' WHERE quarter = '3'
GROUP BY 1 ) DT
WHERE H.sale_date
; BETWEEN DT.min_date and DT.max_date
GROUP BY 1
;
内部资料,注意保密
提取公共 SQL 形成临时表
出现以下 SQL 代码段,共 5 次,平均每次执行需 10 分钟
。。。
FROM PVIEW.VW_xx_MON a
,PVIEW.VW_MID_yy b
,vt_subs c
WHERE a.CUST_Brand_ID=b.SUBS_Brand_Level_Third
AND a.CAL_Month=200908
AND a.SUBS_ID=c.SUBS_ID
。。。
整个脚本需要扫描以下 SQL 14 次,平均每次执行需 3 分钟
PVIEW.VW_xx_MON where CAL_Month=200908
内部资料,注意保密
关联条件 (1)
Select A.a2, B.b2
from A join B
on substring(A.a1 from 1 for 7) = B.b1
应该写为
Select A.a2, B.b2
from (select substring(a1 from 1 for 7) as a1_new
,a2 from A
) A_new
join B
on a1_new = b1
内部资料,注意保密
关联条件 (2)
应该写为
Select A.a2, B.b2
from A join B
on A.a1 = B.b1
内部资料,注意保密
SQL 书写不当可能会引起笛卡儿积
以下面两个 SQL 为例,它们将进行笛卡儿积操作。
例子 1 :
Select
表 Employee 与表 A 进行笛卡儿积
employee.emp_no
, employee.emp_name
From employee A
例子 2 :
表 A 与表 B 进行笛卡儿积
SELECT A.EMP_Name, B.Dept_Name
FROM employee A, Department B
Where a.dept_no = b.dept_no;
表 A 与表 B 进行 Inner Join
内部资料,注意保密
改变查询计划的手段
在表上点右键 选择 Space Summary 菜单 ,查看
Skewfactor 项,大于 20 时需要调整表的 PI
收集统计信息
关联字段上的统计信息
Partition 上的统计信息
Where 条件上的统计信息
Group by 字段上的统计信息
查看某个表的统计信息情况: help stat DBName.TableName
通过 Explain 查看,尚需统计哪些信息?
diagnostic helpstats on for session;
总的来说
尽量应当定时在系统不繁忙的时候做;
执行频率应当和数据变化量成正比;
内部资料,注意保密
优化示例 1 :数据分布 与 JOIN 方法
select
200709, 主要问题:
a.City_ID, 1 、把表 b 进行 Duplicate
a.SUBS_ID,
》统计信息不齐全,认为表 b 经过条件过滤
a.BELONG_DISTRICT
from ( 只有 130 条记录,
select 》实际上有 200 万记录左右
City_ID,
SUBS_ID,
2 、用 Product Join 连接算法
BELONG_DISTRICT
from dwview.vw_a
》表 A 有 1000 万记录
where CAL_Month=200612 》 Duplicate 连接,共进行比较次数:
union 1000 万 ×200 万
select
City_ID,
SUBS_ID,
3 、最优的 Join 方法?
BELONG_DISTRICT
from dwview.vw_b 4 、解决办法:
) a
》对表 b 收集统计相应字段的信息
inner join dwview.vw_c b
on a.subs_id = b.subs_id
》必要的话,固化表 A ,并统计字段
Where CAL_Month = 200709 subs_id
And SUBS_STS_Code not In ('10','11','12','13','20','30','60')
and SUBS_STS_EFCT_Date between 200709 || '01' and '20070930'
group by 1,2,3,4;
内部资料,注意保密
优化示例 2 :数据分布 与 JOIN 方法
11 小时
Select case when b.CUST_Brand_ID is null then '5020' 记录数情况:
when b.CUST_Brand_ID in('2000','5010') then '5020' t: 580 万, b: 9400 万 , c:8, d:8
else b.CUST_Brand_ID end 》都有统计信息
,sum(COALESCE(b.Bas_CHRG_DUR_Unit,0)) as
Thsy_Accum_New_SUBS_CHRG_DUR
主要问题:
, 。。。 1 、连接顺序:
from ( (b Join c) join d ) join t
VT_t t
inner join VT_b b
2 、对表 b 进行 3 次 redistribute
on t.Subs_ID=b.Subs_ID
3 、连接算法: Merge Join
left join
PVIEW.vw_C c 4 、原因: b 表经过汇总而得,虽然知有总记录
on b.Long_Type_Level_SECND= 数,但未知各个 join 字段的情况
c.Long_Type_Level_SECND
left join 解决办法?
PVIEW.vw_D d 》固化 b ,并对 b 表连接字段进行统计
on b.Roam_Type_Level_SECND= 》调整连接顺序?
d.Roam_Type_Level_SECND
group by 1;
内部资料,注意保密
优化示例 3 --固化临时表
脚本: rpt_mart_new_comm_mon0400.pl 固化临时表:
注意命名的唯一性
…. ….
Drop table ttemp.mart_new_comm_mon0400_DUR_1;
Create multiset table ttemp.mart_new_comm_mon0400_DUR_1 as (
……
) with data primary index(subs_id);
内部资料,注意保密
优化示例 4 --强制多表 JOIN 的顺序
select
c.prov_title
,sum(....) AS fee
• JOIN 顺序:
from
PVIEW.VW_STL_GSM_INTER a
9 亿记录 1. a join b:
INNER JOIN
比较次数≈ 9 亿 ×418
pview.vw_CdE_TARRIF_dIST b 418 记录 结果≈ 9 亿条
ON a.OPPER_Home_Area = b.Long_Prefix
2 、 (a join b) join c :
INNER JOIN
比较次数≈ 9 亿 × 32
dwpview.vw_LOC_prov c
32 记录 结果≈ 9 亿条
ON b.prov_code =c.prov_id
WHERE Self_Home_Area IN --- 主叫为本省用户 ≈9 亿 ×418 + 9 亿 ×32 次比较
( select city_Id from ttemp.vt_city_Id = 9 亿 ×450 次比较
12 记录
)
and trim(SETLMT_Area) in --- 结算地为内蒙
(select city_Id from ttemp.vt_city_Id 12 记录
)
and SELF_Telco_Operator_Code = '2'
and PROC_Date between '20070601' and '20070630'
group by 1
内部资料,注意保密
优化示例 4 --强制多表 JOIN 的顺序 (cont.)
select
c.prov_title
,sum(....) AS fee
from SQL 重写
( select * JOIN 顺序:
from ttemp.TB_STL_GSM_INTER06 1. b join c:
where SELF_Telco_Operator_Code = '2'
比较次数≈ 32×418
and PROC_Date between '20070601' and '20070630'
结果 : 418 条
and Self_Home_Area IN --- 主叫为本省用户
( select city_Id from ttemp.vt_city_Id
2 、 a join (b join c) :
) 比较次数≈ 9 亿 × 418
and trim(SETLMT_Area) in --- 结算地为内蒙 结果≈ 9 亿条
(select city_Id from ttemp.vt_city_Id
) ≈9 亿 ×418 次比较
)a
INNER join
( select b1.Long_Prefix, c1.prov_title
FROM pview.vw_CdE_TARRIF_dIST b1
INNER join dwpview.vw_LOC_prov c1
ON b1.prov_code =c1.prov_id
)b
ON a.OPPER_Home_Area = b.Long_Prefix
group by 1
内部资料,注意保密
优化示例 5 --强制多表 JOIN 的顺序
select a.subs_id
,a.Phone_NUM
,***
,sum(coalesce(c.last_arpu,0))last_arpu
,sum(coalesce(d.moths_arpu,0))moths_arpu
除了表 e, 其它表 PI 都是
,sum(coalesce(f.accum_intg,0))CUST_INTG PI:subs_id
FROM vt_a a
subs_ID
left join (
除了表 e ,与其它表的 join 都是
select ***** from *** ) b
基于 subs_id
on a.subs_id=b.subs_id
left join (select *** from *** ) c Join 顺序为:
on a.subs_id=c.subs_id a*b*c*d*e*f
left join (select *** from ***) d
Join e 之前,需要数据重分布
on a.subs_id=d.subs_id
left join (select cust_id,Contact_Person,Contact_Phone Join e 之后, join f 又要重分布
from PVIEW.vw_e PI:cust_id
解决方法:
where efct_date<='20070831' and end_date>'20070831' )e > 把 left join e 放在 f 之后 :
on a.cust_id=e.cust_id
> a*b*c*d*f*e
left join (select subs_id,accum_intg
PI:subs_id > 只需一次的数据重分布
from pview.vw_f_HIS
where efct_date<='20070831'
and end_date>'20070831' )f
on a.subs_id=f.subs_id
内部资料,注意保密
并非所有 SQL 都可进行简单优化
以下 SQL 限定了:
数据的分布方式:只能用 duplicate
JOIN 算法:只能用 product join
无法从 SQL 层面进行简单优化:共 2 万亿次 (” 取长度”,”字符串截取”与”比较” )
16 小时内无法完成
SELECT
A.Msisdn
,A.Opper_Num
,'2'
,COUNT(*) AS Sms_Quan 请修改”业务逻辑”
FROM
PVIEW.VW_NET_GSM_SMS A
INNER JOIN
VT_ORDER_USER B
ON SUBSTRING( A.Opper_Num FROM 1 FOR (CHAR_LENGTH(B.Msisdn)) ) = B.MSISDN
AND B.Serv_Id = 'A01'
WHERE
A.Proc_Date ...
GROUP BY 1,2,3;
表 A : PI(subs_ID) , 30 天共 6 亿记录; 表 B : PI(SUBS_ID), 3 千记录
内部资料,注意保密
JOIN 问题的经验分析
运行速度慢的 SQL ,绝大多数都是 JOIN
例外 1 : INSERT 操作慢,可能是因为目标表为 set 类型,或者 PI 不对
例外 2 :数据读取慢,可能用 like 操作,或者数据本身就很大
JOIN 的问题,主要在于:
1. 数据分布方式不对:把大表进行 duplicate ,或者 redistribute
大表 Redistribute 有可能导致数据分布不均衡
2. JOIN 算法不对:
例如,大表 join 小表,用 merge join 导致大表需要重新 hash 与 sort
例如,大表 join 大表不用 merge join
JOIN 问题的解决办法:
对参与 join 的字段进行统计信息
必要的时候,固化临时表,并统计信息
一般情况下,不需要调整 SQL 的业务逻辑
内部资料,注意保密
系统监控中发现的问题
系统资源在上班高峰时常常被大量耗尽
未利用 PI 字段或 Partition 字段查询大表
执行顺序
避免对大表的 UPDATE 操作
书写习惯
历史数据取法
设计考虑
内部资料,注意保密
条件未加限制
事件明细或中间表中未加条件限制
充分理解中间表内容,优化设计思路
例如:
select subs_id from
PVIEW.vw_mid_subs_info_daily
where cust_type_id in
('41','22','42','43','21','51','44')
group by 1
内部资料,注意保密
执行顺序
导出表先做关联,再做汇总?
更改执行顺序,导出表先做汇总,再做关联,达到相同效果,可避免 IO 操作
例如:
Select *
FROM (
SELECT home_area , subs_id , Bas_Fee_CHRG_NUM , call_type_code , begin_time , proc_date ,
roam_type_code , cfee , lfee , chrg_dur , long_type AS long_type_code , opper_num
FROM pview.vw_a
WHERE proc_date = '20070501'
UNION
SELECT home_area , subs_id , CAST( ( chrg_dur + 59 ) AS INT ) / 60 AS Bas_Fee_CHRG_NUM ,
Comm_Type_Code AS call_type_code , begin_time , proc_date , roam_type_code , cfee , lfee ,
chrg_dur , long_type_code , opper_num
FROM pview.vw_b
WHERE proc_date = '20070501' ) t1
INNER JOIN vt_subs_a t2
ON t1.subs_id = t2.subs_id
GROUP BY 1 , 2 ;
内部资料,注意保密
避免对大表的 UPDATE 操作
目标表数据量大,应尽量避免 UPDATE 操作
UPDATE 操作对性能影响较大,而且效率低
如需对大表 UPDATE ,可考虑用 INSERT+DELETE 操作替代
例如:
UPDATE T1
FROM VT_COLOR_SUBS_tmp AS T1,(SEL
SUBS_ID,MMS_SVC_Type_Cod,SUM(Comm_NUM) AS Comm_NUM FROM
VT_MS_INFO GROUP BY 1,2) AS T2
SET Total_QUAN= T2.Comm_NUM
WHERE T1.SUBS_ID=T2.SUBS_ID AND
T1.MMS_SVC_Type_Cod=T2.MMS_SVC_Type_Cod
Update TB set col1 = ‘A’ where col2 = ‘B’
create multiset table TB1 as TB
Insert into TB1 sel … case when col2 = ‘B’ then ‘A’ else col1 end
Delete from TB where col1 = ‘A’
Insert into TB sel * from TB1
内部资料,注意保密
书写习惯
限制条件中未考虑字段类型
考虑字段类型
例如:
cal_month = '200701'
cal_month = 200701 (Integer)
内部资料,注意保密
历史数据提取方法
历史数据提取方法必须是半闭半开区间,否则历史数据将会有问题
书写仔细
例如:
Where Efct_Date <= '20070701'
and End_Date > '20070701'
内部资料,注意保密
设计优化
设计时应该充分考虑系统性能
合理设计
利用现有中间表
月任务加载时间过长,可考虑拆分成日作业执行
例如:
select
home_area
,subs_id
from PVIEW.vw_XX_DET
where proc_date between '2007'||'0101' and '20070331'
and opper_num like '12593%'
and roam_type_code not in ('2','3','7')
内部资料,注意保密
优化前提
保证数据正确性与一致性
对于后台脚本,优化时还要考虑作业间关系,不能为了优化破坏脚本
的逻辑及依赖关系
内部资料,注意保密
数据分布设计策略
PI & PPI (数据分布不均匀是大忌)
极大影响性能。
选择 PI 的大致原则 :
ACCESS( 访问 )
DISTRIBUTION( 分布 )
VOLATILITY( 可变性 )
即选择那些经常需要引用或用作关联的、能让表数据均匀分布、相对比较稳定
( 经常变化必然导致数据在 AMP 间的迁移 ) 的字段做 PI.
表一定要有 PI, 如果你没有指定 ,Teradata 会按如下原则指定 PI:
1) 有 PK 的话 , 用 PK 字段作为 UPI.
2) 没有 PK 的话 , 有 USI 的话 , 将 USI 的字段做 UPI.
3) 没有 PK, 没有 USI 的话 , 将第一个字段作为 NUPI. 所以 , 尽量自己去指定 PI!
内部资料,注意保密
一般优化策略
尽量利用分区
尽量创造条件使用分区,例如明细数据中的处理日期和统计月份
表与表的关联,尽量通过两个表的 PI 字段进行关联,避免数据的重
分布
若 PI 由多个字段组成,则要将多个字段列全,否则 PI 会不使用
关联条件不可忽略,避免迪卡尔乘积
内部资料,注意保密
DDL 上的优化
DDL 中用 MULTISET ,避免使用 SET ( SET 可用指定 UPI 来实现)
;
日期格式均指定为’ YYYYMMDD’ ;
考虑使用 NO FALLBACK 与 FALLBACK 以及 NO JOURNAL 与
JOURNAL ;
尽量少用 SI ,只是有时在追求性能的情况下可以使用;
索引尽量选择后续 SQL 可以用到的,并尽可能考虑唯一性;
字符字段评估是否该使用 CHAR 类型,而不是 VARCHAR 类型,使用
CASESPECIFIC (大小写敏感);
使用的字段尽可能设置 Not Null ;
代码表中应将代码设置成 UPI ;
Partition 字段一般为日期 (YYYYMMDD) 或年月 (YYYYMM) ;
字段压缩:节省空间和提高速度;
只读视图在创建时增加 Locking Row for ACCESS 选项
内部资料,注意保密
其他优化方法
可变临时表不能提高速度,使用的目的是维护的方便性,缺陷也是显而易见的
:事后没法对中间过程数据进行检查;
内部资料,注意保密
优化心得
没有最好,只有更好;
优化的过程是平衡的过程 - 中庸;
内部资料,注意保密
保密须知:本文件及其书面或其他任何形式的附件乃以保密形式提供,其著作权归属于本公司,仅供阁下内
部使用。未经过本公司的审核、确认及书面授权,阁下不得以任何方式在任何媒体(包括互联网)上公开引
用或在阁下的任何资料中引用本文件及其附件中的任何数据和信息,不得以任何方式将本文件及其附件中的
任何内容提供、披露给其他单位或个人。敬希阁下与我们共同遵守法律。
内部资料,注意保密