You are on page 1of 201

TeraData 基础培训

编写日期: 2010 年 5 月 1 日
Teradata 学习推荐资料:
 TF v800 Read Book1.pdf

 TF v800 Read Book2.pdf

 Teradata SQL.pdf

 ETL Automation Manual V2.5.2(GB).doc

 perl 编程 24 学时教程

 。。。。。

内部资料,注意保密
Agenda
 Teradata Client 安装

 Teradata 架构

 Teradata SQL Assistant & Teradata Administrator

 Teradata 数据库及 ETL 环境

 Perl 脚本开发、测试、 ETL 上线

 Procedure 、 Macro 、 View 、 Tables

 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 架构

 Teradata SQL Assistant & Teradata Administrator

 Teradata 数据库及 ETL 环境

 Perl 脚本开发、测试、 ETL 上线

 Procedure 、 Macro 、 View 、 Tables

 PI 、 SI 、 PPI 机制

 数据重分布及 JOIN 机制

 SQL 函数及开发经验
内部资料,注意保密
Teradata 体系架构 Physical View

内部资料,注意保密
Teradata RDBMS Architecture

Teradata is the software that makes a MPP system appear to


be a single system to users and administrators.
The two major components
of the Teradata RBDMS are BYNET 0 BYNET 1
implemented as virtual
processors (vproc).

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

AMP AMP AMP AMP AMP AMP AMP AMP


The MPL (PDE and BYNET)
connects multiple nodes AMP AMP AMP AMP AMP AMP AMP AMP
together and allows O.S. O.S. O.S. O.S.
Teradata to communicate
between nodes. Node 0 Node 1 Node 2 Node 3

内部资料,注意保密
Teradata Functional Overview

Channel-Attached Network-Attached
System System
Client Client
Applicatio Applicatio
n n

CLI CLI or ODBC


Teradata RDBMS
MTDP
Channe Parsing Parsing LAN
TDP l Engine Engine
MOSI
Message Passing Layer

AMP AMP AMP AMP

内部资料,注意保密
Channel-Attached Client Software Overview

 Client Application -- 客户端应用程序:


 自己开发的应用程序
 Teradata 工具( BTEQ 等)
 CLI ( Call-Level Interface )服务程序 -- 调用接口层
 请求和响应控制
 打包 SQL 请求和解析返回结果
 缓冲分配和初始化
 TDP ( Teradata Director Program ) -- Teradata 指引程序
 多个 PE 间的会话平衡
 确保 RDBMS 的送到 RDBMS 系统或从 RDBMS 系统来的消息路由
 错误通知(应用程序错误, Teradata 重新启动)

内部资料,注意保密
Network-Attached Client Software Overview

 CLI ( Call Level Interface ) -- 调用接口层


 打包 SQL 请求和解释返回结果
 ODBC™ (Open Database Connectivity) Driver
 使用基于开放标准的 ODBC 接口为 Teradata 客户提供应用程序访问
 MTDP ( Micro Teradata Director Program ) -- 微型 Teradata 指引程序
 会话管理的程序库
 MOSI ( Micro Operating System Interface ) -- 微型操作系统接口
 提供操作系统独立性接口的程序库

内部资料,注意保密
The Parsing Engine

The Parsing Engine 分析引擎主要负责:

 管理单独的会话层(可以到 120 个)

 分析和优化 SQL 请求

 将优化的计划发送给 AMP

 ASCII/EBCDIC 之间的转化(如果需
要的话)

 发送响应的结果给请求客户

内部资料,注意保密
Message Passing Layer
Notes:
 AMP 与 PE 之间的信息传送

 广播,点对点和多点通讯

 合并结果集返回给 PE

 让 Teradata 的并行处理成为可能

消息传递层是一个组合:

 并行数据库扩展( PDE )的软件

 BYNET 软件

 BYNET MPP 系统的硬件

内部资料,注意保密
The Access Module Processor

 Notes:
 查找请求行
 锁的管理
 行排序
 列聚合
 Join 处理
 输出转化和格式化
 为客户端建立结果集
 磁盘空间管理
 统计
 专用的协议
 恢复处理

内部资料,注意保密
Disk Arrays

Disk Arrays Notes:


 每个 AMP 能支持的最大磁盘空间
 V2R2――46GB
 V2R3/V2R4――119GB
 每个 AMP 虚拟处理器额可以指派给
一个虚拟存储器
 每个虚拟存储器可以拥有 119 的磁
盘空间

内部资料,注意保密
BYNET (for MPP)

 BYNET 是一个双重容余、双向互联的网络。 BYNET 能够完成:


 多个 SMP 节点之间的通讯(最多 512 个)
Even though there are
 自动平衡信息通讯量的装载
two physical BYNETs to
 发生错误后能够自动重配 provide redundancy and
bandwidth, Teradata and
 完全可用的双重 BYNET 具有较强的容错能力 TCP/IP software only
see a single network.
 当节点增加时带宽可以扩展

内部资料,注意保密
AWS(adminstration Workstation)

内部资料,注意保密
Teradata Parallelism

Notes:
 每个 PE 可以并行处理 120 个会话

 每个会话可以操纵多条请求

 MPL 可以并行处理所有的信息

 每个 AMP 可以并行执行 80 个任务

 所有的 AMP 可以并行地协作处理任何


请求

 每个 AMP 可以并行地执行多条请求

Parallelism is built into Teradata from the ground up!

内部资料,注意保密
Linear Growth and Expandability

Notes:
 Teradata 是一个线性扩展的
RDBMS 。

 系统构成在需求增长时可以线性
扩展。

 线性的可扩展性允许在不减少传
输量的情况下增加工作量

内部资料,注意保密
Teradata Storage Process

Notes:
 PE 发出插入一行的请求

 MPL 确保行到达适当的 AMP

 AMP 将行存储在相关的磁盘中

 每个 AMP 管理一个逻辑或虚拟磁
盘映射到磁盘阵列多个物理磁盘

内部资料,注意保密
Teradata Retrieval Process

Notes:
 PE 发送一个请求读取一行或多行

 MPL 确保相应的 AMP 的可用性

 AMP 以并行访问方式查找并读取所需要的
数据行

 MPL 将读取的数据行返回给 PE

 PE 将结果数据返回到请求的客户端应用程

内部资料,注意保密
Multiple Tables on Multiple AMPs

Notes:
 每个表中的某些行可以在每个
AMP 中找到

 每个 AMP 可以有所有表中的行

 在理想情况下,每个 AMP 将保
存大致相同数量的数据

内部资料,注意保密
Single-Node SMP

Notes:
 一个节点一个或多个共享存储器的处理器组

 应用程序, LAN 网关和通道驱动软件运行在


UNIX 下

 AMP 和 PE 是运行在并行数据库扩展 (PDE) 下


的虚拟处理器

 AMP 通过磁盘矩阵控制器与虚拟磁盘相关联

 Teradata 被称为 PDE 的可信任并行运用


( TPA
Teradata ) a Trusted Parallel Application of PDE.
is called

内部资料,注意保密
Multi-Node MPP System

Notes:
 多个节点可以构造成一个海量并行处理
系统( MPP )。

 用来连接多个节点的物理信息传送层叫
BYNET 。

 Teradata 系统是可以线性扩展的,当数
据库增大时,你可以增加节点。

Teradata is a linearly expandable RDBMS


- as your database grows, additional
nodes may be added.

内部资料,注意保密
Teradata Cliques

 Clique 是一个具有失效保护能力的结点的集合

 Clique 里所有的节点必须能够存取 Clique 里所有 AMP 的虚拟磁盘

 如果一个节点失效,所有的虚拟处理器将移动到 Clique 里其他的节点中

 每个节点能支持 128 个虚拟处理器

 每个 Clique 所能支持的最大虚拟处理器的数量不能超过 128 个

内部资料,注意保密
Fallback Clusters
 FALLBACK 保护集群定义为独立的 AMP 容错单元
 集群中的 FALLBACK 行必须在同一个集群中
 集群中一个 AMP 失效仍然可以访问表中的数据
 在同一集群中同时有两个 AMP 失效,数据库系统停掉

Cluster 0 AMP 1 AMP 2 AMP 3 AMP 4

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

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
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

集群的大小 工作负载增加值 运行的 AMP


每集群有 16 个 AMP 1.06 集群中剩余的 15 个 AMP
每集群有 8 个 AMP 1.14 集群中剩余的 7 个 AMP
每集群有 4 个 AMP 1.33 集群中剩余的 3 个 AMP
每集群有 2 个 AMP 2.00 集群中剩余的 1 个 AMP

注意:任何 AMP 出现不均衡负载,系统都将会受到很大的影响


内部资料,注意保密
Clusters and Cliques
SMP001-4 SMP001-5 SMP002-4 SMP002-5
Clique 160 Disks in Multiple
0 0 4 … 36 1 5 2 6 3 7 39 Disk Arrays for Clique 0
…... …... ....

SMP003-4 SMP003-5 SMP004-4 SMP004-5


Clique 160 Disks in Multiple
1 40 44 41 45 42 46 43 47 Disk Arrays for Clique 1
…... …... …... ...…

SMP005-4 SMP005-5 SMP006-4 SMP006-5


Clique 160 Disks in Multiple
2 80 84 81 85 …... 82 86 …... 83 87 ...… Disk Arrays for Clique 2
…...

SMP007-4 SMP007-5 SMP008-4 SMP008-5


Clique 160 Disks in Multiple
3 120 124 ...… 121 125 …... 122 126 …... 123 127 …... Disk Arrays for Clique 3

Cluster 0 Cluster 1
内部资料,注意保密
Agenda
 Teradata Client 安装

 Teradata 架构

 Teradata SQL Assistant & Teradata Administrator

 Teradata 数据库及 ETL 环境

 Perl 脚本开发、测试、 ETL 上线

 Procedure 、 Macro 、 View 、 Tables

 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

数字加千位逗

显示字段标题
还是名字

NULL 用什么显 最高结果行数


内部资料,注意保密
TeradataSQL Assistant

 <SQL Assistant Menu> Help -> Query Builder

内部资料,注意保密
Teradata Administrator

 启动 Teradata Administrator 后,先指定数据源,然后输入用户名和密码,即


可建立与 Teradata 的连接。

 Teradata Administrator I 的左面以层次型结构的方式形象地描述了 Teradata


的空间结构,最上面是 DBC ,接下来有一些系统用户和系统数据库,以及用户
自创建的用户。系统的数据字典在 DBC 下面,通过右键选择 , 就可显示 DBC 下
所有的表、视图和宏。

 创建、调整、删除、复制用户与数据库,权限的设置,数据库中具体对象的操
作等等,甚至还能通过它来递交 SQL 交易请求都可以通过它完成

 F12 能显示记录操作记录和记录执行的对应的 SQL

内部资料,注意保密
Teradata Administrator

新建库、用户、表、
角色等 赋权功能选项

修改库、用户、
表、角色等
从某个空间
移走空间给
可执行查询申 另外个空间

数据库树形结
构对象列表 记录返回显示

内部资料,注意保密
Teradata Administrator

显示宏和存
储过程 返回表、视图、
宏、存储过程、
触发器等对象
相关信息列表

显示所有对象
显示表和索引
列表

显示该库
或用户下视图

该库和用户下对象
相关的权限管理

记录返回显示
显示该库 / 表下的子 区
库、表的空间情况

内部资料,注意保密
Teradata Administrator

显示该对象(表、
视图)的列信息

浏览数据 显示表的统计信息

表的 返回表或视图
的记录条数
总空间
对象 表空间在各
的权 AMP 分布情况

显示该对象(表、
视图、宏、函数等)
的定义语句

记录返回显
示区

内部资料,注意保密
Agenda
 Teradata Client 安装

 Teradata 架构

 Teradata SQL Assistant & Teradata Administrator

 Teradata 数据库及 ETL 环境

 Perl 脚本开发、测试、 ETL 上线

 Procedure 、 Macro 、 View 、 Tables

 PI 、 SI 、 PPI 机制

 数据重分布及 JOIN 机制

 SQL 函数及开发经验
内部资料,注意保密
数据库环境

内部资料,注意保密
ETL AUTOMATION 服务器端目录架构图
/APP

用来存放作业 (Job) 的作业指令文件 ( 任务脚本 ) 。 在这

个目录下会依照 ETL 系统来建立子目录, 在各系统的子目

录下才是各所属作业所对应的目录。

/APP/$SYS/$JOB/bin

用来存放 JOB 作业的脚本

/bin

用来存放 ETL Automation 系统程序的执行文件。也会放一些

自定义的函数包。

/etc

用来存放 ETL Automation 机制的一些配置文件,如登录文件。

内部资料,注意保密
Perl 应用模板

脚本头注明
脚本内容、
开发人员、修改等

参数、变量

定义函数方法:
通过管道将要执行
的语句注入

主函数

内部资料,注意保密
Agenda
 Teradata Client 安装

 Teradata 架构

 Teradata SQL Assistant & Teradata Administrator

 Teradata 数据库及 ETL 环境

 Perl 脚本开发、测试、 ETL 上线

 Procedure 、 Macro 、 View 、 Tables

 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

Create multiset table tmp_1 as


…;
.IF ERRORCODE <> 0 THEN .QUIT 12;
BT
deltete from a SQL 脚本
;
.IF ERRORCODE <> 0 THEN .QUIT 12;
INSET INTO a select * from tmp_1
;
.IF ERRORCODE <> 0 THEN .QUIT 12;
ET
ENDOFINPUT
内部资料,注意保密
Perl 脚本开发、测试、 ETL 上线

Perl 脚本测试

把脚本 FTP 到服务器 ETL 服务器作业目录下,用 CMD 或是


CRT 工具连到服务器 , 执行语句:

Perl xxxx/xxx0200.pl 20100501.dir;

Perl xxxx/xxx0200.pl 20100501.dir >0501.log;

Nohup perl xxxx/xxx0200.pl 20100501.dir >0501.log &;

内部资料,注意保密
Perl 脚本开发、测试、 ETL 上线
ETL 上线

测试完成并提交相关测试报告文档后,根据项目
组的要求填写上线文档,完成上线

 维护性上线: 要求记录修改的上线历史

 批量上线:如果批量大,不一定保存该次上线历史

内部资料,注意保密
Perl 脚本开发、测试、 ETL 上线
新上线作业:
TST 系统 作业名 TST_JOB_E ETL 服务器: AUTO1
脚本 tst_job_e0200.pl

 在 ETL 服务器 建立 JOB 文件夹

 Mkdir D:\ETL\APP\TST\TST_JOB_E;

 Mkdir D:\ETL\APP\TST\TST_JOB_E\bin;

 把脚本 tst_job_e0200.pl 放到 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 工具都有什么办法?

 Automation 的做法是将触发表中 TST_JOB_A 与其下


游的触发关系记录全部失效。
 UPDATE etl.etl_job_stream SET enable='9' WHERE
ETL_JOB='TST_JOB_A '

 跑完后再 UPDATE 成 ' 1'


内部资料,注意保密
Agenda
 Teradata Client 安装

 Teradata 架构

 Teradata SQL Assistant & Teradata Administrator

 Teradata 数据库及 ETL 环境

 Perl 脚本开发、测试、 ETL 上线

 Procedure 、 Macro 、 View 、 Tables

 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);

假设原有 1286449 条记录 假设原有 1286449 条记录


插入 :152853 条记录 插入 :152853 条记录
耗时: 15 秒 耗时: 1 秒

• 建议: Teradata 中都用 MultiSet, 若真要限定唯一性,可以通过 UPI


或 USI 实现
内部资料,注意保密
Table
 永久表
 临时表
 可变临时表
 在一个会话中,能够被多个查询使用。
 占用 SPOOLSPACE ,在 cache 中保留表的定义, spool 缓冲区中物化, 不使用数据字典
 每个会话可以建立 64 个,可以随时被手动删除,会话结束时自动删除。
 全局临时表
 每个会话最多可以物化 32 个全局临时表。
 空间占用 Temporary Space ,对会话而言,每个实例是本地的。物化表中内容与其他会话不共享。
 会话结束后,物化的表被自动删除。 ( 但基础定义仍然存储在数据字典中 )
 导出表
 只有一个查询要求使用临时表,其他查询都不要求。
 空间占用 SPOOL SPACE ,使用 SELECT 语句在 spool 缓冲区中创建导出表。
 查询结果只使用一次。

内部资料,注意保密
永久表 设计原则:
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)

ON COMMIT PRESERVE ROWS;

CREATE INDEX (empcnt)ON gt_deptsal;

COLLECT STATISTICS ON gt_deptsal INDEX (deptno);

COLLECT STATISTICS ON gt_deptsal COLUMN avgsal;

HELP STATISTICS gt_deptsal;


TEMPORARY
内部资料,注意保密
导出表
 示例:
SELECT *

FROM

SELECT deptno,SUM(sal) AS sal_sum

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;

CREATE multiset TABLE Customer_N CREATE multiset TABLE Trans_N


AS Customer with no data; as Trans with no data;
INSERT INTO Customer_N INSERT INTO Trans_N
SELECT Credit_Limit * 1.20 FROM Customer ; SELECT * FROM Trans WHERE Trans_Date > 981231;
DROP TABLE Customer ; DROP TABLE Trans;
RENAME TABLE Customer_N TO Customer ; RENAME TABLE Trans_N TO Trans;

 先建立空表,通过 insert / select 方式插入数据--这是非常快的操作!


 先备份,然后做变更操作,更加安全!

内部资料,注意保密
Insert/select : the fast path
INSERT INTO New_Table
Parsing Engine Parsing Engine
SELECT * FROM Old_Table ;

Message Passing Layer

SQL SQL SQL SQL


INSERT/SELECT INSERT/SELECT INSERT/SELECT INSERT/SELECT

Block Block Block Block

INSERT / SELECT achieves highest performance if:


• Target table is empty, AND
• Source and target tables have same Primary Index.
Advantages of using optimized INSERT / SELECT:
• One WRITE to the Transient Journal – instantaneous rollback for aborted
Insert/Select statements.
• Data copied and written to disk a block at a time.
• No data redistribution over the BYNET.
内部资料,注意保密
Multi-statement insert/select

INSERT INTO Summary_Table


Region_1 Region_2 Region_N
SELECT store, region,
SUM(sales),
COUNT(sale_item)
FROM Region_1
GROUP BY 1, 2
SPOOL
; INSERT INTO Summary_Table
SELECT store, region,
SUM(sales), Optimized INSERT/SELECT
COUNT(sale_item)
FROM Region_2
GROUP BY 1, 2
... Empty Target Table
; INSERT INTO Summary_Table
SELECT store, region,
SUM(sales),
COUNT(sale_item)
FROM Region_N
GROUP BY 1, 2
;

内部资料,注意保密
Delete all : the fast path
DELETE FROM Old_Table ALL; Parsing Engine Parsing Engine

Message Passing Layer

SQL SQL SQL SQL


DELETE ALL DELETE ALL DELETE ALL DELETE ALL

Block Free Block Free Block Free Block Free

DELETE achieves its highest performance with use of the ALL option.

High performance is achievable because of:


• Not using the Transient Journal.
• Doing DELETEs at the cylinder index / master index level.

内部资料,注意保密
Agenda
 Teradata Client 安装

 Teradata 架构

 Teradata SQL Assistant & Teradata Administrator

 Teradata 数据库及 ETL 环境

 Perl 脚本开发、测试、 ETL 上线

 Procedure 、 Macro 、 View 、 Tables

 PI 、 SI 、 PPI 机制

 数据重分布及 JOIN 机制

 SQL 函数及开发经验
内部资料,注意保密
Storing Rows

 每个表的行被分配到所有的 AMP 中
 每个 AMP 负责每个表中的行子集
 理想的情况下,每个表将被均匀地分配到所有的 AMP 中去
 均匀分配的表将使系统工作量得以均匀的分配

 The uniformity of distribution of the rows of a table depends on the


choice of the Primary Index.
内部资料,注意保密
Creating a Primary Index

 创建表的时候创建主索引
 主索引可以由 1 列或多到 64 列组合而成。
 具有同一 PI 值的所有数据行存放在同一个 AMP 中。
 PI 的选择非常重要,它会影响到数据行的分布,进而影响到性能。

内部资料,注意保密
Primary Index Values

 特定行的主索引的值决定了它的 AMP 分配。


 这里使用到 Hashing Algorithm (哈希算法)。
PE PI Value

Row assignment Hashing


Row access Algorithm

 通过主索引值访问行: AMP AMP AMP


 总是一种单个 AMP 的操作
 访问行最有效的方法
 其它的访问方法:
 次索引访问
 全表扫描

内部资料,注意保密
Accessing Via a Unique Primary Index

A UPI access is a one-AMP operation which may access at most a single row.

CREATE TABLE sample_1


(col_a INTEGER
,col_b INTEGER
,col_c INTEGER)
UNIQUE PRIMARY INDEX (col_b); PE UPI = 345

SELECT col_a Hashing


,col_b Algorithm
,col_c
FROM sample_1
WHERE col_b = 345; AMP AMP AMP

col_a col_b col_c col_a col_b col_c col_a col_b col_c


123 345 567
234 456 678

内部资料,注意保密
Accessing Via a Non-Unique Primary Index

内部资料,注意保密
Primary Keys and Primary Indexes
 索引在概念上区别于键:
 主键是关系模型的惯例,允许每一行被唯一确定。
 主索引是 Teradata 的惯例,确定行怎样被存储和访问。
 很大一部分的表使用相同的列作为主键和主索引。
 在一个设计较好的数据库中,一些表也使用与主键不同的主索引。

Primary Key Primary Index


数据模型的逻辑概念 访问和存储的物理机制

Teradata 不需要指定 每个表必须有一个


没有列数量的限制 16 列限制 (V2R4.1); 64 列限制 (V2R5 …)
数据模型中定义 在建表时被定义
(建表时可选择)

必须唯一 可以是唯一或非唯一
确定每一行 用来放置或定位 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 中的分配是均衡的。
• 确保并行操作最高的效率。

AMP AMP 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 中
• 导致了行的不一致或倾斜分布 .

AMP AMP AMP 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 选择。
• 唯一性的程度对其效率很重要。

AMP AMP AMP AMP

o_# c_# o_dt o_# c_# o_dt


o_st o_st
7402 3 4/16 C 7103 1 4/10 O
7202 2 4/09 C 7324 3 4/13 O
7225 2 4/15 C 7325 2 4/13 O
7415 1 4/13 C
7188 1 4/13 C
7384 1 4/12 C
内部资料,注意保密
Hashing Primary Index Values
SQL with primary index values PARSER PI value = 38
and data.
Hashing Hashing
For example: Algorithm Algorithm
Assume PI value is 38

Row Hash PI values 1177 7C3C


DSW and data DSW(Destination Selection Wor

Message Passing Layer (Hash Maps) Hash Maps

AMP 0 AMP 1 ... AMP x ... AMP n - 1 AMP n AMP #

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.

Bucket# 1177 contains the


AMP number that has this
x 'FFFFFFFF' hash value – effectively the
AMP with this row.
内部资料,注意保密
Hashing Down to the AMPs
Index value(s)

hashing algorithm
{ 哈希算法设计是用来保证所有的唯一值在 AMP 中均匀分配。

不同的哈希算法应用于不同的国际字符集。

Row Hash
DSW or
Hash Bucket #
{ Row Hash 是索引值通过哈希算法得出来的一个 32 位的结果

DSW 是 Row Hash 的前 16 位 , 用来确定哈希图的入口

Hash Map
{ 哈希图 (Hash Map) 在每个系统中是唯一配置的。

哈希图是关联 DSW(Hash Bucket #) 指向特定 AMP 的一个二维表。

AMP #
{ 两个有相同数目 AMP 的系统有相同的哈希图 .

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

32 bit Row Hash


Destination Selection Word Remaining 16 bits
0110 1001 0001 1011 0001 0100 1010 1110

6 9 1 B

内部资料,注意保密
The Hash Map

7202 Hashing Algorithm 691B 14AE

32 bit Row Hash


Destination Selection Word Remaining 16 bits
0110 1001 0001 1011 0001 0100 1010 1110

(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

A row hash is not adequate to uniquely identify a row.

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

Row ID Row Data


Row Hash Unique ID Emp_No Last_Name First_Name

Rows 在 Row-ID 的 3B11 5032 0000 0001 1018 Reynolds Jane


3B11 5032 0000 0002 1020 Davidson Evan
序列中被逻辑地维护 3B11 5032 0000 0003 1031 Green Jason
3B11 5033 0000 0001 1014 Jacobs Paul
3B11 5034 0000 0001 1012 Chevas Jose
3B11 5034 0000 0002 1021 Carnet Jean
: : : : :

内部资料,注意保密
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

'Smith' Hash Algorithm 0016 5557 Hash Map 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

Add a row for 'Dan Jones' - (Hash Synonym) 1058


00169829
5557 0000
00000001
0002 Adams
Smith Sam
Fred
0016 5557 0000 0003 Jones Dan

'Smith' Hash Algorithm 0016 5557 Hash Map AMP #3

Add a row for 'Dan Jones' - (Hash Synonym)

'Jones' Hash Algorithm 0016 5557 Hash Map AMP #3

内部资料,注意保密
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

START WITH: APPLY TO: FIND:


Table Id Master
Row Hash Cylinder #
Index
Table Id
Row Hash Cylinder
Cylinder # Index Data Block Address

Row Hash Data


PI Value Data Row
Block
内部资料,注意保密
Secondary Indexes

There are 3 general ways to access a table:


Primary Index access (one AMP access)
Secondary Index access (two or all AMP access)
Full Table Scan (all AMP access)

 次索引是访问表里的行的一种可替换的方法。
 一个表可以有 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

CREATE UNIQUE INDEX CREATE INDEX


(Employee_Number) ON (Last_Name) ON Employee;
Employee;
Notes:
 次索引导致内部子表的建立
 删除索引的同时子表也被删除

内部资料,注意保密
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;

Table ID Row Hash Unique Val


778
PE 100 7

Message Passing Layer


Customer USI Value = 56
Table ID = 100
Hashing AMP 1 AMP 2 AMP 3 AMP 4
Algorithm

Base Table Base Table Base Table Base Table


Table ID Row Hash USI Value
RowID Cust Name Phone RowID Cust Name Phone RowID Cust Name Phone RowID Cust Name Phone
100 602 56 USI NUPI USI NUPI USI NUPI USI 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
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

内部资料,注意保密
Non-Unique Secondary Index (NUSI) Access
Message Passing Layer
Create NUSI
CREATE INDEX (Name) ON AMP 1 AMP 2 AMP 3 AMP 4
Customer;

NUSI Subtable NUSI Subtable NUSI Subtable NUSI Subtable


Access via NUSI RowID Name RowID
RowID Name RowID
RowID Name RowID RowID Name RowID
432, 3 Smith 884, 1
432, 8 Smith 640, 1 432, 1 Smith 147, 1 155, 1 Marsh 915, 9
SELECT * 448, 1 White 107, 1
567, 2 Adams 471, 1
448, 4 Black 822, 1 396, 1 Peters 778, 3
FROM Customer 567, 3 Adams 638, 1 567, 6 Jones 338, 1 432, 5 Smith 778, 7
717, 2
WHERE Name = 'Adams'; 656, 1 Rice 536, 5
852, 1 Brown 555, 6
770, 1 Young 147, 2 567, 1 Jones 639, 1

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

Examples of Full Table Scans:


SELECT * FROM Customer WHERE Cust_Phone LIKE '524-_ _ _ _';

SELECT * FROM Customer WHERE Cust_Name = 'Davis';

SELECT * FROM Customer WHERE Cust_ID > 1000;

内部资料,注意保密
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

RH O_# O_Date RH O_# O_Date RH O_# O_Date RH O_# O_Date


4 AMPs with
'14' 1001 06/01 '06' 1009 06/01 '04' 1008 06/01 '08' 1006 06/01
Orders Table defined '35' 1007 06/01 '26' 1002 06/01 '24' 1004 06/01 '20' 1005 06/01
with PPI on O_Date. '39' 1011 06/01  '36' 1012 06/01 '32' 1003 06/01 '43' 1010 06/01

'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 架构

 Teradata SQL Assistant & Teradata Administrator

 Teradata 数据库及 ETL 环境

 Perl 脚本开发、测试、 ETL 上线

 Procedure 、 Macro 、 View 、 Tables

 PI 、 SI 、 PPI 机制

 数据重分布及 JOIN 机制

 SQL 函数及开发经验
内部资料,注意保密
Join 之前的重分布

Join 的列都是两个表的 PI 不需要数据重分布 .


SELECT ...
FROM Table1 T1 AMP1 AMP2
INNER JOIN Table2 T2
ON T1.A = T2.A; Subs_id B C Subs_id B C

PI PI

100 214 433 200 214 433


话单表

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

Subs_id Cust_id Subs_id Cust_id


Spool 空间 PI PI
100 214 100 408
200 214

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 个市

 意味着只有 13 个 AMP 有数据,其它 AMP 根本不能被用到

 同时,由于 A 市的用户数较大,意味这 A 市所在的 AMP 上数据量很大,造成了


13 个 AMP 运行过程中的不均匀。

内部资料,注意保密
Join 之前的复制小表到所有的 AMP
AMP1 AMP2
City_id City_name City_id
地市代码表 City_name
PI
PI
100 A市
200 A市

City_id City_name City_id


Spool 空间 City_name

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 里面的记录进行排序 .

对于 Join 列的 Hash 值相同的记录进行比较 .


与 Product Join 相比,比较次数大大降低 .

内部资料,注意保密
关联策略 Nested Joins

• This is a special join case.


• This is the only join that doesn't always use all of the AMPs.
• It is the most efficient in terms of system resources.
• It is the best choice for OLTP applications.
• To choose a Nested Join, the Optimizer must have:
– An equality value for a unique index (UPI or USI) on Table1.
– A join on a column of that single row to any index on Table2.
• The system retrieves the single row from Table1.
• It hashes the join column value to access matching Table2 row(s).

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

优化器技术有效的将小表放在 Cache 内存中,并且与未排序的大表进行关联 .


Row Hash Join 的处理流程 : 适用情况:
• 找到小表 . 大表非 PI 字段对中等小的表
例如 700 万 × 1 万
• 重分布小表或者复制小表到各个 AMP 的内存中 .
• 将小表在 Cache 内存中按照 join 字段的 row hash 顺序排序 .
• 将记录放在内存中 .
• 用大表的 join 字段的 row hash 在内存中进行折半查找 .

这种 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 语句

 数据分布的变化( Redistribute , Duplicate )


 ... which is redistributed by hash code to all AMPs

 Redistributing data (in SPOOL) in preparation for a join.
 ... which is duplicated on all AMPs …
 Duplicating data (in SPOOL) from the smaller table in
preparation for a join.

内部资料,注意保密
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;

EXPLAIN output on following page.


内部资料,注意保密
Product Join (cont.)

EXPLAIN EXPLANATION V2R6.1


EXPLAIN
-----------------------------------------------------------------------------------------------------------------------------------------------------
1) First, we lock a distinct TFACT."pseudo table" for read on a RowHash to prevent global deadlock for
TFACT.E.
2) Next, we lock a distinct TFACT."pseudo table" for read on a RowHash to prevent global deadlock for
TFACT.D.
3) We lock TFACT.E for read, and we lock TFACT.D for read.
4) We do an all-AMPs RETRIEVE step from TFACT.D by way of an all-rows scan with no residual
conditions into Spool 2 (all_amps), which is duplicated on all AMPs. The size of Spool 2 is estimated
with high confidence to be 11,224 rows. The estimated time for this step is 0.03 seconds.
5) We do an all-AMPs JOIN step from Spool 2 (Last Use) by way of an all-rows scan, which is joined to
TFACT.E by way of an all-rows scan with no residual conditions. Spool 2 and TFACT.E are joined
using a product join, with a join condition of ("(TFACT.E.Dept_Number = Dept_Number) OR
(TFACT.E.Employee_Number = Dept_Mgr_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. The result spool file will not be cached in memory. The size of
Spool 1 is estimated with no confidence to be 973,873 rows. The estimated time for this step is 24.34
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 24.38 seconds.

内部资料,注意保密
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 . . . ;

Join Plan 1 Join Plan 2


Table_A Table_B Table_C Table_D Table_A Table_B Table_C Table_D

SPOOL SPOOL SPOOL SPOOL SPOOL SPOOL SPOOL SPOOL


FILE FILE FILE FILE FILE FILE FILE FILE

SPOOL SPOOL SPOOL


FILE FILE FILE

SPOOL
FILE

RESULT 内部资料,注意保密 RESULT


Agenda
 Teradata Client 安装

 Teradata 架构

 Teradata SQL Assistant & Teradata Administrator

 Teradata 数据库及 ETL 环境

 Perl 脚本开发、测试、 ETL 上线

 Procedure 、 Macro 、 View 、 Tables

 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 '1' WHERE'Sc' (CS)='sc';

 SELECT '1' WHERE('Sc'(UPPERCASE))(CASESPECIFIC)='sc';

 SELECT '1' WHERE 'Sc'(CASESPECIFIC)='sc';

 SELECT '1' WHERE 'Sc'(NOT CASESPECIFIC)='sc';

 SELECT UPPER('sc');

 SELECT LOWER('Sc');

 SELECT 'Sc'(UPPERCASE);

内部资料,注意保密
Teradata / Oracle 常用语法比较
Oracle Teradata

nvl(f1,f2,…) coalesce(f1,f2…)

case when AA=V1 then R1

when AA=V2 then R2


decode(AA,V1,R1,V2,R2)
else NULL

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 函数
语法 意义

TRIM (<expression>) 去除字符数据中前后端的空格或者二进制数据中前后头的零

TRIM (BOTH FROM <expression>) 同上

TRIM (TRAILING FROM <expression>) 去除后端的空格或二进制零

TRIM (LEADING FROM <expression>) 去除前端的空格或二进制零

SQL: 输出:

SELECT TRIM(' abc '); ' abc'

SELECT TRIM (TRAILING FROM ' abc ') ' abc'

SELECT TRIM (LEADING FROM ' abc ') ' abc ‘

Teradata 没 replace 函数

内部资料,注意保密
SQL 变量
 SELECT DATABASE; 显示当前数据库

 DBC

 SELECT USER; 显示当前 Session 登陆的用户名

 DBC

 SELECT DATE, CURRENT_DATE ; 显示当前日期

 2010-05-21 , 2010-05-21

 定义格式 : SELECT CAST(DATE AS DATE FORMAT 'YYYYMMDD')

 SELECT TIME, CURRENT_TIMESTAMP(0); 显示当前时间

 08:43:17, 2007-08-06 2010-05-21 08:43:54+00:00

 转换 : SELECT CAST(CURRENT_TIMESTAMP(0) AS CHAR(19));

 2010-05-21 08:44:10

 SELECT CAST(CURRENT_TIMESTAMP(0) AS TIMESTAMP(0) FORMAT 'YYYY-MM-


DDBHH:MI:SS')

内部资料,注意保密
日期 (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

a,b,0,1,null a,b,c,d,e a,b,c,d,null

SQL results SQL results


select col1 from T1 a, b select col1 from T1 0, 1
where col1 in where col1 not in
(select col2 from T2) (select col2 from T2)
select col1 from T1 a, b select col1 from T1 No
where col1 in where col1 not in results
(select col3 from T3) (select col3 from T3)
select col1 from T1 a, b select col1 from T1 0, 1 ,
where exists where not exists null
(select * from T2 (select * from T2
where T2.col2 = T1.col1) where T2.col2 = T1.col1)
select col1 from T1 a, b select col1 from T1 0, 1 ,
where exists where not exists null
(select * from T3 (select * from T3
where T3.col3 = T1.col1) where T3.col3 = T1.col1)

内部资料,注意保密
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

,RANK() OVER (PARTITION BY sales_region ORDER BY sales_amount DESC) AS rank_sales

FROM sales_table

QUALIFY rank_sales= 1;

sales_person sales_region sales_amount rank_sales

Garabaldi East 100 1


Baker East 99 2
Fine East 89 3
Adams East 75 4
Edwards West 100 1
Connors West 99 2
Davis West 99 2
内部资料,注意保密
Rank & Row_Number()

INSERT INTO wt_k(


INSERT INTO wt_k(
Currency_Cd
,Fx_Mid_Price) Currency_Cd
SELEC TRIM(Currency_Cd),CAST(Fx_Mid_Price/Unit AS ,Fx_Mid_Price)
DECIMAL(18,8))
FROM $PDATADB.T99_EXCHANGE_RATE_PARAM_H SELECT TRIM(Currency_Cd)
WHER Record_Stat_Cd='0'
,CAST(Fx_Mid_Price/Unit AS
AND Effective_Dt<=CAST('$TX_DATE' AS DATE DECIMAL(18,8))
FORMAT 'YYYYMMDD')-1
AND (TRIM(Currency_Cd) ,Effective_Dt) IN FROM
(SELECT TRIM(Currency_Cd) AS Currency_Cd $PDATADB.T99_EXCHANGE_RATE_PARAM_H
,MAX(Effective_Dt) AS Effective_Dt
WHERE Record_Stat_Cd='0'
FROM $PDATADB.T99_EXCHANGE_RATE_PARAM_H
WHERE Record_Stat_Cd='0' AND Effective_Dt<=CAST('$TX_DATE' AS DATE
AND Effective_Dt<=CAST('$TX_DATE' AS DATE FORMAT 'YYYYMMDD')
FORMAT 'YYYYMMDD')-1
QUALIFY ROW_NUMBER() OVER(PARTITION BY
GROUP BY 1)
Currency_Cd ORDER BY Effective_Dt
GROUP BY 1
DESC,Posted_Price_Tm DESC)=1;
QUALIFY RANK(Posted_Price_Tm)=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

PI : 9 字段-》 2 字段: City_ID ,Channel_ID 3 、值访问+连接访问


调整 PI 后,在右边的 SQL 中, PI 是否起作用? Select *
From DWPDATA.TB_XXX_M A
, VT_×××_INFO B
WHERE A. Channel_ID = B. Channel_ID
AND A. City_ID = B. City_ID
AND A.CAL_MONTH = 200707
AND A. Consume_Level_Cod=B. Consume_Level_Cod

内部资料,注意保密
PPI 的使用
 PPI ( Partition Primary Index ,分区索引),把具有相同分区值的数据聚簇存放在一起;
类似于 SQL Server 的聚簇索引( Cluster Index ), Oracle 的聚簇表( Cluster Table )。

 利用 PPI ,可以快速插入 / 访问同一个 Partition (分区)的数据。

 用表分区字段作过滤条件
 直接比较 = > <=

 不用分区字段作运算

 大大加快速度

CREATE MULTISET TABLE qdata.TB_A Select *


From qdata.TB_A
( Where tx_date = ‘20070701’;
TX_DATE DATE FORMAT 'YYYYMMDD' TITLE ' 数据日期 ' NOT NULL,
KPI_CODE INTEGER TITLE ' 指标代码 ' NOT NULL, 或
。。。。 Where tx_date between ‘20070701’
) and ‘20070731’;
PRIMARY INDEX ( KPI_CODE )
PARTITION BY RANGE_N(TX_DATE

BETWEEN CAST(('20030101') AS DATE FORMAT 'YYYYMMDD') Where tx_date > ‘20070701’;
AND CAST(('20191231') AS DATE FORMAT 'YYYYMMDD') 但
EACH INTERVAL '1' DAY , Where tx_date like ‘200707%’;
NO RANGE OR UNKNOWN
不起作用
);

内部资料,注意保密
PPI 的使用( cont. )

 Partition 上不要使用表达式,否则 Partition 不能被正确使用。

T1. tx_date/100=CAST('20070917'AS DATE FORMAT 'YYYYMMDD')/100

Substring(T1. tx_date from 1 for 6) ='200709’

 应该修改为
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) 等操作

 这样,可以减少参与连接操作的数据集大小,从而提高效率

 好的查询引擎,可以自动优化;但有些复杂 SQL ,查询引擎优化得并不好。

 注意:系统的 SQL 优化,只是避免最差的,选择相对优的,未必能够得到最好的优化


结果。
SELECT A.TX_DATE, A.KPI_CODE
SELECT A.TX_DATE, A.KPI_CODE
,B.SRC_NAME,A.KPI_VALUE
,coalesce(B.SRC_NAME, ‘no name’)
FROM (
,A.KPI_VALUE
select *
FROM from qdata.tb_a
qdata.tb_a A
rewrite where TX_DATE = '20070701'
LEFT JOIN AND KPI_CODE = 65
qdata.tb_b B )A
ON A.KPI_CODE = B.KPI_CODE LEFT JOIN (
SELECT *
WHERE A. TX_DATE = '20070701' FROM qdata.tb_b
AND A.KPI_CODE = 65 where KPI_CODE = 65
AND B.N_TYPE = ‘M’ and N_TYPE = ‘M’
)B
ON A.KPI_CODE = B.KPI_CODE

内部资料,注意保密
用 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

select subs_id select DISTINCT


,acct_id subs_id
from PVIEW. VW_FIN_ACCT_SUBS_HIS ,acct_id
where efct_date <= '20070701' from PVIEW. VW_FIN_ACCT_SUBS_HIS
and end_date > '20070701' where efct_date <= '20070701'
group by 1,2 and end_date > '20070701'

内部资料,注意保密
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

 提取公共 SQL ,形成临时表,较少扫描 (IO) 次数。


 该脚本,经过优化之后,从 50 分钟缩减至 10 分钟

内部资料,注意保密
关联条件 (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 TRIM(A.a1 ) = TRIM(B.b1)

应该写为
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);

Collect stat on ttemp.mart_new_comm_mon0400_DUR_1 column subs_id;

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
, 。。。
from
VTNEW_SUBS_THISYEAR t
inner join ttemp.mart_new_comm_mon0400_DUR_1 b
on t.Subs_ID=b.Subs_ID
left join
….
group by 1;
Drop table ttemp.mart_new_comm_mon0400_DUR_1; 并非所有临时表都需要固化 !!

内部资料,注意保密
优化示例 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 操作
 书写习惯
 历史数据取法
 设计考虑

内部资料,注意保密
条件未加限制
事件明细或中间表中未加条件限制

充分利用大表中的 Partition ,避免进行全表扫描,减少 IO

充分理解中间表内容,优化设计思路

例如:
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')

内部资料,注意保密
优化前提

 保证数据正确性与一致性

 对于后台脚本,优化时还要考虑作业间关系,不能为了优化破坏脚本
的逻辑及依赖关系

 所有的优化不能脱离 DDL 及数据库本身的机制

内部资料,注意保密
数据分布设计策略
 PI & PPI (数据分布不均匀是大忌)

在 Teradata 中 ,PI 的选择十分重要 , 选取不正确,则有如下的影响:


 占用更大数据空间;

 极大影响性能。

选择 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 会不使用

 关联条件不可忽略,避免迪卡尔乘积

 在 SQL 中列全所需要的所有字段,避免 select * from TableName


,减少 SPOOL 空间开销 ;

内部资料,注意保密
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 选项
内部资料,注意保密
其他优化方法

 定期用 COLLECT STATISTICS 对表进行统计信息收集;

 必要时使用临时表 , 简化 JOIN 语句的复杂度,便于人为控制;

 INSERT INTO A SELECT * FROM B; (若 A,B 主索引一致 ,A 为空表 , 插入


数据极快);

 可变临时表不能提高速度,使用的目的是维护的方便性,缺陷也是显而易见的
:事后没法对中间过程数据进行检查;

 表之间的字段类型定义应保持一致,特别注意 JOIN 条件中的字段;

 对于百万级以上的表,若 UPDATE 的比例超过 5-10% ,尽可能采取其它方法


处理;

 尽可能多使用 EXPLAIN ,查询数据库执行计划

内部资料,注意保密
优化心得

 了解数据库原理及 SQL 解析、执行步骤,充分利用数据库本身的特性;

 没有最好,只有更好;

 优化的过程是平衡的过程 - 中庸;

 优化前后的 SQL 要在相同数据库环境下进行比较,持续关注优化结果;

 灵活运用 SQL 技巧,多实践 - 实践出真知。

内部资料,注意保密
保密须知:本文件及其书面或其他任何形式的附件乃以保密形式提供,其著作权归属于本公司,仅供阁下内
部使用。未经过本公司的审核、确认及书面授权,阁下不得以任何方式在任何媒体(包括互联网)上公开引
用或在阁下的任何资料中引用本文件及其附件中的任何数据和信息,不得以任何方式将本文件及其附件中的
任何内容提供、披露给其他单位或个人。敬希阁下与我们共同遵守法律。

内部资料,注意保密

You might also like