pnp什么意思:db2性能优化以及dpf

来源:百度文库 编辑:中财网 时间:2024/04/29 17:26:33
db2 分析函数的一篇文章
===========================================================
--OLAP:DB2® Universal Database 中引入的在线分析处理(OLAP)函数,这些函数扩展了关系模型、使关系模型能够理解行集合内的排序方式(ordering)。
排列函数 第一类引入到 DB2 中的 OLAP 函数是 排列(ranking)函数,它们是在 DB2 Version 6 中引入的。这些排列函数提供了定义一个集合(使用 PARTITION 子句),然后根据某种排序方式对这个集合内的元素进行排列的能力。例如,假设我们有一个雇员表,现在要对每个部门内的雇员薪水进行排列。要实现这一点,我们需要一个函数调用,这个函数调用可以完成以下工作:
将分区(集合)定义为各个部门,将集合内的排序方式定义为按薪水排序。 按照惯例,我们一般会将薪水高的排在前面,所以我们将指定一个对薪水的降序排序方式。下面的例子展示了这个查询的查询和输出。
select empnum, dept, salary, rank() over (partition by dept order by salary desc nulls last) as rank, dense_rank() over (partition by dept order by salary desc nulls last)as denserank, row_number() over (partition by dept order by salary desc nulls last)as rownumber from emptab;
EMPNUM DEPT SALARY RANK DENSERANK ROWNUMBER
------ ---- ------ ---- --------- ---------
6 1 78000 1 1 1
2 1 75000 2 2 2
7 1 75000 2 2 3
11 1 53000 4 3 4
5 1 52000 5 4 5
1 1 50000 6 5 6
--------------------------------------------------
9 2 51000 1 1 1
4 2 - 2 2 2
注意,rank 函数本身没有参数。这是因为 rank 函数不对任何参数执行任何计算。相反,rank 函数只是着眼于行集合--以及每一行在集合中的位置--正如排序方式所定义的那样。那么,我们如何为这个函数定义集合和排序方式呢?两者都是用 OVER 子句定义的。在这个例子中,因为我们要在每个部门内进行排列,因此我们通过按部门划分分区来定义集合。这样做的效果是可以确保只有那些在 dept 列具有相等值的行才参与排列。对排列函数的而言, 分区(partition) 和 集合(set)这两个术语是等价的。在 PARTITION 子句后面,我们有一个 ORDER BY 子句,这个子句定义了分区内的排序方式。在这里,我们想将高薪排在前面,因此我们将排序方式定义为降序。除了指定降序以外,我们还指定 NULLS LAST。在 SQL 中,空值排在前面,意即空值显得要大于所有其他非空的值。这就给排列带来了问题,因为我们可能并不想将为空的薪水排在前面。因此,我们使用 NULLS LAST 子句来更改默认的排序方式,这样就可以将空值排在后面了。(注意,NULLS LAST 子句是在 DB2 V7 中引入的;不过,在 V6 中使用一个 CASE 表达式来强加排序方式也是可以的。) 现在,让我们看一下输出。前 6 行都是 Department 1 的雇员,每一行都被赋予一个按薪水降序排列所得的名次。注意,在 Department 1 中,有两个雇员的薪水都是 75000,这两行都被赋予第二的名次。这是因为 rank 函数提供了一种 “奥林匹克式”的排列方式,在这种方式中,两个相等的值得到相等的名次。因为有两行“结在一起,同获第二”,所以就没有排在第 3 的行。相反,接下来的一行排在第 4,因为根据排序方式,有 3 行严格地排在这一行之前。 对于 Department 2,注意其中有一个行具有为空的薪水。因为我们指定了 NULLS LAST,所以这一行被排在非空行的后面。如果我们没有指定 NULLS LAST 的话,Department 2 中两行的排列顺序就要倒过来了。 到现在,您可能会问自己,在上面的例子中,其他两个输出列 denserank 和 rownumber 是什么呢?DB2 实际上有三个不同的排列函数。首先是 rank 函数,它提供了奥林匹克式的排列方式,这在前面已经描述过了。其他两个函数分别是 dense_rank和 row_number。Dense_rank 很像 rank,在这个函数中,“结”中的行排名是相等的。这两个函数惟一的不同之处在于对跟在结后面的值的处理方式,在 Dense_rank函数中排名是按 1 递增的(而不是像 rank 函数那样按结中行的数量来递增)。因而,这里不会出现排名有间隔的现象(因此函数名中才用了“dense”)。虽然 Employee 11 的薪水在 rank 函数中获得的名次是第 4,但是 denserank 函数返回的值是 3。 最后一列给出 row_number 函数的输出。Row_number 也执行一次排列,但是当碰到有结的情况时,结中的行要进行任意的(也就是说,不是确定的)排序。这在对有重复值的数据进行分析时很有用。row_number 函数一个有趣的方面是它是惟一不要求提供排序方式的排列函数。如果在没有指定排序方式的情况下调用 row_number 函数,则所有的行都将被当作结中的行来对待,因而这些行是任意排序的。这对于在输出中给行排序来说很有用。
在 DB2 Version 7 中还引入了许多其他的 OLAP 函数。在引入这些函数之前,DB2 支持两类基本的函数,分别是 标量(scalar)函数和 聚集(aggregate) 函数。标量函数是那些对单个行中的值进行操作、并在每一行返回一个结果的函数。arithmetic 和 string 函数就是标量函数的例子。例如,下面的查询使用了 DIGITS 标量函数来格式化 salary 字段。
该函数对每一行执行结果计算,并且该计算只使用当前行中的 salary 值。
select empnum, salary, digits(salary) as digits from emptab where dept = 1;
EMPNUM SALARY DIGITS
----------- ----------- ----------
1 50000 0000050000
2 75000 0000075000
5 52000 0000052000
聚集函数(也叫 列 或 集合 函数)的行为有所不同。聚集函数对一组行进行操作,并在输出中将这些行聚集(或者合并)到单个的行中。聚集函数的一个例子是 sum 函数,这个函数计算一组值的和,并将这个和放入一个结果行中。例如,下面的查询计算每个部门中所有雇员薪水的总和。GROUP BY 子句用于表明要聚集的集合(或分区)是各个部门中所有行的集合。对于每个部门都返回一行,给出该部门中所有薪水的总和。
select dept, sum(salary) as sum from emptab group by dept;
DEPT SUM
----------- -----------
1 383000
2 51000
3 209000
- 84000
在 DB2 V7 中引入的 OLAP 函数引入了一类新的函数,我们称之为 标量-聚集(scalar-aggregate) 函数。这些函数像标量函数,因为它们也是在每一行返回单个的值,但是它们也像聚集函数,因为它们要对一个集合中多个行中的值执行计算,以计算出结果。下面的标量-聚集函数执行的是与 sum 聚集函数一样的计算,但是这个函数返回的是没有合并行的结果:
select dept, salary, sum(salary) over (partition by dept) as deptsum, avg(salary) over (partition by dept) as avgsal, count(*) over (partition by dept) as deptcount, max(salary) over (partition by dept) as maxsal from emptab;
DEPT SALARY DEPTSUM AVGSAL DEPTCOUNT MAXSAL
----- ------- - ------- ------- --------- --------
1 50000 383000 63833 6 78000
1 75000 383000 63833 6 78000
1 52000 383000 63833 6 78000
1 78000 383000 63833 6 78000
1 75000 383000 63833 6 78000
1 53000 383000 63833 6 78000
2 - 51000 51000 2 51000
2 51000 51000 51000 2 51000
3 79000 209000 69666 3 79000
3 55000 209000 69666 3 79000
3 75000 209000 69666 3 79000
- - 84000 84000 2 84000
- 84000 84000 84000 2 84000
注意,该查询没有包含 GROUP BY 子句。相反,该查询使用了 OVER 子句来对数据分区,以便 sum 函数对同一部门中的行执行计算,并在每一个部门内的每一行中返回该部门所有薪水的总和。按惯例,为了在每一行中包括那样的聚集结果,我们需要使用一个联合,但是现在 OLAP 函数为此提供了更简易的模式。我们推荐使用这种类型的函数作为 报告 函数,因为这种函数是对集合计算总和,并在每一行中都报告一次结果的。我曾经在前面和后面的例子中使用了 SUM, 但是大部分聚集函数(例如 AVG、MIN、MAX、STDEV,等等)都使用 OVER 子句。在 DEPTSUM 列右边的其他列显示了平均薪水、部门中雇员的人数以及部门中的最高薪水。惟一不支持作为标量-聚集函数的聚集函数是线性回归函数。
这些报告函数一个强大的用处就是计算比率和百分比。要计算某个雇员的薪水占整个部门薪水总和的百分比,只需简单地用报告的薪水总和去除该雇员的薪水。
select empnum, dept, salary, sum(salary) over (partition by dept) as deptsum, decimal(salary,10,2) / sum(salary) over(partition by dept) as percentage from emptab;
EMPNUM DEPT SALARY DEPTSUM PERCENTAGE
------ ----- -------- ----------- --------
1 1 50000 383000 0.1305
2 1 75000 383000 0.1958
5 1 52000 383000 0.1357
6 1 78000 383000 0.2036
7 1 75000 383000 0.1958
……
如果我们在要进行聚集的集合中引入一个排序方式,会出现什么情况呢?答案是,我们不处理一个 报告( reporting ) 函数,而是处理一个 累加( cumulative )函数。累加函数是一种标量-聚集函数,它对当前行 以及集合中当前行之前(相对排序方式而言)的所有行进行操作。让我们为这个例子使用一个不同的表。假设我们有一个这样的表,它记有当前历年的每月销售业绩。那么,我们如何计算每个月的 年至今日(year-to-date) 销售数字呢?这里,我们要计算每月销售的累加和。我们可以这样做:
select date, sales, sum(sales) over (order by date) as cume_sum, count(*) over (order by date) as setcount from sales where year(date) = 2000;
DATE SALES CUME_SUM SETCOUNT
---------- ------------ ------------ ---------
01/01/2000 968871.12 968871.12 1
02/01/2000 80050.05 1048921.17 2
03/01/2000 757866.14 1806787.31 3
04/01/2000 58748.13 1865535.44 4
05/01/2000 40711.69 1906247.13 5
06/01/2000 241187.78 2147434.91 6
07/01/2000 954924.16 3102359.07 7
08/01/2000 502822.963605182.03 8
09/01/2000 97201.45 3702383.48 9
10/01/2000 853999.45 4556382.93 10
11/01/2000 358775.59 4915158.52 11
12/01/2000 437513.35 5352671.87 12
每月销售量和到当前日期的累加销售量
让我们看一下结果。对于第一行,累加和就等于这一行的销售量。对于第二行,累加和等于一月份和二月份销售量的和(968871.12 + 80050.05 = 1048921.17)。类似地,第三行的结果是一月份、二月份和三月份销售量的和。在 CUME_SUM 列右边的列执行一个累加计数,给出在集合中行的数量。例如,第一行只有一行被求和(也就是该行本身),第二行有两行被求和(该行本身以及前一行),依此类推。上面的图给出了销售数字以及在前面的查询中计算出的累加和的图形化表示。
如果我们有多年的数据,并且想计算 每一年内 到当月的累加和,那么我们也可以像下面这样使用 PARTITION BY 子句:
select date, sales, sum(sales) over (partition by year(date) order by month(date)) as cume_sum from sales where year(date) >= 2000;
DATE SALES CUME_SUM
---------- ------------ -----------
01/01/2000 968871.12 968871.12
02/01/2000 80050.05 1048921.17
03/01/2000 757866.14 1806787.31
04/01/2000 58748.13 1865535.44
05/01/2000 40711.69 1906247.13
06/01/2000 241187.78 2147434.91
07/01/2000 954924.16 3102359.07
08/01/2000 502822.963605182.03
09/01/2000 97201.45 3702383.48
10/01/2000 853999.45 4556382.93
11/01/2000 358775.59 4915158.52
12/01/2000 437513.35 5352671.87
01/01/2001 476851.71 476851.71
02/01/2001 593768.12 1070619.83
03/01/2001 818597.97 1889217.80
...
使用 PARTITION BY 子句计算累加和
现在,请注意 2001年1月那一行是如何重置的。这是因为日期按年划分了分区,而在 2001年内 没有在一月份之前的行,因此 cume_sum 就等于一月份的销售量。这个例子还演示了另一件有趣的事情,那就是 OVER 子句使用的参数可以是表达式,而不仅仅是列值。
在更复杂的例子中,甚至可能会将其他的聚集函数嵌入到标量-聚集函数调用中。这很有用,因为在执行分析之前先执行某种类型的聚集(例如,将销售量聚集到月的层次上)是十分常见的。这就引发了下面的问题:何时处理标量-聚集函数?答案是在处理选择清单中剩下的部分时处理这些函数。通常,一个查询的处理顺序是这样的:
From 子句
Where 子句
Group By 子句
Having 子句
选择清单
您可以看到,选择清单是在查询的所有其他部分处理完之后才被处理的。这意味着如果您有谓语(在 WHERE 或 HAVING 子句中),或者您有任何作为 GROUP BY 子句结果的聚集,那么在处理标量-聚集函数之前首先要应用这些东西。例如,让我们看下面的查询:
select year(date) as year, sum(sales) as sum, sum(sum(sales)) over (order by year(date)) as cume_sum from sales where year(date) >= 1995 group by year(date);
YEAR SUM CUME_SUM
----------- ------------- ------------
1995 7731162.39 7731162.39
1996 4127017.98 11858180.37
1997 7211584.76 19069765.13
1998 4149296.50 23219061.63
1999 6278023.54 29497085.17
2000 5352671.87 34849757.04
2001 5736777.81 40586534.85
对一个聚集的累加和
在这个例子中,我们访问表(在 FROM 子句中指定)并应用 WHERE 子句,然后应用 GROUP BY 子句并计算每年的销售总量。最后,我们处理选择清单,包括所有的标量-聚集函数。
这里还要讲一点。因为标量-聚集函数是在 WHERE 子句 之后处理的,因此在一个谓语中引用标量-聚集函数是不可能的。相反,如果您想这么做,您就必须 嵌套 标量-聚集函数调用,要么是嵌套在一个公共表表达式内,要么是嵌套在一个嵌套查询内。这在执行返回前 n 行结果的查询时变得很有用。
一个这样例子就是编写一个用于选择具有最高销售总量的3年的查询。我们可以通过对每年的销售量排列、然后选择名次为 3 或者更小的行这种方法来做这件事。
with ranked_years (year, sum, rank) as (select year(date) as year, sum(sales) as sum, rank() over (order by sum(sales) desc) as rank from sales group by year(date) ) select year, sum, rank from ranked_years where rank <= 3;
YEAR SUM RANK
----------- ------------- -------
1995 7731162.39 1
1997 7211584.76 2
1999 6278023.54 3
Top n查询的例子
在这个例子中您可以看到,我们有一个公共表表达式,它执行聚集来计算每年的销售总量,然后对销售总量进行排列。接着,外围的选择使用这个结果表并添加一个谓语,使得查询只返回那些名次 <=3(也就是销售总量排在前3名)的行。要计算中数、百分位以及其他分布统计,也可以执行类似的查询。
我希望至此我已经传达了这些新 OLAP 函数是什么以及如何使用它们的大致信息。实际上,有关这些函数的内容比我在这里描述的要多得多。因此,敬请关注另一篇更详细介绍这些函数的文章。
我想告诉你的是,DB2 已经使用这些 OLAP 函数的实现扩展了关系模型,因而现在关系模型就可以理解相对于数据集合的 排序方式。如果您曾经试过编制牵涉到排序方式的查询,您就知道这些查询可以变得多么的困难和复杂(即使是像中数这样的简单查询也是如此)。OLAP 函数为您提供了可以高效、简明地编制那样的查询的工具。随着对 DBMS 的需求的日益增长,显然必须将传统的关系模型加以扩展,以便能够处理那些越来越复杂的分析,而这些函数正是 DB2 打破局限的一个例子。
myfriend2010 发表于:2008.01.09 17:36 ::分类: (db2 ) ::阅读:(810次) ::评论 (0)
===========================================================
DB2中數据庫管理頁大小的限制
===========================================================
DB2中的限制之六數据庫管理頁大小的限制
在現實的DB2應用中大家可能經常會遇到一些錯誤,錯誤的原因是對DB2的
限制不太了解而引起的,在此我簡單地總結一下,歡迎大家繼續﹐以便和大家共享﹐
共同探討﹐共同近步﹗(以下主要以DB2 7.X為例)。
1. 一個表中的列的最大個數
4KB頁大小的限制=500
8KB頁大小的限制=1012
16KB頁大小的限制=1012
32KB頁大小的限制=1012
2. 一行的最大長度
4KB頁大小的限制=4005
8KB頁大小的限制=8101
16KB頁大小的限制=16293
32KB頁大小的限制=32677
3. 一個表的每個分區的最大規模(千兆字節)
4KB頁大小的限制=64
8KB頁大小的限制=128
16KB頁大小的限制=256
32KB頁大小的限制=512
4. 一個索引的每個分區的最大規模(千兆字節)
4KB頁大小的限制=64
8KB頁大小的限制=128
16KB頁大小的限制=256
32KB頁大小的限制=512
5. 一個選擇列表元素的最大個數
4KB頁大小的限制=500
8KB頁大小的限制=1012
16KB頁大小的限制=1012
32KB頁大小的限制=1012
6. 一個GROUP BY子語句列的最大個數
4KB頁大小的限制=500
8KB頁大小的限制=1012
16KB頁大小的限制=1012
32KB頁大小的限制=1012
7. 一個GROUP BY子語句列的最大長度(字節數)
4KB頁大小的限制=4005
8KB頁大小的限制=8101
16KB頁大小的限制=16293
32KB頁大小的限制=32677
8. 一個ORDER BY子語句列的最大個數
4KB頁大小的限制=500
8KB頁大小的限制=1012
16KB頁大小的限制=1012
32KB頁大小的限制=1012
9. 一個ORDER BY子語句列的最大長度(字節數)
4KB頁大小的限制=4005
8KB頁大小的限制=8101
16KB頁大小的限制=16293
32KB頁大小的限制=32677
10. 一個INSERT語句中數值的最大個數
4KB頁大小的限制=500
8KB頁大小的限制=1012
16KB頁大小的限制=1012
32KB頁大小的限制=1012
11. 一個UPDATE語句中數值的最大個數
4KB頁大小的限制=500
8KB頁大小的限制=1012
16KB頁大小的限制=1012
32KB頁大小的限制=1012
12. 一個常規DMS表空間的最大規模(千兆字節數)
4KB頁大小的限制=64
8KB頁大小的限制=128
16KB頁大小的限制=256
32KB頁大小的限制=512
myfriend2010 发表于:2008.01.07 18:08 ::分类: (db2 ) ::阅读:(688次) ::评论 (1)
===========================================================
DB2 分区特性
===========================================================
在数据仓库中,事实表或历史表的大小是摆在设计人员和管理员面前的一个挑战。这些表通常包含数亿行数据,有时候甚至包含数千亿行数据。对于这种规模的表,主要关心以下几点:
查询性能 将大量新数据插入到这些表中 每月或每个季度删除大量过时的数据
随着时间的推移,DB2 继续添加和增强特性,以解决这些需求。DB2 9 for Linux, UNIX, and Windows 中一个重要的增强是表分区特性。这导致以下问题:
有哪些这样的特性? 每个特性对解决上面关心的问题有什么作用? 我应该使用哪些特性? 如何将这些特性结合起来使用以增强效果?
这些就是本文要解决的问题。阅读本文之后,读者将可以:
理解每个特性对于解决相关问题的独特作用。 明白如何有效地将这些特性结合起来使用。
有了这些背景,读者就足以进一步研究他们感兴趣的特性的细节。
CREATE table 语句现在提供了三种方式来组织数据库表中的数据。
CREATE TABLE 语句中的子句 DB2 特性名称
DISTRIBUTE BY HASH DPF —— 数据库分区特性
ORGANIZE BY DIMENSION MDC —— 多维聚类
PARTITION BY RANGE TP —— 表分区
您可以任意组合使用这些子句,以达到期望的效果。表 2 总结了与这些特性相关的术语,本文中用到的其他一些特性也列在下面。
DB2 特性名称 一部分的名称 用于分区数据的列 其他术语
数据分区特性(Data Partitioning Feature,DPF) 数据库分区 分布键(distribution key) 在之前的版本中,分布键被称做分区键
多维聚类(Multidimensional Clustering,MDC) 单元格,由一些块组成 维 块索引
表分区(TP) 数据分区 表分区键
每种特性都为分组表中的数据提供了独特的方法,并对解决与事实表或历史表相关的需求有独特的作用。
DPF 是最老的特性,通过它可以将数据库分成多个数据库分区。每个数据库分区有它自己的一组计算资源,包括 CPU 和存储。在 DPF 环境中,根据 CREATE TABLE 语句中指定的分区键,表中的每个行被分布到一个分区上。当处理一个查询时,请求也相应地被划分成多个部分,以便让各个数据库分区各自处理其负责的那些行。实际上,DPF 是一种可伸缩特性。DPF 可以通过增加数据库分区来提高处理能力,因此,随着表的增长,仍然可以保持较高的查询性能。这种能力常常被称作使用 DB2 的无共享架构提供线性的可伸缩性。
DPF 的作用不仅仅体现在表设计上。它还是调整和配置整个数据库系统的一种方法。现在已经有了关于配置那样的系统,以取得最佳性能、可靠性和增长的能力的建议实践。客户可以购买建议的硬件和软件以及配置,它们都放在一个称做 BCU (Balanced Configuration Unit) 的解决方案中。
MDC 是在 DB2 Version 8 中引入的,通过它可以在物理上将在多个维上具有类似值的行聚合在一起放在磁盘上。这种聚合能为常见分析性查询提供高效的 I/O。例如,对于 Product=car,Region=East,并且 SaleMonthYear = Jan09 的所有行,可以将它们存储在相同的存储位置,即所谓的块(block)。在 CREATE table 语句中定义维的时候,就为每种值的组合预留了存储空间。实际上,MDC 是一个能最大化查询性能的特性,对于数据仓库中常用的查询更是如此。这包括需要根据几个列中的值的组合选择行的查询。例如,DATE is between "Jan-01-2004" and "Feb-01-2005" AND Country IS NOT "United States" AND Product="Cell Phones"。
TP 是在 DB2 9 中引入的,与 MDC 类似,它也可以将具有近似值的行存储在一起。但是,TP 的以下特征是 MDC 所不具备的:
TP 支持按照一个维将一个表分区成多个数据分区。一种常见的设计是为每个月的数据创建一个数据分区。MDC 则支持定义多个维。 通过 TP,用户可以手动地定义每个数据分区,包括将被包括到那个分区的值的范围。MDC 则为每种惟一的 MDC 维值组合自动定义一个单元格(并创建块来存储那个单元格的数据)。 每个 TP 分区是一个单独的数据库对象(不同于其他作为单个数据库对象的表)。因此,TP 支持为 TP 表附加和卸除数据分区。卸除的分区成为一个常规表。而且,必要时可以将每个数据分区放在它自己的表空间中。
实际上,TP 不同于其他特性的优势在于为表添加或删除大量数据这个方面,即转入和转出。对于熟悉使用 Union All View (UAV) 来按日期对历史表分区的读者,TP 可以作为一种功能相似但是更为高级的解决方案。
表 3 总结了这些特性之间的比较:
特性 特性如何组织数据 优点
DPF 将行均匀地分布在多个数据库分区上 可伸缩性 —— 随着数据库的增长增加计算资源(也就是数据库分区)
MDC 将在多个维上具有近似值的行放在表中相同的物理位置,即所谓的块 查询性能 —— 组织数据的方式有利于获得更快的检索速度,对于由多个谓词指定范围的查询尤其有效
TP 将所有行放在同一个数据分区的一个指定范围的维中 数据移动 —— 通过添加和删除整个数据分区,可以增加和删除大量数据
本节详细阐述前面提出的观点,这 “三个朋友” 既是独立的,又是互补的。
当设计一个表时,对每个特性的使用可以认为是独立的。例如,
是否使用 MDC 和 TP 对于决定 DPF 的分布键没有影响。 一个列是否被用作 MDC 维对于是否应该将它作为表分区键没有影响,反之亦然。每个决定都可以单独做出。
每个特性的工作方式,例如索引方面,不会随着新的分区特性的引入而改变。例如,当引入 MDC 时,它的索引方面不会改变 DPF 在索引方面的工作方式。同样,当引入 TP 时,也不会改变 DPF 或 MDC 在索引方面的行为。在学习这些特性的时候,记住这一点有助于避免陷入困惑。
例如,假设您在学习 TP 的过程中碰到了 "TP has global indexes" 这个语句。那么,您应该不会推断 DPF 在处理索引方面的行为会有所变化。在这样的语句中,术语 "global" 仅仅是指索引对于多个 TP 数据分区来说是全局的。
通常来讲,一个特性不能用于解决数据库设计中与另外一个特性相关的不足或问题。值得注意的例子有:
TP 不能解决与 DPF 相关的问题,不管这个问题是 DPF 数据倾斜还是 DPF 中的管理活动速度降慢。不管有没有同时使用 TP,DPF 之前的补救方法仍然适用。 TP 不能用于纠正不好的 MDC 设计。
总之,如果存在与 DPF、MDC 或 TP 相关的问题,那么还是应该尝试适用于那个特性的解决方法。
数据仓库中的事实表(或历史表)非常适合使用上述每种特性,如下面的表 4 所示。
特性 适合的表特征 事实表的特征
DPF 大型表 —— 大到无法仅依靠单独一组 CPU 和 I/O 通道来处理 事实表是最大的数据库表。它们常常包含数亿行数据,有时候甚至包含数千亿行数据
MDC 结果集返回在多个维上具有近似值的行的查询 事实表(以及通常所说的数据仓库)是为支持这种类型的查询而设计的
TP 这种类型的表:周期性地添加大量数据,然后在数据到期后又删除大量数据 在事实表中,常常是每天都添加新数据。通常每月或每个季度删除过时的数据
本节让您对于设计决定的性质有一个感性的认识(也仅仅是感性的认识),并给出一些经验法则。后面列出的参考资料提供了更全面的设计指南。
对于 DPF,在选择一个分布键时,应首选那种能使数据行均匀地分布在多个数据库分区上的列。当不具备这样的条件时,就会造成数据倾斜。这意味着一个或一些数据库分区承担了更重比例的表行,从而造成了性能瓶颈。具有很多不同值的列是较好的选择。还有一种考虑是选择能最大化联结性能的列。
另一个 DPF 设计决定是数据库分区的数量。数据库分区的数量不算是表设计方面的考虑。实际上,它是整个系统设计上的考虑,需要根据整个数据库预期的原始数据大小和服务器硬件的能力来决定。很多系统需要的数据库分区不超过 20 个。但是,最大的系统可能需要更多的数据库分区。由于数据仓库有越来越大的趋势,数据库分区的数量有望增加。
对于 MDC,一个关键的决定是用哪些列作为 MDC 维。设计上的挑战是找到最佳的一组维和最佳的粒度,使得组织最大化,存储需求最小化。较好的选择是具有以下一部分或全部特征的列:
用于范围、等于或 IN 列表谓词 用于转入、转出或其他大规模的行删除 被 GROUP BY 或 ORDER by 子句引用 外键列 星型数据库的事实表中 join 子句中的列 粗粒度,也就是说不同的值很少的列
典型的设计是用一个表示日期的列作为一个 MDC 维,再加上 0 到 3 个其他列作为其他维,例如 region 和 product_type。
对于 TP,设计决定包括选择用作表分区键的列和分区的数量。通常表分区键是基于时间的列。每个分区与每次转入的数据量相符。例如,每月转出数据的表,对于每个月的数据都有一个分区。对于 TP,在设计时需要特别考虑的一点是,需要处理不在 CREATE table 语句中定义的值范围内的行。
对于需要每月根据 sale_date 转出数据的数据库,一种典型的设计是使用 sale_date 作为表分区键,并为每个月创建一个单独的分区。
通常,有一个 MDC 维是基于时间的列,这样一来,同一个列既可以用于 MDC,又可以用于 TP。MDC 的粒度可以比 TP 数据库分区更细一些。
下面的表总结了以上几点。
分区特性设计决定 经验法则
DPF —— 用作分布键的列 首选是具有很多不同值的列
MDC —— 用作 MDC 维的列 一种典型的设计是选择一个表示日期的列,再加上 0 到 3 个其他列,例如 region 和 product_type
TP —— 用作表分区键的列和分区的数量 选择一个基于时间的列。定义与每次转出的数据量相符的分区
表 6 展示了一些典型的表设计的例子。Transactions 历史表代表关系数据仓库中的一个典型的表。Recent transactions 表代表运营数据存储中的一个表,这种数据存储实际上是只有最近数据的一个数据仓库。
分区属性 Transactions 历史表 Recent transactions 表
DPF —— 用作分布键的列 Transaction ID Transaction ID
DPF —— 数据库分区的数量 20 4
MDC —— 用作维的列 Transaction date(Year+Month)=36 values (见注 1);Account type=5 values; State=51 values Transaction date(days)=90 values; Account type=5 values; State=51 values
TP —— 用作表分区键的列和分区的数量 Transaction date(Year+Month)=1 partition per month Transaction date(Year+Month)=1 partition per month
其他表属性 - - - -
# of rows (1 million per day) 1 billion 90 million
# of columns 30 30
# of indexes 4 15
注 1:对于 Transactions 历史表上的 MDC 维,另一种设计方案是以更细的粒度定义 Transaction 日期,例如每周或每天。更好的查询性能与增加的存储需求之间的平衡取决于数据和查询的特征。
阐明了以上三个特性相互区别、相互补充的关系之后,有必要进一步扩大讨论,谈一谈 MQT(物化查询表)。MQT 和分区特性都是为在相同的情况下(即数据仓库事实表或历史表)使用而设计的。因此,为了全面考虑如何使用本文中谈到的分区特性,需要解决涉及到 MQT 的情况下的一些特殊的考虑。
MQT 是基于一个查询的结果而定义的表。从另一种角度来看,MQT 就像结果集存储在一个表中的一个视图。MQT 可以提高涉及以下方面的复杂查询的响应时间:
基本表中的数据上的聚类或计算 基本表的联结 一个或多个较大基本表中常被访问的一部分数据。
当基本表中的数据发生改变时,需要相应地更新 MQT。MQT 特性为适应各种运营需求而进行更新提供了多种选项。
下面的表为表 3 增加了关于 MQT 的一行。
特性 特性如何组织数据 优点
DPF 将行均匀地分布在多个数据库分区上 可伸缩性 —— 随着数据库的增长增加计算资源(也就是数据库分区)
MDC 将在多个维上具有近似值的行放在表中相同的物理位置,即所谓的块 查询性能 —— 组织数据的方式有利于获得更快的检索速度,对于由多个谓词指定范围的查询尤其有效
TP 将所有行放在同一个数据分区的一个指定范围的维中 数据移动 —— 通过添加和删除整个数据分区,可以增加和删除大量数据
MQT 将查询的结果存储在一个表中 查询性能 —— 对于涉及较高代价的操作,例如复杂的联结和表扫描的查询,预先计算其结果集并存储(物化)结果集
与分区特性一起设计 MQT 时,在设计上的考虑可以总结为以下几点:
可以在使用分区特性的任意组合的表上创建 MQT。例如,可以在一个或多个使用 MDC 和 TP 的表上创建 MQT。基本表上分区特性的使用不需要考虑将来是否会在这个表上创建 MQT。然而,MQT 的设计却可能受到基本表上使用的分区特性的影响。例如,如果基本表使用了 DPF 进行分区,那么 MQT 的设计就应该考虑是否要在各个数据库分区上复制 MQT。 MQT 也可以使用分区特性。例如,可以使用 MDC 或 TP 对 MQT 分区。
接下来进一步介绍前面的 Transactions 历史表的例子,下面是这些表上定义的一些 MQT:
MQT 1 - transaction totals per day per account type MQT 2 - Year-to-Date totals per state
现在我们来看看在评价和使用这些特性时关键的考虑角度:性能,尤其是通常的数据仓库业务的用户查询的性能。这些查询有以下特征:
从事实表中选择在几个维上符合标准的行。这意味着要将几个维表与事实表相联结。 使用分组或聚类函数,例如 COUNT、GROUP BY 和 ORDER BY。 返回包括很多行的结果集,从数千行到数百万行。 这些查询是由用户或他们的 BI 工具生成的。这意味着这些查询更多情况下是临时性的,事务处理系统中的性能测试和调优方法对于它们并不适合。
虽然人们倾向于想到更快的性能,但最好还是说成更好的 性能。谈到性能,就应该包括以下一些方面:
峰值查询执行性能 查询执行性能的稳定性 对于数据仓库中各种具有不同特征的工作负载的性能 设计数据库以达到性能目标是否容易 为达到性能目标需要付出的代价
与过去相比,现在在设计数据库以达到性能目标的过程中还需要考虑的一点是硬件的发展趋势。随着 CPU 处理能力的不断提高以及存储设备容量的不断扩大,I/O 带宽是一个潜在的性能瓶颈。在这种环境下,I/O 效率是设计时要关键考虑的一点。
本节阐释每个分区特性对查询执行性能的作用。在后面的小节中我们还会谈到转入和转出的性能。
使用 DPF 与不使用 DPF 相比可以提供更多的计算资源,从而对性能产生积极的影响。当 DB2 优化器为一个查询形成查询访问计划时,它将工作划分到多个数据库分区上,这些数据库分区是并行工作的。之后,再收集各个数据库分区上得到的结果,并返回给查询提交者。
MDC 对性能的贡献在于提高检索数据的效率。在多个维上具有近似值的数据存储在相同的位置,这使得 I/O 操作变得更高效,而 I/O 操作正是数据仓库中一个常见的瓶颈。而且,MDC 特性还包括块索引,在块索引中,对于每个块的数据(而不是每一行的数据)都有一个条目。这使得执行索引操作时有更高的效率。为了发挥它潜在的性能,必须为 MDC 表设计一组最佳的(或者至少是够好的)维。MDC 只对那些包括维列的查询有好处。MDC 对于查询是完全透明的。最后,MDC 在管理方面有两个值得注意的优点:
MDC 块索引意味着需要的 RID 索引更少。管理方面的一个优点是用于索引的存储空间减少了。 由于新行是插在表中具有近似值的行附近的位置,因此数据仍然是聚合的,而不需要运行 REORG 实用程序。
TP 通过分区排除提高查询性能。例如,假设 Transactions 历史表有 36 个分区,每个月对应一个分区。对于一个选择过去 12 个月的数据的查询,优化器知道不必扫描这 12 个月之外的其他分区的数据。这种分区排除既适用于索引扫描,也适用于表扫描。TP 只对那些包括表分区键列的查询有利。
将来自运营系统的新数据插入到仓库中的事实表,这个过程称作 ETL、摄取(ingest)、填充数据仓库或者转入。下面的例子演示了可能遇到的各种情况。
例 1 - 使用 LOAD 每日摄入数据
在业务日结束后,运营系统中包含五十万到两亿条记录的多个平面文件如期到来。 一个客户脚本使用 DB2 Load 实用程序将每个文件装载到事实表中。这是在一个每夜批处理窗口中当表离线的时候完成的。 在下一个业务日一开始,查询这个表的用户就可以看到前一天的数据。
例 2 - 使用 insert 的准实时摄取
每过 30 分钟,一个包含 1 万到 10 万条记录的文件到来。 当该文件到来时,用户编写的一个程序将这些记录添加到一个 staging 表中,然后使用 insert 语句将这些记录添加到事实表中。
例 3 - MQT 刷新
在有 MQT 的时候,它们被看作将新数据添加到数据仓库这个过程中的一部分。比较特别的是,这种情况下可以使用 MQT 刷新策略。通常,ETL 过程是手动地指定何时更新 MQT,而不是让更新自动发生。
对于例 1,很可能是在每夜更新的所有任务完成之后立即更新。 对于例 2,MQT 通常是每天更新一次。因此,即使底层的数据是周期性地更新的,访问 MQT 的查询全天返回的都是相同的结果。
DB2 分区特性对于转入会有帮助,但是有时候也会带来新情况,客户在转入过程中要适当考虑这一点。
通过 DPF 可以更快速地添加数据,因为每个数据库分区可以并行工作。另一方面,DPF 又需要考虑将行发送到适当的数据分区。
与不使用 MDC 相比,使用 MDC 可以改善转入过程。其优点包括:
更少的物理 I/O:MDC 表的 RID 索引更少,因此在转入期间更新索引时需要的物理 I/O 更少。 更快的插入:MDC 表减少了页面争用和锁,因此有助于使用多个并行的流来执行插入。 并发的业务查询能拥有更好的性能:MDC 表减少了页面争用的锁,这一点同时也有利于并发业务查询的性能。
另一方面,如果使用 MDC,建议预先根据 MDC 维对数据进行排序。
在某些情况下,TP 有助于转入操作。TP 允许将行添加到一个分区,然后再在准备好的时候将那个分区附加到表上。然而,在这里的例子中,这个选项并不适用。还记得吗,我们的示例表(Transactions 历史表)对于每个月都有一个单独的分区,而我们是每天添加一次或多次数据。在这种情况下,在一个月开始之前,即这个月还没有开始每天添加数据之前,需要为这个表添加一个空白的分区。
最后,MQT 还增加了转入过程中要考虑的因素。特别是,需要决定何时更新 MQT。
当数据在数据仓库中存放了一段时间后,对于业务用户来说它就不再有用了,因此需要删除它们,为新数据腾出空间。这个过程称作转出、清洗(purging)和归档。下面的例子演示了可能遇到的各种不同的情况。
通常,转出涉及到以下业务规则,并关系到如何使用 DB2 分区特性的问题:
删除到了一定年龄的行:这是最简单也是最常见的业务需求。在传统的历史表中,一般的期限为 36 个月。对于最近历史表,一般期限为 60 到 180 天。 根据业务规则删除到了一定年龄的行:在这种情况下,有些行虽然到了一般的退休年龄,但是仍然需要保留。例如,为了为争议或调查提供证据,可能需要保留某个历史事务。 使数据仍然可以被访问,但是释放存储:这种情况有时候称作归档,而不是转出。在这种情况下,行必须对用户查询可见,但是需要将这些很少被访问的行转移到更便宜的、性能更低的存储上。这种业务需求可以通过 Tivoli Hierarchical Storage Manager (HSM) 之类的工具来解决。
通常,MQT 也需要放进来考虑。通常,MQT 也需要更新,以删除相应的总结数据。例如,如果从事实表中删除了 2003 年 3 月的数据,那么也需要删除 MQT 中关于那个月的总结数据。
为了支持转出,针对不同的业务需求,DB2 分区特性有一些值得注意的特性。
先说 DPF,这个特性对转出作用不大。使用 DPF 与不使用 DPF 相比,转出操作相差不大。
MDC 和 TP 都为转出操作带来好处。在任何 DB2 版本中,一个特性可能比另一个特性提供更好的转出性能,但是随着时间的推移,这两个特性应该大致相当。在比较这些特性时,更重要的是看每个特性在某些转出情况下特有的优势。
对于基本的、常见的转出情况(也就是说,只是删除到了一定年龄的行),TP 显然是首选。如果使用 TP,那么转出可以通过一个简单的 DETACH 操作来完成。而且,TP 是惟一适合以下情况的特性:
将转出的数据移动到另外一个位置(也就是说移动到一个表或数据库中),而不仅仅是删除它。 使用 Tivoli HSM 之类的工具将这些较老的、很少被访问的行转移到更便宜的存储中,但是用户查询仍然可以看到它们。
MDC 是惟一适合以下情况的特性,与基本转出相比,下面这些情况要求更高,但是不大常见:
客户希望在并发查询活动期间执行转出,但是他们不能接受在 DETACH 操作期间 TP 暂时需要的 zlock 的影响。 客户不希望修改他们的应用程序或脚本。也就是说,他们不想用 TP 的 DETACH 语句代替他们的 DELETE 语句。 客户想删除除时间维(表是在这一列上进行数据分区的)以外的其他维上的大量数据。 客户想根据业务规则删除到了一定年龄的行。在这种情况下,他们可以发出一条 SELECT 语句来识别符合条件的行,然后再 DELETE 那些行。
对于 MQT,当从 MQT 中删除相应的总结数据时,建议在 MQT 上使用表分区,并与基本表定义一样的数据分区。
虽然转出是删除过时数据的常见方式,但是应该注意到,客户有时候也使用其他方式来删除数据,这些方式不需要借助分区特性。这些方式有:
刷新表:在某些数据仓库中,整个表每年删除一次,然后装载一个替代的表,这个新表包含了除不再需要的数据以外的所有数据。 清洗:在某些最近历史表中,每过一些天就删除整个表,并重新创建表,数据将放在有更长历史的另一个表中。然后,重新创建的空表又可以摄取新的数据,直到清洗日的到来。
本文介绍了以下 DB2 表设计特性:表分区、MDC、DPF 和 MQT。这些特性并肩作战,一起解决客户在查询性能、插入新数据和删除老数据方面关心的问题。下面的表总结了这些 DB2 特性如何解决各种客户需求。
客户需求 优点
查询性能 每个特性都以它自己的方式为提高查询性能作出贡献。使用更多的特性将导致更好的性能。
转入 在大多数客户场景中,MDC 可以带来最大的好处。TP 可以在某些不常见的情况下带来好处。
转出 对于简单、常见的转出场景,TP 可以带来最大的好处。MDC 则适合处理 TP 不适合的其他转出情况。
myfriend2010 发表于:2008.01.07 14:55 ::分类: (db2 ) ::阅读:(533次) ::评论 (0)
===========================================================
db2 分区数据库概念:分区兼容性,并置
===========================================================
最近在看一些DB2的DPF方面的东西,有两个概念有一些搞不懂。
就是“分区兼容性”和“并置”两个概念。
资料是这样写的:
分区兼容性
可对分区键的对应列的基本数据类型进行比较,并可将它们声明为是分区兼容的(partition compatible)。分区兼容的数据类型具有如下属性:具有相同值但有不同类型的两个变量会按相同的分区算法映射至同一个分区号。 分区兼容性具有下列特征:
基本数据类型与另一个相同的基本数据类型兼容。
内部格式用于 DATE、TIME 和 TIMESTAMP 数据类型。它们彼此都不兼容,且都不与 CHAR 兼容。
分区兼容性不受带有 NOT NULL 或 FOR BIT DATA 定义的列的影响。
对兼容数据类型的 NULL 值的处理是完全相同的;对不兼容数据类型的 NULL 值的处理可能不相同。
用户定义的类型的基本数据类型用于分析分区兼容性。
对分区键中相同值的小数的处理是完全相同的,即使它们的标度和精度不同。
字符串中(CHAR、VARCHAR GRAPHIC 或 VARGRAPHIC)的尾部空格会被散列算法忽略。
BIGINT、SMALLINT 和 INTEGER 是兼容的数据类型。
REAL 和 FLOAT 是兼容的数据类型。
不同长度的 CHAR 和 VARCHAR 是兼容的数据类型。
GRAPHIC 和 VARGRAPHIC 是兼容的数据类型。
分区兼容性不适用于 LONG VARCHAR、LONG VARGRAPHIC、CLOB、DBCLOB 和 BLOB 数据类型,因为它们不能作为分区键。
并置
并置(collocation)是安置同一个数据库分区中包含相关数据的不同表中的行。并置的表使 DB2 可以更有效地使用连接策略。
您可能会发现,作为对特定查询的响应,两个或多个表频繁地提供数据。在此情况下,您会希望这样的表中的相关数据的位置尽可能地靠近。在数据库被物理地划分为两个或多个数据库分区的环境中,必须有一种方法可将划分的表的相关碎片尽可能地靠近。完成此过程的功能称为表并置。
当存取用于连接或子查询的多个表时,DB2(R) 通用数据库(DB2 UDB)能够识别要连接的数据是否位于相同数据库分区上。于是 DB2 就可以在存储数据的数据库分区上执行连接或子查询,而不必在数据库分区之间移动数据。这种局部地执行连接或子查询的能力具有显著的性能优点。
要发生并置,表必须:
在相同数据库分区组中,且这个数据库分区组不能处在再分配期间。(在再分配期间,数据库分区组中的表可能使用不同的分区映射 —— 它们不是并置的。)
有包含相同数量的列的分区键。
分区键的相应列是分区兼容的。
如果一个表在一个单分区数据库分区组中,且该分区组是在另一个表所在的同一个分区上定义的,那么也可以发生并置。
pub中这么回答:
比如int, char, varchar之类能够被散列的数据类型就是分区兼容性得,其他类似LOB, LF等类型不能被散列的就不是
对于并置,比如我有两个表A,B,其中A包含列c1 int, c2 char,B包含c1 varchar, c2 int
然后表A按照c1分区,表B按照c2分区,也就是说,当用户插入一行数据到表A,首先会对A.c1进行散列,然后模分区数量,把新的数据插入相应的分区,而对于表B则是对B.c2进行相同算法散列。
这样当查询select * from c1,c2 where A.c1=B.c2的时候,由于A.c1和B.c2的数据类型相同,使用相同的散列算法,如果A.c1与B.c2相等,那么他们肯定在同一分区,这样的话进行join的时候就不需要再分区间移动数据,只需要在本分区join完后向coord partition返回数据
 
myfriend2010 发表于:2008.01.05 09:09 ::分类: (db2 ) ::阅读:(1764次) ::评论 (4)
===========================================================
profile使用入门 :)--pub精华!
===========================================================
profile使用入门 :)
很多开发和数据库管理人员都在为优化器问题烦恼不已。尽管很多时候优化器问题都是可以通过常规手段解决的,但是在某些特殊情况下,或者紧急情况(没有时间完整地分析问题)下,用户可以使用profile暂时强制优化器使用某些特定的操作。。。
下面是一个step by step的例子,简单地说明了怎样强制优化器使用table scan
DB21085I Instance "DB2" uses "32" bits and DB2 code release "SQL09010" with
level identifier "02010107".
Informational tokens are "DB2 v9.1.0.356", "s060629", "NT32", and Fix Pack "0".
Product is installed at "D:PROGRA~1IBMSQLLIB" with DB2 Copy Name
"DB2COPY1".
<---------------创建一个数据库
D:TEMPdb2service.perf1>db2 create db sampel2DB20000I The CREATE DATABASE command completed successfully.
D:TEMPdb2service.perf1>db2 connect to sampel2
Database Connection Information
Database server = DB2/NT 9.1.0
SQL authorization ID = TAOEWANG
Local database alias = SAMPEL2
<----------创建优化器系统表
D:TEMPdb2service.perf1>db2 "create table systools.opt_profile (schema VARCHAR(128) not null, name varchar(128) not null, profile blob (2M) not null, primary key (schema, name))"
DB20000I The SQL command completed successfully.
D:TEMPdb2service.perf1>cd ..
<----------创建用户表
D:TEMP>db2 "create table mytable (name varchar(128), id integer, salary float,phone varchar(20))"
DB20000I The SQL command completed successfully.
<-----------插入一些数据
D:TEMP>db2 "insert into mytable values ('tao wang', 12345, 100, '123-456')"
DB20000I The SQL command completed successfully.
D:TEMP>db2 "insert into mytable values ('diablo2', 12346, 101, '123-457')"
DB20000I The SQL command completed successfully.
D:TEMP>db2 "insert into mytable values ('whiterain', 123, 102, '123-458')"
DB20000I The SQL command completed successfully.
D:TEMP>db2 "insert into mytable values ('ganquan', 1255, 104, '123-459')"
DB20000I The SQL command completed successfully.
<---------别忘了runstats
D:TEMP>db2 "runstats on table taoewang.mytable"
DB20000I The RUNSTATS command completed successfully.
D:TEMP>db2 "runstats on table taoewang.mytable for indexes all"
DB20000I The RUNSTATS command completed successfully.
<-----------试试看
D:TEMP>db2 "SELECT * FROM TAOEWANG.MYTABLE WHERE ID < 1000"
NAME
ID SALARY
PHONE
-------------------------------------------------------------------------------------------------------------------------------- ----------- ------------------------ --------------------
whiterain
123 +1.02000000000000E+002 123-458
1 record(s) selected.
<--------创建explain表
D:TEMP>cd D:Program FilesIBMSQLLIBMISC
D:Program FilesIBMSQLLIBMISC>db2 -tvf EXPLAIN.DDL
.....
D:Program FilesIBMSQLLIBMISC>cd D:temp
<----------看一看现在的访问计划
D:TEMP>db2 set current explain mode explain
DB20000I The SQL command completed successfully.
D:TEMP>db2 "SELECT * FROM TAOEWANG.MYTABLE WHERE ID < 1000"
SQL0217W The statement was not executed as only Explain information requests
are being processed. SQLSTATE=01604
D:TEMP>db2 set current explain mode no
DB20000I The SQL command completed successfully.
D:TEMP>db2exfmt -d sampel2 -g TIC -w -1 -n % -s % -# 0 -o output.txt
DB2 Universal Database Version 9.1, 5622-044 (c) Copyright IBM Corp. 1991, 2006
Licensed Material - Program Property of IBM
IBM DATABASE 2 Explain Table Format Tool
Connecting to the Database.
Connect to Database Successful.
Binding package - Bind was Successful
Output is in output.txt.
Executing Connect Reset -- Connect Reset was Successful.
D:TEMP>uedit32 output.txt
<-------------现在优化器用了index scan
Original Statement:
------------------
SELECT *
FROM TAOEWANG.MYTABLE
WHERE ID < 1000
Optimized Statement:
-------------------
SELECT Q1.NAME AS "NAME", Q1.ID AS "ID", Q1.SALARY AS "SALARY", Q1.PHONE AS
"PHONE"
FROM TAOEWANG.MYTABLE AS Q1
WHERE (Q1.ID < 1000)
Access Plan:
-----------
Total Cost: 7.56853
Query Degree: 1
Rows
RETURN
( 1)
Cost
I/O
|
1
FETCH
( 2)
7.56853
1
/----+---
1 4
IXSCAN TABLE: TAOEWANG
( 3) MYTABLE
0.00630865
0
|
4
INDEX: TAOEWANG
IX1
<---------创建一个xml文件,叫做a1.xml
a1.xml:











<----------创建一个del文件,叫insert.del
insert .del:
"TAOEWANG", "PROF1", "a1.xml"
<--------用import把xml插入profile系统表
D:TEMP>db2 import from insert.del of del modified by lobsinfile insert into systools.opt_profile
SQL3109N The utility is beginning to load data from file "insert.del".
SQL3110N The utility has completed processing. "1" rows were read from the
input file.
SQL3221W ...Begin COMMIT WORK. Input Record Count = "1".
SQL3222W ...COMMIT of any database changes was successful.
SQL3149N "1" rows were processed from the input file. "1" rows weresuccessfully inserted into the table. "0" rows were rejected.
Number of rows read = 1
Number of rows skipped = 0
Number of rows inserted = 1
Number of rows updated = 0
Number of rows rejected = 0
Number of rows committed = 1
<--------设置db2set env variable打开profile
D:TEMP>db2set DB2_OPTPROFILE=YES
<--------重起实例让db2set生效
D:TEMP>db2stop force
12/27/2007 08:54:45 0 0 SQL1064N DB2STOP processing was successful.
SQL1064N DB2STOP processing was successful.
D:TEMP>db2start
12/27/2007 08:54:48 0 0 SQL1063N DB2START processing was successful.
SQL1063N DB2START processing was successful.
D:TEMP>db2 connect to SAMPEL2
Database Connection Information
Database server = DB2/NT 9.1.0
SQL authorization ID = TAOEWANG
Local database alias = SAMPEL2
D:TEMP>db2 set current explain mode explain
DB20000I The SQL command completed successfully.
D:TEMP>db2 set current schema taoewang
DB20000I The SQL command completed successfully.
<---------设置需要使用的profile
D:TEMP>db2 set current optimization profile='PROF1'
DB20000I The SQL command completed successfully.
D:TEMP>db2 "SELECT * FROM TAOEWANG.MYTABLE WHERE ID < 1000"
SQL0217W The statement was not executed as only Explain information requests
are being processed. SQLSTATE=01604
D:TEMP>db2 set current explain mode no
DB20000I The SQL command completed successfully.
D:TEMP>db2exfmt -d sampel2 -g TIC -w -1 -n % -s % -# 0 -o output2.txt
DB2 Universal Database Version 9.1, 5622-044 (c) Copyright IBM Corp. 1991, 2006
Licensed Material - Program Property of IBM
IBM DATABASE 2 Explain Table Format Tool
Connecting to the Database.
Connect to Database Successful.
Output is in output2.txt.
Executing Connect Reset -- Connect Reset was Successful.
<------现在用了tablescan了
D:TEMP>uedit32 output2.txt
Profile Information:
--------------------
OPT_PROF: (Optimization Profile Name)
TAOEWANG.PROF1
STMTPROF: (Statement Profile Name)
Use Table Scan instead of Index Scan
Original Statement:
------------------
SELECT *
FROM TAOEWANG.MYTABLE
WHERE ID < 1000
Optimized Statement:
-------------------
SELECT Q1.NAME AS "NAME", Q1.ID AS "ID", Q1.SALARY AS "SALARY", Q1.PHONE AS
"PHONE"
FROM TAOEWANG.MYTABLE AS Q1
WHERE (Q1.ID < 1000)
Access Plan:
-----------
Total Cost: 7.56912
Query Degree: 1
Rows
RETURN
( 1)
Cost
I/O
|
1
TBSCAN
( 2)
7.56912
1
|
4
TABLE: TAOEWANG
MYTABLE
Extended Diagnostic Information:
--------------------------------
No extended Diagnostic Information for this statment.
如果用户希望在应用程序里面使用profile,可以使用下面的几种方法之一
对于cli应用程序中使用EXEC SQL SET CURRENT OPTIMIZATION PROFILE = 'xxxxxxxxx';
也可以在db2cli.ini中指定CURRENTOPTIMIZATIONPROFILE='"SCHEMA"."PROFILE"'
对于stored procedure在bind的时候指定OPTPROFILE
再次强调,profile不是万能药,只是止痛药~~~只有在万不得已的情况下才应该使用profile暂时指定用户需要的操作.一般来说,对于优化器问题用户应该尽量找到root cause,而不是简单地指定一个profile了事~~~
myfriend2010 发表于:2007.12.28 09:18 ::分类: (db2 ) ::阅读:(776次) ::评论 (0)
===========================================================
DB2表中统计信息收集及数据重组 转
===========================================================
DB2提供了3个命令工具,重组和分析table中的数据:
REORGCHK
REORG
RUNSTAT
在(一)中收集了对象的统计信息,这里,可以用这些统计信息来诊断对象的物理存储了。
具体内容见:http://blog.csdn.net/dlinger/archive/2004/10/12/133178.aspx
2.REORGCHK ,诊断对象的物理存储
>>-REORGCHK----+-------------------------------+----------------------------------+<<
| |-UPDATE--| | | .-USER------- .--|
'--+-CURRENT-+---STATISTICS--' '-ON TABLE--+-SYSTEM-----+--'
+-ALL--------+
'-table-name-'
在UDB的V8版本中增加了on schema 的选项。
UPDATE STATISTICS:先调用RUNSTATS来对table进行分析,
然后根据分析的统计信息诊断是否需要重组table
CURRENT STATISTICS:使用现有的统计信息诊断是否需要重组table
ON TABLE USER: 当前USER的所有table
ON TABLE SYSTEM:SYSTEM的所有table
ON TABLE ALL: 当前db的所有table
ON TABLE table-name:指定名称的table
我们分析SYSIBM.SYSTABLES,看看具体的执行结果:
db2 => reorgchk update statistics on table SYSIBM.SYSTABLES
执行 RUNSTATS ....
表统计信息:
F1: 100 * OVERFLOW / CARD < 5
F2: 100 * (Effective Space Utilization of Data Pages) > 70
F3: 100 * (Required Pages / Total Pages) > 80
SCHEMA NAME CARD OV NP FP ACTBLK TSIZE F1 F2 F3 REORG
----------------------------------------------------------------------------------------
SYSIBM SYSTABLES 2988 0 290 290 - 4774824 0 100 100 ---
----------------------------------------------------------------------------------------
索引统计信息:
F4: CLUSTERRATIO 或正常化的 CLUSTERFACTOR > 80
F5: 100 * (KEYS * (ISIZE + 9) + (CARD - KEYS) * 5) / ((NLEAF - NUM EMPTY LEAFS) * INDEXPAGESIZE) > 50
F6: (100 - PCTFREE) * ((INDEXPAGESIZE - 96) / (ISIZE + 12)) ** (NLEVELS - 2) * (INDEXPAGESIZE - 96)
/ (KEYS * (ISIZE + 9) + (CARD - KEYS) * 5) < 100
F7: 100 * (NUMRIDS DELETED / (NUMRIDS DELETED + CARD)) < 20
F8: 100 * (NUM EMPTY LEAFS / NLEAF) < 20
SCHEMA NAME CARD LEAF ELEAF LVLS ISIZE NDEL KEYS F4 F5 F6 F7 F8 REORG
-------------------------------------------------------------------------------------------------
表:SYSIBM.SYSTABLES
SYSIBM IBM00 2988 55 0 2 27 42 2988 95 47 3 1 0 -*---
SYSIBM IBM137 2988 18 0 2 4 52 2845 98 51 9 1 0 -----
SYSIBM IBM21 2988 5 0 2 3 26 3 99 73 24 0 0 -----
SYSIBM IBM22 2988 5 0 2 3 22 1 100 72 24 0 0 -----
SYSIBM IBM23 2988 5 0 2 3 2 1 100 72 24 0 0 -----
SYSIBM IBM78 2988 62 0 2 33 17 2988 95 49 2 0 0 -*---
-------------------------------------------------------------------------------------------------
CLUSTERRATIO 或正常化的 CLUSTERFACTOR(F4)将指示索引需要
REORG,该索引与基本表不在相同的序列中。当在表中定义了多个索引时,一个或多个索引
可能被标记为需要 REORG。指定 REORG 顺序的最重要索引。
使用 ORGANIZE BY 子句和相应的维索引定义的表的名称有 '*'
后缀。维索引的基数等价于表的“活动的块数”统计信息。
先来说明一下上面的信息:
CARD:基表中的数据行数
OV(OVERFLOW): 迁移行的数量
NP(NPAGES): 包含数据的page的数量
FP(FPAGES): 该表总共分配的page数量
TSIZE:table的实际数据的大小,以字节为单位。
TABLEPAGESIZE:table所在表空间的page size
F1: 处理溢出行。在溢出行超过总行数的5%时,该报告建议对table进行重组。
F2:处理空间使用率。在TSIZE小于等于该表分配总空间的70%时,该报告建议对table进行重组。
F3:处理空白页。所谓空白页,就是没有数据的页。当table中空白页大于20%时,该报告建议对table进行重组。
LEAF:index上叶节点的数量
LVLS(LEVELS):index级数
ISIZE:index的平均行长。
KEYS:唯一取值的数量
INDEXPAGESIZE:index所在表空间的page size
PCTFREE:index page中预留空间(%)
F4:聚簇因子
F5:为index key预留的空间。这个值应小于50%,否则该报告建议对index进行重组
F6:估算index页的用量,应大于总数的90%,否则该报告建议对index进行重组
F7:伪删除RID的数量。应小于总数的20%,否则该报告建议对index进行重组
F8: 伪空页的数量。应小于总数的20%,否则该报告建议对index进行重组
我们根据报告中REORG的值中有“*”来决定是否对table或index进行数据重组。当然,F1-F8的阀值只是建议值。
第三部分,我们将介绍在DB2中如何对数据进行重组。
myfriend2010 发表于:2007.12.18 21:12 ::分类: (db2 ) ::阅读:(1261次) ::评论 (0)
===========================================================
SQL0290N 表空间状态为: 停顿的独占的处理
===========================================================
今天一个同事报告一个问题,表都不能使用了
检查了一下,发现
问题 db2 => select * from test
ACTNO ACTKWD ACTDESC
------ ------ --------------------
SQL0290N Table space access is not allowed. SQLSTATE=55039
其他表也不能使用
在db2cc里查看表空间状态为: 停顿的独占
解决方法:
到命令行状态,首先connect 到需要处理的数据库
1、db2 => list tablespaces show detail 显示表空间状态
Tablespaces for Current Database
Tablespace ID = 0
Name = SYSCATSPACE
Type = System managed space
Contents = Any data
State = 0x0000
Detailed explanation:
Normal
Total pages = 2519
Useable pages = 2519
Used pages = 2519
Free pages = Not applicable
High water mark (pages) = Not applicable
Page size (bytes) = 4096
Extent size (pages) = 32
Prefetch size (pages) = 32
Number of containers = 1
Tablespace ID = 1
Name = TEMPSPACE1
Type = System managed space
Contents = System Temporary data
State = 0x0000
Detailed explanation:
Normal
Total pages = 1
Useable pages = 1
Used pages = 1
Free pages = Not applicable
High water mark (pages) = Not applicable
Page size (bytes) = 4096
Extent size (pages) = 32
Prefetch size (pages) = 32
Number of containers = 1
Tablespace ID = 2
Name = USERSPACE1
Type = System managed space
Contents = Any data
State = 0x0004 这个代码意义就是“停顿的独占”,正常状态为0x0000,
非0就是有问题,都可以用下面方法解决。
Detailed explanation:
Quiesced: EXCLUSIVE
Total pages = 687
Useable pages = 687
Used pages = 687
Free pages = Not applicable
High water mark (pages) = Not applicable
Page size (bytes) = 4096
Extent size (pages) = 32
Prefetch size (pages) = 32
Number of containers = 1
Number of quiescers = 1 注意下面几行
Quiescer 1:
Tablespace ID = 2
Object ID = 50 “object id是造成死锁表的id”
2、db2 => select tabname from syscat.tables where tableid=50 通过所住的id号找出是哪个表
TABNAME
--------------------------------------------------------------------------------------------------------------------------------
SYSINDEXEXTENSIONPARMS
TEST 就是这个表
2 record(s) selected.
3、db2 => quiesce tablespaces for table test reset 执行该命令清除错误的状态
DB20000I The QUIESCE TABLESPACES command completed successfully.
4、重新select,问题解决
5、比较常见导致改种问题的原因是,非正常的中止正对表进行的操作,导致对表空间的使用没有正常的释放。
myfriend2010 发表于:2007.12.06 09:56 ::分类: (db2 ) ::阅读:(2536次) ::评论 (1)
===========================================================
db2执行计划显示工具介绍
===========================================================
db2执行计划显示工具介绍
db2有图形执行计划显示工具,如果没有图形环境,如unix主机,可以生成文本的
文件来显示执行计划
1.如果第一次执行,请先 connect to dbname,
执行db2 -tvf $HOME/sqllib/misc/EXPLAIN.DDL建立执行计划表
2.db2 set current explain mode explain
设置成解释模式,并不真正执行下面将发出的sql命令
3.db2 "select count(*) from staff"
执行你想要分析的sql语句
4.db2 set current explain mode no
取消解释模式
5.db2exfmt -d sample -g TIC -w -l -s % -n % -o db2exmt.out
执行计划输出到文件db2exmt.out
myfriend2010 发表于:2007.12.05 14:46 ::分类: (db2 ) ::阅读:(903次) ::评论 (1)
===========================================================
在DB2中恢复删除表的技巧-转
===========================================================
这边转载了一个恢复drop后的表的一个操作,类似于oracle 10g中的闪回!
DB2在历史文件中保存了备份,恢复,装载数据,删除表等操作.
假设数据库名为sample, 您可以用下面的命令列出删除表的记录: db2 "list history dropped table all for sample"
下一步是从以前的备份中恢复删除表所在的表空间, 备份所在的目录是c:db2backup.
without rolling forward指明不需要前滚.
db2 "restore db sample tablespace(userspace1) from c:db2backup taken at 20041102100931 without rolling forward without prompting"
第三步是把所删除表的数据卸载到某一目录中
db2 "rollforward db sample to end of logs and complete recover dropped table 00000000000002010002000d to c:db2backup"
第四步是用历史文件中保留的该表的DDL语句重建该表
第五步是重新装载数据到该表. p(1,2)表明装载该表的第一个和第二个字段的内容. recoverme是表名
db2 "load from c:db2backupnode0000data OF DEL METHOD p(1,2) insert into recoverme"
myfriend2010 发表于:2007.11.29 13:31 ::分类: (db2 ) ::阅读:(667次) ::评论 (0)
===========================================================
客户端查看数据库服务器端的锁信息
===========================================================
1.查看本地实例
C:>db2ilist
DB2
---本地实例为db2
2.查看当前正在使用的实例
C:>db2 get instance
当前数据库管理器实例是:DB2
3.查看节点编目情况,得到非本地的实例
C:>db2 list node directory
节点目录
目录中的条目数 = 1
节点 1 条目:
节点名 = DB164
注释 =
目录条目类型 = LOCAL
协议 = TCPIP
主机名 = 169.254.11.164
服务名称 = 50000
C:>db2 list node directory show detail
节点目录
目录中的条目数 = 1
节点 1 条目:
节点名 = DB164
注释 =
目录条目类型 = LOCAL
协议 = TCPIP
主机名 = 169.254.11.164
服务名称 = 50000
远程实例名 = db2
系统 =
操作系统类型 = 无
可以看到本地有169.254.11.164上的DB164实例的节点编目。
4.查看所有数据库和实例的对应信息。
C:>db2 list db directory
系统数据库目录
目录中的条目数 = 3
数据库 1 条目:
数据库别名 = DW
数据库名称 = DW
节点名 = DB164
数据库发行版级别 = a.00
注释 =
目录条目类型 = 远程
认证 = SERVER
目录数据库分区号 = -1
备用服务器主机名 =
备用服务器端口号 =
数据库 2 条目:
数据库别名 = CCP_BUSI
数据库名称 = CCP_BUSI
节点名 = DB164
数据库发行版级别 = a.00
注释 =
目录条目类型 = 远程
认证 = SERVER
目录数据库分区号 = -1
备用服务器主机名 =
备用服务器端口号 =
数据库 3 条目:
数据库别名 = MYDB
数据库名称 = MYDB
数据库驱动器 = D:DB2
数据库发行版级别 = a.00
注释 =
目录条目类型 = 间接
目录数据库分区号 = 0
备用服务器主机名 =
备用服务器端口号 =
---可以看到db164上有2个数据库DW和CCP_BUSI,下一步就连结到DW上看看
5.attach到db164上
C:>db2 attach to db164 user db2admin
输入 db2admin 的当前密码:
实例连接信息
实例服务器 = DB2/NT 8.2.0
授权标识 = DB2ADMIN
本地实例别名 = DB164
6. 查看db164上的锁信息
C:>
C:>db2 get snapshot for locks on dw
数据库锁定快照
数据库名称 = DW
数据库路径 = F:DB2NODE0000SQL00001
输入数据库别名 = DW
挂起的锁定 = 0
当前已连接的应用程序 = 6
当前正等待锁定的代理进程数 = 0
快照时间戳记 = 2007-11-21 16:06:10.510838
应用程序句柄 = 395
应用程序标识 = A9FE0B84.O009.0465C1073117
序号 = 0008
应用程序名 = QuestCentral.exe
CONNECT 授权标识 = CCP
应用程序状态 = UOW 正在等待
状态更改时间 = 未收集
应用程序代码页 = 1386
挂起的锁定 = 0
总计等待时间(毫秒) = 未收集
应用程序句柄 = 336
应用程序标识 = A9FE0BA6.I708.071121064255
序号 = 0004
应用程序名 = QuestCentral.exe
CONNECT 授权标识 = CCP
应用程序状态 = UOW 正在等待
状态更改时间 = 未收集
应用程序代码页 = 1386
挂起的锁定 = 0
总计等待时间(毫秒) = 未收集
应用程序句柄 = 280
应用程序标识 = A9FE0BA6.N806.071121031820
序号 = 0011
应用程序名 = QuestCentral.exe
CONNECT 授权标识 = CCP
应用程序状态 = UOW 正在等待
状态更改时间 = 未收集
应用程序代码页 = 1386
挂起的锁定 = 0
总计等待时间(毫秒) = 未收集
应用程序句柄 = 95
应用程序标识 = A9FE0B86.NA06.015D01013815
序号 = 0042
应用程序名 = QuestCentral.exe
CONNECT 授权标识 = CCP
应用程序状态 = UOW 正在等待
状态更改时间 = 未收集
应用程序代码页 = 1386
挂起的锁定 = 0
总计等待时间(毫秒) = 未收集
应用程序句柄 = 62
应用程序标识 = A9FE0BA6.MF05.071121013410
序号 = 0005
应用程序名 = QuestCentral.exe
CONNECT 授权标识 = CCP
应用程序状态 = UOW 正在等待
状态更改时间 = 未收集
应用程序代码页 = 1386
挂起的锁定 = 0
总计等待时间(毫秒) = 未收集
应用程序句柄 = 54
应用程序标识 = A9FE0BA6.M305.071121013157
序号 = 0008
应用程序名 = QuestCentral.exe
CONNECT 授权标识 = CCP
应用程序状态 = UOW 正在等待
状态更改时间 = 未收集
应用程序代码页 = 1386
挂起的锁定 = 0
总计等待时间(毫秒) = 未收集
 
myfriend2010 发表于:2007.11.21 16:56 ::分类: (db2 ) ::阅读:(665次) ::评论 (0)
===========================================================
IP转换的函数!
===========================================================
在数据库的开发和管理过程中,时常用到需要查询链接对应的IP地址!
一般都是用这个命令db2 list applications,但是db2的这个命令有一个不合理的地方,就是他显示IP是以16进制的形式,
所以通常需要把进程对应的“应用程序标识”的小数点前的那个字符串,转换成10进制的数来检查IP。
于是乎我写了一个小过程,可以把那个字符串直接转换成ip地址的形式,不敢独享,现公布给大家。
程序如下:
-- Start of generated script for 169.254.11.164-db2-DW (ccp)
-- Nov-15-2007 at 17:35:12
drop PROCEDURE CCP.GETIP;
SET SCHEMA CCP ;
SET CURRENT PATH = "SYSIBM","SYSFUN","SYSPROC","CCP";
CREATE PROCEDURE CCP.GETIP
(IN I_IP VARCHAR(8),
OUT O_IP VARCHAR(20)
)
LANGUAGE SQL
NOT DETERMINISTIC
CALLED ON NULL INPUT
EXTERNAL ACTION
OLD SAVEPOINT LEVEL
MODIFIES SQL DATA
INHERIT SPECIAL REGISTERS
begin
/*
--auther:Z.X.T
--DATE:2007-11-15
--描述,本过程可以把16进制的IP转换成一般的IP形式
--I_IP 输入:长度为8的16进制数,如'AABBCCDD'
--O_IP 输出:ip地址形式如:192.168.1.0
*/
declare first_IP1 varchar(3);
declare first_IP2 varchar(3);
declare first_IP3 varchar(3);
declare first_IP4 varchar(3);
declare first_IP11 INTEGER;
declare first_IP21 INTEGER;
declare first_IP31 INTEGER;
declare first_IP41 INTEGER;
if(I_IP='*N0') then
set O_IP ='本地';
return;
end if;
if(length(I_IP)!=8) then
set O_IP ='输入错误';
return;
end if;
set first_IP1=Ucase(substr(I_IP,1,2));
set first_IP2=Ucase(substr(I_IP,3,2));
set first_IP3=Ucase(substr(I_IP,5,2));
set first_IP4=Ucase(substr(I_IP,7,2));
set first_IP11=INTEGER(case substr(first_IP1,1,1) when 'A' then '10' when 'B' then '11' when 'C' then '12'
when 'D' then '13' when 'E' then '14' when 'F' then '15'
when 'G' then '0' else substr(first_IP1,1,1) end)*16
+INTEGER(case substr(first_IP1,2,1) when 'A' then '10' when 'B' then '11' when 'C' then '12'
when 'D' then '13' when 'E' then '14' when 'F' then '15'
when 'G' then '0' else substr(first_IP1,2,1) end);
set first_IP21=INTEGER(case substr(first_IP2,1,1) when 'A' then '10' when 'B' then '11' when 'C' then '12'
when 'D' then '13' when 'E' then '14' when 'F' then '15'
when 'G' then '0' else substr(first_IP2,1,1) end
)*16
+INTEGER(case substr(first_IP2,2,1) when 'A' then '10' when 'B' then '11' when 'C' then '12'
when 'D' then '13' when 'E' then '14' when 'F' then '15'
when 'G' then '0' else substr(first_IP2,2,1) end);
set first_IP31=INTEGER(case substr(first_IP3,1,1) when 'A' then '10' when 'B' then '11' when 'C' then '12'
when 'D' then '13' when 'E' then '14' when 'F' then '15'
when 'G' then '0' else substr(first_IP3,1,1) end
)*16
+INTEGER(case substr(first_IP3,2,1) when 'A' then '10' when 'B' then '11' when 'C' then '12'
when 'D' then '13' when 'E' then '14' when 'F' then '15'
when 'G' then '0' else substr(first_IP3,2,1) end);
set first_IP41=INTEGER(case substr(first_IP4,1,1) when 'A' then '10' when 'B' then '11' when 'C' then '12'
when 'D' then '13' when 'E' then '14' when 'F' then '15'
when 'G' then '0' else substr(first_IP4,1,1) end
)*16
+INTEGER(case substr(first_IP4,2,1) when 'A' then '10' when 'B' then '11' when 'C' then '12'
when 'D' then '13' when 'E' then '14' when 'F' then '15'
when 'G' then '0' else substr(first_IP4,2,1) end);
set O_IP=rtrim(char(first_IP11))||'.'||rtrim(char(first_IP21))||'.'||rtrim(char(first_IP31))||'.'||Rtrim(char(first_IP41));
end;
#SYNC 10;
commit;
-- End of generated script for 169.254.11.164-db2-DW (ccp)
ok,存储过程完成!下来测试下看看!
C:>db2 list applications
授权标识 应用程序名 应用程序 应用程序标识 DB 代理进程
句柄 名称 序号
-------- -------------- ---------- ------------------------------ -------- -----
CCP db2bp.exe 341 A9FE0B84.G710.033705103339 DW 1
CCP QuestCentral.e 325 A9FE0B84.G510.00F5C5102039 DW 1
CCP QuestCentral.e 323 A9FE0B84.G410.00F5C5102026 DW 1
CCP QuestCentral.e 302 A9FE0B84.C10F.00F5C5100723 DW 1
CCP QuestCentral.e 262 A9FE0B84.I50F.00F5C5093513 DW 1
CCP QuestCentral.e 258 A9FE0B84.I20F.00F5C5093332 DW 1
CCP QuestCentral.e 186 A9FE0B84.LF0E.00F5C5084450 DW 1
CCP clemlocal.exe 178 A9FE0BA6.B007.071115083616 DW 7
CCP QuestCentral.e 82 A9FE0B84.AE0C.00F5C5082400 DW 3
TEST db2jccWebConta 329 A9FE0B9E.F181.071115102030 CCP_BUSI 12
TEST QuestCentral.e 320 A9FE0B88.N00C.019845101725 CCP_BUSI 2
TEST QuestCentral.e 318 A9FE0B88.MD0C.019845101711 CCP_BUSI 1
TEST db2jccWebConta 317 A9FE0B9E.F081.071115101401 CCP_BUSI 11
TEST QuestCentral.e 313 A9FE0B88.G20C.019845101424 CCP_BUSI 1
TEST QuestCentral.e 309 A9FE0B88.F10B.019845101203 CCP_BUSI 1
TEST QuestCentral.e 306 A9FE0B88.E20B.019845100938 CCP_BUSI 3
TEST QuestCentral.e 298 A9FE0B88.A90B.019845100509 CCP_BUSI 10
C:>db2 list applications
授权标识 应用程序名 应用程序 应用程序标识 DB 代理进程
句柄 名称 序号
-------- -------------- ---------- ------------------------------ -------- -----
CCP db2bp.exe 341 A9FE0B84.G710.033705103339 DW 1
CCP QuestCentral.e 325 A9FE0B84.G510.00F5C5102039 DW 1
CCP QuestCentral.e 323 A9FE0B84.G410.00F5C5102026 DW 1
CCP QuestCentral.e 302 A9FE0B84.C10F.00F5C5100723 DW 1
CCP QuestCentral.e 262 A9FE0B84.I50F.00F5C5093513 DW 1
CCP QuestCentral.e 258 A9FE0B84.I20F.00F5C5093332 DW 1
CCP QuestCentral.e 186 A9FE0B84.LF0E.00F5C5084450 DW 1
CCP clemlocal.exe 178 A9FE0BA6.B007.071115083616 DW 7
CCP QuestCentral.e 82 A9FE0B84.AE0C.00F5C5082400 DW 3
TEST db2jccWebConta 329 A9FE0B9E.F181.071115102030 CCP_BUSI 13
TEST QuestCentral.e 320 A9FE0B88.N00C.019845101725 CCP_BUSI 2
TEST QuestCentral.e 318 A9FE0B88.MD0C.019845101711 CCP_BUSI 1
TEST QuestCentral.e 313 A9FE0B88.G20C.019845101424 CCP_BUSI 1
TEST QuestCentral.e 309 A9FE0B88.F10B.019845101203 CCP_BUSI 1
TEST QuestCentral.e 306 A9FE0B88.E20B.019845100938 CCP_BUSI 3
TEST QuestCentral.e 298 A9FE0B88.A90B.019845100509 CCP_BUSI 10
C:>db2 connect to dw
数据库连接信息
数据库服务器 = DB2/NT 8.2.0
SQL 授权标识 = DB2ADMIN
本地数据库别名 = DW
C:>db2 call CCP.GETIP('A9FE0B88',?)
输出参数的值
--------------------------
参数名: O_IP
参数值: 169.254.11.136
返回状态 = 0
C:>
myfriend2010 发表于:2007.11.16 15:02 ::分类: (db2 ) ::阅读:(750次) ::评论 (0)
===========================================================
DB2改服务器名字过程
===========================================================
1.停止事例和数据库
db2stop
db2admin stop
2.改计算机名字并重启
原来为ZXT
修改为ZXTZ
重启
3.修改IBMSQLLIBDB2下的db2nodes.cfg
原来为
0 zxt ZXT 0
1 zxt ZXT 1
修改为
0 zxtz ZXT 0
1 zxtz ZXT 1
4.修改注册信息
C:>db2set db2system
ZXT
修改为
C:>db2set -g db2system=ZXTZ
5.uncatalog 本地node
C:>db2 list admin node directory show detail
节点目录
目录中的条目数 = 1
节点 1 条目:
节点名 = ZXT
注释 =
目录条目类型 = LOCAL
协议 = TCPIP
主机名 = ZXT
服务名称 = 523
远程实例名 =
系统 = ZXT
操作系统类型 = 无
C:>db2 uncatalog node zxt
DB20000I UNCATALOG NODE 命令成功完成。
DB21056W 只有在刷新目录高速缓存以后,目录更改才会生效。
6.catalog 本地node
C:>db2 catalog admin tcpip node ZXTZ remote ZXTZ system ZXTZ
DB20000I CATALOG ADMIN TCPIP NODE 命令成功完成。
DB21056W 只有在刷新目录高速缓存以后,目录更改才会生效。
C:>db2 update admin cfg using DB2SYSTEM ZXTZ
DB20000I UPDATE ADMIN CONFIGURATION 命令成功完成。
C:>db2 update admin cfg using SMTP_SERVER ZXTZ
DB20000I UPDATE ADMIN CONFIGURATION 命令成功完成。
7.启动数据库
C:>db2admin start
SQL4406W 已成功启动“DB2 管理服务器”。
C:>db2start
2007-11-14 15:42:50 1 0 SQL1063N DB2START 处理成功。
2007-11-14 15:42:51 0 0 SQL1063N DB2START 处理成功。
SQL1063N DB2START 处理成功。
C:>db2 connect to mydb
数据库连接信息
数据库服务器 = DB2/NT 8.2.0
SQL 授权标识 = ADMINIST...
本地数据库别名 = MYDB
myfriend2010 发表于:2007.11.16 15:00 ::分类: (db2 ) ::阅读:(784次) ::评论 (0)
===========================================================
DB2中有关日期和时间的函数,及应用--转
===========================================================
DAYNAME 返回一个大小写混合的字符串,对于参数的日部分,用星期表示这一天的名称(例如,Friday)。
DAYOFWEEK 返回参数中的星期几,用范围在 1-7 的整数值表示,其中 1 代表星期日。
DAYOFWEEK_ISO 返回参数中的星期几,用范围在 1-7 的整数值表示,其中 1 代表星期一。
DAYOFYEAR 返回参数中一年中的第几天,用范围在 1-366 的整数值表示。
DAYS 返回日期的整数表示。
JULIAN_DAY 返回从公元前 4712 年 1 月 1 日(儒略日历的开始日期)到参数中指定日期值之间的天数,用整数值表示。
MIDNIGHT_SECONDS 返回午夜和参数中指定的时间值之间的秒数,用范围在 0 到 86400 之间的整数值表示。
MONTHNAME 对于参数的月部分的月份,返回一个大小写混合的字符串(例如,January)。
TIMESTAMP_ISO 根据日期、时间或时间戳记参数而返回一个时间戳记值。
TIMESTAMP_FORMAT 从已使用字符模板解释的字符串返回时间戳记。
TIMESTAMPDIFF 根据两个时间戳记之间的时差,返回由第一个参数定义的类型表示的估计时差。
TO_CHAR 返回已用字符模板进行格式化的时间戳记的字符表示。TO_CHAR 是 VARCHAR_FORMAT 的同义词。
TO_DATE 从已使用字符模板解释过的字符串返回时间戳记。TO_DATE 是 TIMESTAMP_FORMAT 的同义词。
WEEK 返回参数中一年的第几周,用范围在 1-54 的整数值表示。以星期日作为一周的开始。
WEEK_ISO 返回参数中一年的第几周,用范围在 1-53 的整数值表示。
要使当前时间或当前时间戳记调整到 GMT/CUT,则把当前的时间或时间戳记减去当前时区寄存器:
current time - current timezone
current timestamp - current timezone
给定了日期、时间或时间戳记,则使用适当的函数可以单独抽取出(如果适用的话)年、月、日、时、分、秒及微秒各部分:
YEAR (current timestamp)
MONTH (current timestamp)
DAY (current timestamp)
HOUR (current timestamp)
MINUTE (current timestamp)
SECOND (current timestamp)
MICROSECOND (current timestamp)
因为没有更好的术语,所以您还可以使用英语来执行日期和时间计算:
current date + 1 YEAR
current date + 3 YEARS + 2 MONTHS + 15 DAYS
current time + 5 HOURS - 3 MINUTES + 10 SECONDS
从时间戳记单独抽取出日期和时间也非常简单:
DATE (current timestamp)
TIME (current timestamp)
而以下示例描述了如何获得微秒部分归零的当前时间戳记:
CURRENT TIMESTAMP - MICROSECOND (current timestamp) MICROSECONDS
如果想将日期或时间值与其它文本相衔接,那么需要先将该值转换成字符串。为此,只要使用 CHAR() 函数:
char(current date)
char(current time)
char(current date + 12 hours)
要将字符串转换成日期或时间值,可以使用:
TIMESTAMP ('2002-10-20-12.00.00.000000')
TIMESTAMP ('2002-10-20 12:00:00')
DATE ('2002-10-20')
DATE ('10/20/2002')
TIME ('12:00:00')
TIME ('12.00.00')
TIMESTAMP()、DATE() 和 TIME() 函数接受更多种格式。上面几种格式只是示例,我将把它作为一个练习,让读者自己去发现其它格式。
有时,您需要知道两个时间戳记之间的时差。为此,DB2 提供了一个名为 TIMESTAMPDIFF() 的内置函数。但该函数返回的是近似值,因为它不考虑闰年,而且假设每个月只有 30 天。以下示例描述了如何得到两个日期的近似时差:
timestampdiff (, char(
timestamp('2002-11-30-00.00.00')-
timestamp('2002-11-08-00.00.00')))
对于 ,可以使用以下各值来替代,以指出结果的时间单位:
1 = 秒的小数部分
2 = 秒
4 = 分
8 = 时
16 = 天
32 = 周
64 = 月
128 = 季度
256 = 年
当日期很接近时使用 timestampdiff() 比日期相差很大时精确。如果需要进行更精确的计算,可以使用以下方法来确定时差(按秒计):
(DAYS(t1) - DAYS(t2)) * 86400 +
(MIDNIGHT_SECONDS(t1) - MIDNIGHT_SECONDS(t2))
为方便起见,还可以对上面的方法创建 SQL 用户定义的函数:
CREATE FUNCTION secondsdiff(t1 TIMESTAMP, t2 TIMESTAMP)
RETURNS INT
RETURN (
(DAYS(t1) - DAYS(t2)) * 86400 +
(MIDNIGHT_SECONDS(t1) - MIDNIGHT_SECONDS(t2))
)
@
如果需要确定给定年份是否是闰年,以下是一个很有用的 SQL 函数,您可以创建它来确定给定年份的天数:
CREATE FUNCTION daysinyear(yr INT)
RETURNS INT
RETURN (CASE (mod(yr, 400)) WHEN 0 THEN 366 ELSE
CASE (mod(yr, 4)) WHEN 0 THEN
CASE (mod(yr, 100)) WHEN 0 THEN 365 ELSE 366 END
ELSE 365 END
END)@
最后,以下是一张用于日期操作的内置函数表。它旨在帮助您快速确定可能满足您要求的函数,但未提供完整的参考。有关这些函数的更多信息,请参考 SQL 参考大全。
SQL 日期和时间函数
DAYNAME 返回一个大小写混合的字符串,对于参数的日部分,用星期表示这一天的名称(例如,Friday)。
DAYOFWEEK 返回参数中的星期几,用范围在 1-7 的整数值表示,其中 1 代表星期日。
DAYOFWEEK_ISO 返回参数中的星期几,用范围在 1-7 的整数值表示,其中 1 代表星期一。
DAYOFYEAR 返回参数中一年中的第几天,用范围在 1-366 的整数值表示。
DAYS 返回日期的整数表示。
JULIAN_DAY 返回从公元前 4712 年 1 月 1 日(儒略日历的开始日期)到参数中指定日期值之间的天数,用整数值表示。
MIDNIGHT_SECONDS 返回午夜和参数中指定的时间值之间的秒数,用范围在 0 到 86400 之间的整数值表示。
MONTHNAME 对于参数的月部分的月份,返回一个大小写混合的字符串(例如,January)。
TIMESTAMP_ISO 根据日期、时间或时间戳记参数而返回一个时间戳记值。
TIMESTAMP_FORMAT 从已使用字符模板解释的字符串返回时间戳记。
TIMESTAMPDIFF 根据两个时间戳记之间的时差,返回由第一个参数定义的类型表示的估计时差。
TO_CHAR 返回已用字符模板进行格式化的时间戳记的字符表示。TO_CHAR 是 VARCHAR_FORMAT 的同义词。
TO_DATE 从已使用字符模板解释过的字符串返回时间戳记。TO_DATE 是 TIMESTAMP_FORMAT 的同义词。
WEEK 返回参数中一年的第几周,用范围在 1-54 的整数值表示。以星期日作为一周的开始。
WEEK_ISO 返回参数中一年的第几周,用范围在 1-53 的整数值表示。
myfriend2010 发表于:2007.11.12 11:09 ::分类: (db2 ) ::阅读:(705次) ::评论 (0)
===========================================================
DB2锁介绍[转]
===========================================================
1 DB2 多粒度封锁机制介绍
1.1 锁的对象
DB2支持对表空间、表、行和索引加锁(大型机上的数据库还可以支持对数据页加锁)来保证数据库的并发完整性。不过在考虑用户应用程序的并发性的问题上,通常并不检查用于表空间和索引的锁。该类问题分析的焦点在于表锁和行锁。
1.2 锁的策略
DB2可以只对表进行加锁,也可以对表和表中的行进行加锁。如果只对表进行加锁,则表中所有的行都受到同等程度的影响。如果加锁的范围针对于表及下属的行,则在对表加锁后,相应的数据行上还要加锁。究竟应用程序是对表加行锁还是同时加表锁和行锁,是由应用程序执行的命令和系统的隔离级别确定。
1.2.1 DB2表锁的模式
DB2在表一级加锁可以使用以下加锁方式:
名称缩写 全名 描述
IN 无意图锁 (Intenet None)
不需要行锁 该锁的拥有者可以读表中的任何数据,包括其他事务尚未提交的数据,但不能对表中的数据进行更改。
IS 意图共享锁(Intent Share)需要行锁配合 该锁的拥有者在拥有相应行的上的S锁时可以读取该行的数据。但不能对表中的数据进行更改。
IX 意图排它锁(Intent eXclusive)需要行锁配合 该锁的拥有者在拥有相应行的X锁时可以更改该行的数据。
SIX 共享携意图排它锁
(Share with Intent exclusive)需要行锁配合 锁的拥有者可以读表中的任何数据,如果在相应的行上能够获得X锁,则可以修改该行。SIX锁的获得比较特殊,它是在应用程序已经拥有IX锁的情况下请求S锁或者是在应用程序已经拥有S锁的情况下请求IX锁时生成的。
S 共享锁(Share)不需要行锁配合 锁的拥有者可以读表中的任何数据,如果表上被加上S锁,该表中的数据就只能被读取,不能被改变。
U 更新锁(Update)
不需要行锁配合 锁的拥有者可以读表中的任何数据,如果在升级到X锁之后,可以更改表中的任何数据。该锁是处于等待对数据进行更改的一种中间状态。
X 排它锁
(eXclusive)
不需要行锁配合 锁的拥有者可以读取或更改表中的任何数据。如果对表加上X锁,除了未提交读程序,其他应用程序都不能对该表进行存取。
Z 超级排它锁
(Super Exclusive)
不需要行锁配合 该锁不是通过应用程序中的DML语言来生成的。一般是通过对表进行删除(Drop)和转换(Alter)操作或创建和删除索引而获得的。如果对表上加上Z锁,其他应用程序,包括未提交读程序都不能对该表进行存取。
表三:DB2数据库表锁的模式
下面对几种表锁的模式进一步加以阐述:
IS、IX、SIX方式用于表一级并需要行锁配合,他们可以阻止其他应用程序对该表加上排它锁。
如果一个应用程序获得某表的IS锁,该应用程序可获得某一行上的S锁,用于只读操作,同时其他应用程序也可以读取该行,或是对表中的其他行进行更改。
如果一个应用程序获得某表的IX锁,该应用程序可获得某一行上的X锁,用于更改操作,同时其他应用程序可以读取或更改表中的其他行。
如果一个应用程序获得某表的SIX锁,该应用程序可以获得某一行上的X锁,用于更改操作,同时其他应用程序只能对表中其他行进行只读操作。
S、U、X和Z方式用于表一级,但并不需要行锁配合,是比较严格的表加锁策略。
如果一个应用程序得到某表的S锁。该应用程序可以读表中的任何数据。同时它允许其他应用程序获得该表上的只读请求锁。如果有应用程序需要更改读该表上的数据,必须等S锁被释放。
如果一个应用程序得到某表的U锁,该应用程序可以读表中的任何数据,并最终可以通过获得表上的X锁来得到对表中任何数据的修改权。其他应用程序只能读取该表中的数据。U锁与S锁的区别主要在于更改的意图上。U锁的设计主要是为了避免两个应用程序在拥有S锁的情况下同时申请X锁而造成死锁的。
如果一个应用程序得到某表上的X锁,该应用程序可以读或修改表中的任何数据。其他应用程序不能对该表进行读或者更改操作。
如果一个应用程序得到某表上的Z锁,该应用程序可以读或修改表中的任何数据。其他应用程序,包括未提交读程序都不能对该表进行读或者更改操作。
IN锁用于表上以允许未提交读这一概念。
1.2.2 DB2行锁的模式
除了表锁之外,DB2还支持以下几种方式的行锁。
名称缩写 全名 需要表锁的最低级别 描述
S 共享锁
(Share) IS 该行正在被某个应用程序读取,其他应用程序只能对该行进行读操作。
U 更改锁
(Update) IX 某个应用程序正在读该行并有可能更改该行,其他应用程序只能读该行。
X 排它锁
(eXclusive) IX 该行正在被某个应用程序更改,其他应用程序不能访问该行。
W 弱排它锁
(Weak eXclusive) IX 当一行数据被插入表中的时候,该行上会被加上W锁。锁的拥有者能够更改该行,该锁基本与X锁相同,除了它与NW锁兼容。
NS 下一键共享锁
(Next Key Share) IS 锁的拥有者和其他程序都可以读该行,但不能对该行进行更改。当应用程序处于RS或CS隔离级下,该锁用来替代S锁。
NX 下一键排它锁
(Next Key eXclusive) IX 当一行数据被插入到索引中或从索引中被删除的时候,该行的下一行上会被加上该锁。锁的拥有者可以读,但不能更改锁定行。该锁与X锁类似,只是与NS锁兼容。
NW 下一键弱排它锁
(Next Key Weak eXclusive) IX 当一行被插入到索引中的时候,该行的下一行会被加上该锁。锁的拥有者可以读但不能更改锁定行。该锁与X和NX锁类似,只是与W和NS锁兼容。
表四:DB2数据库行锁的模式
DB2锁的兼容性
锁A的模式 锁B的模式
IN IS S IX SIX U X Z
IN Y Y Y Y Y Y Y N
IS Y Y Y Y Y Y N N
S Y Y Y N N Y N N
IX Y Y N Y N N N N
SIX Y Y N N N N N N
U Y Y Y N N N N N
X Y N N N N N N N
Z N N N N N N N N
表五:DB2数据库表锁的相容矩阵
锁A的模式 锁B的模式
S U X W NS NX NW
S Y Y N N Y N N
U Y N N N Y N N
X N N N N N N N
W N N N N N N Y
NS Y Y N N Y Y Y
NX N N N N Y N N
NW N N N Y Y N N
表六:DB2数据库行锁的相容矩阵
下表是笔者总结了DB2中各SQL语句产生表锁的情况(假设缺省的隔离级别为CS):
SQL语句 行锁
模式 表锁
模式 允许的锁模式
Select * from table_name for read only with rr.. 无 S IN,IS,S,U
Select * from table_name for read only with rs.. NS IS IN,IS,S,SIX,U
Select * from table_name for read only with cs.. 无 无
Select * from table_name for read only with ur.. 无 无
Select * from table_name for update with rr 无 U IN,IS,S
Select * from table_name for update with rs U IX IN,IS,IX
Select * from table_name for update with cs U IX IN,IS,IX
Select * from table_name for update with ur U IX IN,IS,IX
Insert into table_name…… W IX IN,IS,IX
Update table_name…… X IX IN,IS,IX
Delete from table_name…… X IX IN,IS,IX
lock table table_name in share mode 无 S IN,IS,S,U
lock table table_name in exclusive mode 无 X IN
Alter table t1 add column id int Z
Drop table t1 X Z
Create table t1(id int) Z
注:alter,create,drop会在syscolumns,systables,systablespaces,sysuserath等数据字典系统表中加行级锁。
1.3 DB2锁的升级
每个锁在内存中都需要一定的内存空间,为了减少锁需要的内存开销,DB2提供了锁升级的功能。锁升级是通过对表加上非意图性的表锁,同时释放行锁来减少锁的数目,从而达到减少锁需要的内存开销的目的。锁升级是由数据库管理器自动完成的,有两个数据库的配置参数直接影响锁升级的处理:
locklist—在一个数据库全局内存中用于锁存储的内存。单位为页(4K)。
maxlocks—一个应用程序允许得到的锁占用的内存所占locklist大小的百分比。
锁升级会在这两种情况下被触发:
某个应用程序请求的锁所占用的内存空间超出了maxlocks与locklist的乘积大小。这时,数据库管理器将试图通过为提出锁请求的应用程序申请表锁,并释放行锁来节省空间。
在一个数据库中已被加上的全部锁所占的内存空间超出了locklist定义的大小。这时,数据库管理器也将试图通过为提出锁请求的应用程序申请表锁,并释放行锁来节省空间。
锁升级是有可能会失败的,比如,现在一个应用程序已经在一个表上加有IX锁,表中的某些行上加有X锁,另一个应用程序又来请求表上的IS锁,以及很多行上的S锁,由于申请的锁数目过多引起锁的升级。数据库管理器试图为该应用程序申请表上的S锁来减少所需要的锁的数目,但S锁与表上原有的IX锁冲突,锁升级不能成功。
如果锁升级失败,引起锁升级的应用程序将接到一个-912的SQLCODE。
myfriend2010 发表于:2007.11.08 17:26 ::分类: (db2 ) ::阅读:(1164次) ::评论 (0)
===========================================================
如何降低DB2的管理表空间的高水位标记
===========================================================
本文介绍如何通过使用 DB2DART 工具降低 DB2 数据库管理表空间的高水位标记。
对于 DB2 数据库管理(DMS)表空间的高水位标记(HWM)是指该表空间曾经使用到的最大数据页数。如果使用:
db2 list tablespaces show detail
看到某个 DMS 表空间的已用页数低于高水位标记,则有可能通过如下方法降低高水位标记:
1、重组表空间的某个表;
2、将某个表中的数据导出,然后将它删除,重新创建该表再将数据导入。
在以上的方法中,首先要找到持有高水位标记的那个表,这可通过 DB2DART 命令(在停止实例后方可使用)加上 /DHWM 选项,提供表空间标识,然后从命令所产生的报告文件中获得。
而要了解通过对该表进行哪些操作可降低 HWM 的建议,可使用 DB2DART 加上 /LHWM 选项,从产生的报告文件中获得。使用 /LHWM 选项时,要求用户给出表空间的标识以及希望 HWM 降低到的页数(虽然不能保证 HWM 一定能降低到这一用户期望值),如果该值使用 0,则表明由 DB2 将 HWM 降低到能够达到的最低值。
另外还可利用 DB2DART 加 /RHWM 选项来移去 DMS 表空间中不再需要的空间映射数据块来降低 HWM,这些空间映射数据块在其映射的数据被删除时是不会被删除的
附:db2dart 使用方法
1.db2dart xx /db (xx为数据库名)
2.db2dart xx /DHWM /RPT c: (需要根据提示输入表空间号)
3.db2dart xx /RHWM(需要根据提示输入表空间号)
myfriend2010 发表于:2007.11.03 11:40 ::分类: (db2 ) ::阅读:(634次) ::评论 (1)
===========================================================
Windows上DB2 UDB脚本编制简介3
===========================================================
另一个可以用 Windows shell 和 DB2 命令迅速进行脚本编制的任务是相关系统、实例和数据库信息的收集。我们可以收集系统资源、DB2 注册表变量、实例和数据库配置参数以及数据库资源利用情况的快照。在开始对数据库系统作出更改之前,有这样一个脚本始终是很方便的。
清单 9. DB2 获取配置信息的脚本(db2getconf.bat)
@echo off ::---------------------------------------------------------------------------:: :: This is a Windows Shell Script to collect DB2 system information. The :: information collected is stored in a file name with the following format: :: ..YYYYMMDD.HHMMSS.rpt ::---------------------------------------------------------------------------:: set script_name=%~n0 set script_log=%~n0.log set script_ver=1.0 set DB2INSTANCE=DB2 set DB2DATABASE=SAMPLE title %script_name% v%script_ver% echo %script_name% v%script_ver% started on %date% at %time% ::---------------------------------------------------------------------------:: :: Set Script Date Variable ::---------------------------------------------------------------------------:: for /F "tokens=1-4 delims=/ " %%i in ('echo %date%') do ( set script_date=%%l%%j%%k ) ::---------------------------------------------------------------------------:: :: Set Script Time Variable ::---------------------------------------------------------------------------:: for /F "tokens=1-4 delims=:. " %%i in ('echo %time%') do ( set script_time=%%i%%j%%k ) ::---------------------------------------------------------------------------:: :: Set Script Report File ::---------------------------------------------------------------------------:: set script_rpt=%db2instance%.%db2database%.%script_date%.%script_time%.rpt ::---------------------------------------------------------------------------:: :: Collect DB2 Services Configuration (Requires Windows Resource Kit) ::---------------------------------------------------------------------------:: echo %script_name% v%script_ver% collecting DB2 Services configuration... echo DB2 Services Configuration > %script_rpt% srvinfo | find "DB2" >> %script_rpt% 2> %script_log% if not %errorlevel% == 0 ( echo ERROR: Unable to collect DB2 Services data, RC=%errorlevel% type %script_log% ) ::---------------------------------------------------------------------------:: :: Collect DB2 Registry Configuration ::---------------------------------------------------------------------------:: echo %script_name% v%script_ver% collecting DB2 Registry configuration... echo DB2 Registry Configuration >> %script_rpt% db2set -all >> %script_rpt% 2> %script_log% if not %errorlevel% == 0 ( echo ERROR: Unable to collect DB2 Registry data, RC=%errorlevel% type %script_log% ) ::---------------------------------------------------------------------------:: :: Collect DB2 Database Administration Server (DB2DAS00) Configuration ::---------------------------------------------------------------------------:: echo %script_name% v%script_ver% collecting DB2DAS00 instance configuration... db2 get admin cfg >> %script_rpt% 2> %script_log% if not %errorlevel% == 0 ( echo ERROR: Unable to collect DB2DAS00 instance data, RC=%errorlevel% type %script_log% ) ::---------------------------------------------------------------------------:: :: Collect DB2 Instance Configuration ::---------------------------------------------------------------------------:: echo %script_name% v%script_ver% collecting %DB2INSTANCE% instance configuration... db2 get dbm cfg >> %script_rpt% 2> %script_log% if not %errorlevel% == 0 ( echo ERROR: Unable to collect %DB2INSTANCE% instance data, RC=%errorlevel% type %script_log% ) ::---------------------------------------------------------------------------:: :: Collect DB2 Database Configuration ::---------------------------------------------------------------------------:: echo %script_name% v%script_ver% collecting %DB2DATABASE% database configuration... db2 get db cfg for sample >> %script_rpt% 2> %script_log% if not %errorlevel% == 0 ( echo ERROR: Unable to collect %DB2DATABASE% database data, RC=%errorlevel% type %script_log% ) db2 connect to %DB2DATABASE% if not %errorlevel% == 0 ( echo ERROR: Unable to connect to %DB2DATABASE% database, RC=%errorlevel% type %script_log% ) db2 "select BUFFERPOOLID, BPNAME, NPAGES from SYSCAT.BUFFERPOOLS" >> %script_rpt% 2> %script_log% if not %errorlevel% == 0 ( echo ERROR: Unable to collect %DB2DATABASE% database bufferpool data, RC=%errorlevel% type %script_log% ) db2 list tablespaces show detail >> %script_rpt% 2> %script_log% if not %errorlevel% == 0 ( echo ERROR: Unable to collect %DB2DATABASE% database tablespace data, RC=%errorlevel% type %script_log% ) db2 connect reset if not %errorlevel% == 0 ( echo ERROR: Unable to reset connection from %DB2DATABASE% database, RC=%errorlevel% type %script_log% ) echo %script_name% v%script_ver% completed on %date% at %time%
您甚至可以将这些信息存储在数据库的表中,这样这些信息就与数据库备份镜像保存在一起。定期地维护这些系统信息的历史记录可以为以后进行容量规划提供极有价值的帮助。
现在让我们看一个 DB2 系统命令的较好示例,该命令在用脚本语言进行自动化时非常有用。DB2 审计工具是一个实用程序,可以利用它充分地增强 DB2 实例和数据库安全性审计。它由名为 db2audit.exe 的 DB2 系统命令完全管理和控制。该命令使您能够全面地实现非常严格的 DB2 UDB 安全性审计实践。您可以配置、启动和停止安全性审计,并可以从该工具清除和抽取审计数据。这个过程是非常耗时的日常工作,但很容易用脚本语言使其自动化。例如,在您配置并启动 DB2 审计工具之后,您也许希望创建并调度一个脚本以定期地清除审计数据并将审计数据抽取到报告文件中。
@echo off ::---------------------------------------------------------------------------:: :: This is a Windows Shell Script to collect DB2 Audit Facility information. :: You must first start the DB2 Audit Facility (db2audit start) and optionally :: configure scope and status (db2audit configure scope all status both). It :: flushes and extracts the audit data to the default DB2 Audit Facility :: directory (sqllibsecurity and then and renames the extracted :: files to db2audit.YYYYDDMM.HHMMSS.rpt and prunes the DB2 Audit Log. ::---------------------------------------------------------------------------:: set script_name=%~n0 set script_log=%~n0.log set script_ver=1.0 set DB2INSTANCE=DB2 set DB2DATABASE=SAMPLE title %script_name% v%script_ver% echo %script_name% v%script_ver% started on %date% at %time% ::---------------------------------------------------------------------------:: :: Set Script Date Variable ::---------------------------------------------------------------------------:: for /F "tokens=1-4 delims=/ " %%i in ('echo %date%') do ( set script_date=%%l%%j%%k set prune_date=%%l%%j%%k ) ::---------------------------------------------------------------------------:: :: Set Script Time Variable ::---------------------------------------------------------------------------:: for /F "tokens=1-4 delims=:. " %%i in ('echo %time%') do ( set script_time=%%i%%j%%k set prune_hour=%%i ) ::---------------------------------------------------------------------------:: :: Set DB2 Path Variable, DB2 Audit Path, and DB2 Audit Log ::---------------------------------------------------------------------------:: if not defined db2path ( for /F %%i in ('db2set db2path') do (set db2path=%%i) echo %script_name% v%script_ver% set db2path to %db2path% ) set db2audit_path=%db2path%%db2instance%SECURITY echo %script_name% v%script_ver% set db2audit_path to %db2audit_path% set db2audit_file=%db2audit_path%db2audit.log echo %script_name% v%script_ver% set db2audit_log to %db2audit_file% ::---------------------------------------------------------------------------:: :: Flush DB2 Audit Data to Log File ::---------------------------------------------------------------------------:: echo %script_name% v%script_ver% flushing data to db2audit.log... db2audit.exe flush 2> %script_log% if not %errorlevel% == 0 ( echo ERROR: Unable to flush db2 audit data to log, RC=%errorlevel% type %script_log% ) ::---------------------------------------------------------------------------:: :: Extract DB2 Audit Data from Log File ::---------------------------------------------------------------------------:: echo %script_name% v%script_ver% extracting data from db2audit.log... db2audit.exe extract 2> %script_log% if not %errorlevel% == 0 ( echo ERROR: Unable to extract db2 audit data from log, RC=%errorlevel% type %script_log% ) ::---------------------------------------------------------------------------:: :: Rename DB2 Audit Out File (db2audit.YYYYMMDD.HHMMSS.rpt) ::---------------------------------------------------------------------------:: echo %script_name% v%script_ver% renaming db2audit.out file... ren %db2audit_path%*.out *.%script_date%.%script_time%.rpt 2> %script_log% if not %errorlevel% == 0 ( echo ERROR: Unable to rename db2 audit out file, RC=%errorlevel% type %script_log% ) ::---------------------------------------------------------------------------:: :: Prune DB2 Audit Log File ::---------------------------------------------------------------------------:: echo %script_name% v%script_ver% pruning db2audit.log file... db2audit.exe prune date %prune_date%%prune_hour% 2> %script_log% if not %errorlevel% == 0 ( echo ERROR: Unable to prune db2 audit file, RC=%errorlevel% type %script_log% ) echo %script_name% v%script_ver% completed on %date% at %time%
然后可以将数据导入或装入到安全性审计数据库,该数据库可以通过触发器和/或存储过程将警报通知自动转发给相应的管理员。
在本文中,我们已经知道正确维护 DB2 UDB 系统所需的全部管理任务如何依赖于 DB2 管理 API,还知道了如何使用 DB2 命令行工具和 DB2 系统命令从命令行界面执行数据库管理任务。我们演示了如何在 Windows shell 脚本中组合 DB2 命令、DB2 系统命令和操作系统命令,以便使其中的许多任务自动化。
myfriend2010 发表于:2007.10.30 16:18 ::分类: (db2 ) ::阅读:(758次) ::评论 (0)
===========================================================
Windows上DB2 UDB脚本编制简介2
===========================================================
可以将一些 DB2 系统命令编制成脚本以便简单地使它们已经提供的功能自动化。DB2 审计工具(db2audit.exe)就是可以通过脚本编制实现自动化的实用程序的典型示例。另一些 DB2 系统命令在单独使用时作用并不大,但与其它 DB2 命令或操作系统命令结合起来就非常有用。我将在本文的脚本编制方案一节向您演示一些示例。
Windows shell 脚本编制环境经过了很长时间的发展,它最初是早期 Windows 操作系统上的简单批处理文件。对于需要用到 Window shell 命令或者带命令行界面的其它程序的任务而言,Windows shell 脚本是调度和自动化这些任务的理想工具。
Windows shell 是自动化 DB2 UDB 管理任务方面引人注目的脚本编制环境,原因如下。第一,Windows shell 集成在 Windows 操作系统中,这使得它可用于所有版本的 Windows 客户机与服务器。第二,Windows shell 脚本编制相对较简单,使它易于实现。这使您可以专注地完成当前的任务。最后,介绍Windows shell 脚本编制的书籍、手册和参考资料有很多。
Windows shell 脚本编制环境提供:
有条件的命令执行 标准输入、输出和错误 命令行参数 环境和系统变量 局部和全局变量名 字符串和数值变量 算术运算符(+、-、*、/ 和 %) 字符串、子串和替换 条件语句(if、if else、if not 和 if defined) 迭代处理(范围、元素、文件和目录) 子例程链接和嵌套(GOTO 和 CALL) 驱动器和文件夹定位(pushd 和 popd)
除了这些特性之外,还可以通过使用 Windows 资源包提供的系统实用程序,进一步增强 Windows shell 脚本。 表 5列出了其中的一些实用程序。有关 Windows 资源包的更多信息,请在www.microsoft.com/windows/reskits访问 Windows Deployment and Resource Kits 主页。
命令 描述
choice 通过显示提示并等待用户从一组键中选择,在批处理程序中提示用户作出选择。只能在批处理程序中使用该命令。
timethis 测量系统运行给定命令所花的时间。
logtime 记录批处理文件中命令行程序的启动或完成。这在对批处理作业(如邮件地址导入)计时和跟踪时很有用。
Uptime 通过处理事件日志分析单一服务器以确定可靠性、可用性和当前运行时间。目标系统可以是本地系统,也可以是远程系统。
logevent 该工具使您能通过命令提示符或批处理文件在本地或远程计算机上的事件日志中记录事件项。
netsvc 您可以使用该工具从命令行远程启动、停止、暂停、继续和查询服务的状态。
Windows shell 脚本的最简单形式是包含一条或多条命令的文本文件。Windows shell 脚本的缺省文件扩展名是 .bat 和 .cmd 。 清单2是一个简单 Windows shell 脚本的示例。
@echo off rem rem This is a sample Windows Shell script. rem echo Hello World!
从 Windows shell 脚本调用 DB2 命令有两个基本方法:
从 Wshell 脚本调用 DB2 命令窗口 从 DB2 命令窗口运行 Wshell 脚本
清单3是一个使用 DB2 CLP 备份 sample 数据库的样本 Windows shell 脚本。该文件无需在 DB2 命令窗口中执行,因为它调用一个 DB2 命令窗口,然后将 DB2 备份数据库命令传递给它。环境变量 DB2INSTANCE 的值将缺省实例设置为“DB2”,也可以用 DB2 ATTACH 命令替换这个值。我将在后面向您演示这一点。
提示:因为 Windows shell 不支持指定的命令行参数,但我们可以用任意顺序将这些参数传递给脚本,所以将这些值显式地定义为脚本内的全局或局部变量是较常见的做法。
@echo off rem rem This is a Windows Shell Script that invokes a DB2 Command Window that rem performs a database backup by calling the DB2 backup database command. rem set DB2INSTANCE=DB2 set DB2DATABASE=SAMPLE title Starting database backup of %DB2DATABASE% on %date% at %time%... DB2CMD.EXE -c -w -i DB2 BACKUP DATABASE %DB2DATABASE% if not %errorlevel% == 0 ( echo Database backup of %DB2DATABASE% failed, RC=%errorlevel% ) else ( echo Database backup of %DB2DATABASE% completed on %date% at %time%. )
从 shell 脚本内执行 DB2 命令窗口的优点是您不必从 DB2 命令窗口内执行 shell 脚本。该方法的缺点是每次调用 DB2 命令窗口时只能运行一条 DB2 命令。可以通过在单独的 DB2 脚本中放置数条 DB2 命令的方法绕开这一限制,并使用 -tf 开关执行 DB2 脚本,如 清单4所示。
清单4也是一个使用 DB2 CLP 备份 sample 数据库的 Windows shell 脚本。该文件无需在 DB2 命令窗口中执行,因为它调用一个 DB2 命令窗口,然后将包含多条 DB2 命令(包括备份数据库命令)的 DB2 脚本( db2backup.db2 ,如 清单5所示)传递给该命令窗口。
@echo off rem rem This is a Windows Shell Script that invokes a DB2 Command Window that rem performs a database backup by calling the DB2 backup database command rem located in a db2 script file (db2backup.db2). rem set DB2INSTANCE=DB2 set DB2DATABASE=SAMPLE title Starting database backup of %DB2DATABASE% on %date% at %time%... DB2CMD.EXE -c -w -i DB2 -tf db2backup.db2 -l db2backup.log -r db2backup.rpt if not %errorlevel% == 0 ( echo Database backup of %DB2DATABASE% failed, RC=%errorlevel% ) else ( echo Database backup of %DB2DATABASE% completed on %date% at %time%. )
清单5显示了由 清单4中的 Windows shell 脚本执行的 DB2 脚本。
-- -- This is a sample DB2 Backup Script -- ATTACH TO DB2; BACKUP DATABASE SAMPLE; DETACH; TERMINATE;
从 DB2 命令窗口内执行 Windows shell 脚本的优点是您可以在该 shell 脚本内调用多条 DB2 命令,而不必将它们置于单独的脚本中。这使您对每条单独的 DB2 命令有更好的执行控制。该方法的缺点是 shell 脚本的执行必须在 DB2 命令窗口内进行。通过从任一调度程序(包括 DB2 任务中心)执行 DB2 命令窗口并将 Windows shell 脚本传递给该窗口,就可以绕开这一限制,方法如下所示:
db2cmd.exe -c -w -i db2backup4.bat
在这一示例中,当 DB2 命令窗口退出时,调度程序将收到最终的返回码。
清单6是一个使用 DB2 backup database 命令备份 sample 数据库的样本 Windows shell 脚本。必须从 DB2 命令窗口内调用该脚本。
@echo off: :---------------------------------------------------------------------------:: :: This is a Windows Shell Script that must be run inside a DB2 Command:: Window (db2cmd). ::---------------------------------------------------------------------------:: set SCRIPT_NAME=%~n0 set SCRIPT_VER=1.0 set DB2INSTANCE=DB2 set DB2DATABASE=SAMPLE title %SCRIPT_NAME% v%SCRIPT_VER% echo Starting database backup of %DB2DATABASE% on %date% at %time%... DB2 BACKUP DATABASE SAMPLE if not %errorlevel% == 0 ( echo Database backup of %DB2DATABASE% failed, RC=%errorlevel% ) else ( echo Database backup of %DB2DATABASE% completed on %date% at %time%. )
如果您已经安装了 Windows 资源包,您可以按清单 7 所示更改脚本。这个版本的脚本使用 logevent 实用程序将信息和错误消息写到 Windows 事件日志而不是写到标准输出。
@echo off ::---------------------------------------------------------------------------:: :: This is a Windows Shell Script that must be run inside a DB2 Command :: Window (db2cmd). It uses the logevent utility from the Windows Resource :: Kit to log information and error messages. ::---------------------------------------------------------------------------:: set SCRIPT_NAME=%~n0 set SCRIPT_VER=1.0 set DB2INSTANCE=DB2 set DB2DATABASE=SAMPLE title %SCRIPT_NAME% v%SCRIPT_VER% ::---------------------------------------------------------------------------:: :: Backup Database (Requires Windows Resource Kit) ::---------------------------------------------------------------------------:: echo Starting database backup of %DB2DATABASE% on %date% at %time%... logevent -s I -r %script_name% "Starting database backup of %DB2DATABASE% on %date% at %time%... "DB2 BACKUP DATABASE %DB2DATABASE% if %errorlevel% == 0 ( echo Database backup of %DB2DATABASE% failed, RC=% errorlevel% logevent -s I -r %script_name% "Database backup of %DB2DATABASE% failed, RC=%errorlevel% " ) else ( echo Database backup of %DB2DATABASE% completed on %date% at %time%. logevent -s E -r %script_name% "Database backup of %DB2DATABASE% completed on %date% at %time%." )
DB2 任务中心提供了用于调度作业的图形用户界面。该工具在 DB2 UDB V8.1 中已得到了显著的增强。它提供了创建新任务的向导,新任务可以是 DB2 脚本、操作系统脚本、MVS shell 脚本和 JCL 脚本。
和 DB2 命令中心一样,可以从文件导入脚本。DB2 任务中心允许您调度任务以使其在本地运行或在另一个 DB2 UDB 系统上远程运行。您可以定义任务完成时的定制返回码,还可以在发生故障时停止任务。您可以定义在任务成功或失败时要通知的联系人名单。DB2 任务中心还允许您按照图4所示的类别对任务进行分组,图 4 显示我们已经为导入的样本 DB2 备份脚本(清单1)创建了 DB2 Maintenance 类别。
560)this.style.width=560;" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dw="http://www.ibm.com/developerworks/" />
在 Windows 上,可以用以下任一方法启动 DB2 任务中心:
Start -> Program -> IBM DB2 -> General Administration Tools -> Task Center 在 Windows shell 中输入命令 db2tc 直接从 DB2 控制中心启动
既然您已经了解 DB2 UDB 如何提供用于脚本编制的接口,并且知道如何从 Windows shell 访问这些接口以及如何用 DB2 任务中心调度脚本,那么让我们看几个可以用脚本使任务自动化的方案。这些方案包括当前没有自动化的任务,以及需要组合多种命令的任务,它们包括 DB2 命令、DB2 系统命令、操作系统特定命令和/或只能通过 DB2 系统命令使用的特性。让我们看看下面的示例:
归档诊断日志 收集 DB2 UDB 系统信息 DB2 UDB 安全性和审计
可以用简单的 Windows Shell 脚本自动化的最简单任务之一是定期归档 DB2 诊断日志。每个 DB2 实例都使用 DB2 诊断日志文件编写与实例及实例内全部数据库相关的诊断信息。写入日志的信息的数量由实例配置参数 DIAGLEVEL 控制。将 DIAGLEVEL 设置成最高级别四(4)可以在问题确定期间提供极有价值的大量信息。但是,在这一级别,DB2 诊断日志很快会增长为吉字节大小的文件。
目前,DB2 不提供任何自动归档或修剪 DB2 诊断日志的工具。管理 DB2 诊断日志文件的策略之一是定期归档 DB2 诊断日志并使这些归档文件在一定的天数内随时可用。在给定的天数过后,就可以删除归档文件,因为已经在定期的系统备份期间将它备份到磁带上了。使用 Windows shell 脚本可以轻松地完成这一任务,如 清单8所示。
@echo off ::---------------------------------------------------------------------------:: :: This is a Windows Shell Script to archive the db2 diagnostic log file. It :: assumes the db2diag.log file is in the default diagnostic log directory :: and renames it to db2diag.YYYYMMDD.log It also deletes all but the last :: seven (7) of these diagnostic log archives. ::---------------------------------------------------------------------------:: set script_name=%~n0 set script_log=%~n0.log set script_ver=1.0 set DB2INSTANCE=DB2 set DB2DATABASE=SAMPLE title %script_name% v%script_ver% echo %script_name% v%script_ver% started on %date% at %time% ::---------------------------------------------------------------------------:: :: Set Script Date Variable ::---------------------------------------------------------------------------:: for /F "tokens=1-4 delims=/ " %%i in ('date /t') do ( set script_date=%%l%%j%%k ) ::---------------------------------------------------------------------------:: :: Set DB2 Path Variable ::---------------------------------------------------------------------------:: if not defined db2path ( for /F %%i in ('db2set db2path') do (set db2path=%%i) echo %script_name% v%script_ver% set db2path as %db2path% ) set db2diag_path=%db2path%%db2instance% echo %script_name% v%script_ver% set db2diag_path to %db2diag_path% set db2diag_file=%db2diag_path%db2diag.log echo %script_name% v%script_ver% set db2diag_file to %db2diag_file% ::---------------------------------------------------------------------------:: :: Archive DB2 Diagnostic Log File ::---------------------------------------------------------------------------:: echo %script_name% v%script_ver% archiving %db2diag_file% to db2diag.%script_date%.log ren %db2diag_file% db2diag.%script_date%.log 2> %script_log% if not %errorlevel% == 0 ( echo ERROR: Unable to archive %db2diag_file% to db2diag.%script_date%.log, RC=%errorlevel% type %script_log% ) ::---------------------------------------------------------------------------:: :: Delete DB2 Diagnostic Log Archives 7 days or older ::---------------------------------------------------------------------------:: set db2diag_arch=%db2diag_path%db2diag.*.log for /f "skip=7" %%i in ('dir %db2diag_arch% /b /o:-n') do ( echo %script_name% v%script_ver% purging %%i del %db2diag_path%%%i 2> %script_log% if not %errorlevel% == 0 ( echo ERROR: Unable to delete archive %%i, RC=%errorlevel% type %script_log% ) ) echo %script_name% v%script_ver% completed on %date% at %time%
以上 Windows shell 脚本假定 db2diag.log 文件位于缺省的 DB2 DIAGPATH 中,并根据脚本的执行日期将该文件归档(重命名)为 db2diag. YYYYMMDD.log 。然后,它删除七天或更旧的所有 db2diag. YYYYMMDD.log 文件。
myfriend2010 发表于:2007.10.30 16:16 ::分类: (db2 ) ::阅读:(787次) ::评论 (0)
===========================================================
Windows上DB2 UDB脚本编制简介
===========================================================
除了提供对结构化查询语言(Structure Query Language,SQL)的支持外,IBM® DB2® Universal Database™ 还提供一组丰富且广泛的管理应用程序编程接口(API)。因为正确维护 DB2 UDB 系统所需的所有日常任务都依靠 DB2 管理 API,所以这些 API 就为 DB2 UDB 的管理提供了一个编程接口。
例如,DB2 控制中心(Control Center)就是一个调用 DB2 管理 API 来执行 DB2 系统、实例和数据库管理任务的基于 Java 的图形用户界面(GUI)工具。DB2 UDB 还提供了象 DB2 CLP 这样的命令行工具来执行类似任务,这些工具也调用 DB2 管理 API。
除了 DB2 UDB 命令行工具,DB2 通用数据库还提供一组丰富的系统实用程序,称为 DB2 系统命令。这些命令通常被用来执行尚未集成到 GUI 工具的任务。通常从操作系统的 shell(如 Windows shell — Wshell),也称为命令提示符,调用 DB2 UDB 系统命令。
您可以在几乎所有的脚本语言(从简单的 Windows shell 脚本到用 JScript、VBScript、Object REXX 或 PerlScript 编写的较复杂脚本)中将 SQL、DB2 命令、DB2 UDB 系统命令和操作系统命令结合起来,以便使简单重复的任务自动化或调度这些任务,从而形成更复杂的任务或您能想到的任何 DB2 管理任务。
一般说来, 脚本(scripting)指的是一种被解释的语言。脚本在文本文件中创建,执行后编译成汇编程序或字节代码。Windows 提供了几种环境,它们可用于执行脚本编制语言。其中,执行系统管理任务最常用的两个环境是 Windows shell(Wshell)和 Windows Scripting Host(WSH)。
本文描述在 Windows 平台上可用于 DB2 UDB 的几种不同的脚本编制接口,首先将概述 DB2 管理 API、DB2 命令行工具和 DB2 系统命令。我将向您介绍用 Windows shell 编制 DB2 UDB 脚本的最佳技术,并提供可从本网站下载的几个有用示例。
作为 DB2 UDB for Linux、UNIX® 和 Windows 的一部分,DB2 管理 API 一直包含在 DB2 UDB 中,有文档记录并得到支持。随着 DB2 UDB 不断提供其它功能,如分割镜像(Split Mirror Images),API 集也随之继续扩展以支持这些特性。用这些 API 编程的样本源代码也和 DB2 UDB 的开发者版本一起提供。
DB2 管理 API 正式支持以下编程语言:
C/C++ COBOL Fortran REXX
由于象 Java、Perl 和 Visual Basic 这样的编程语言(随便列举几个)不断涌现,所以这份列表可能乍一看显得相当短。但是,大多数编程语言都可以调用用其它语言编写的 API,其中 C API 受到最普遍的支持。除了可以通过 C、COBOL、FORTRAN 和 REXX 直接访问 DB2 管理 API 之外,还可以通过其它方法间接访问这些 API,譬如通过 Java 本机接口(Java Native Interface,JNI)。事实上,现今与 DB2 UDB 一起提供的 DB2 管理工具几乎全都是用 Java 编写的,而 Java 却不在 DB2 管理 API 正式支持的编程语言的简短列表上。DB2 控制中心使用 IBM 开发的 Java 本机接口(JNI)访问这些 API。
对于那些不能直接访问 DB2 管理 API 的编程语言和脚本语言(如 VBScript、Jscript 和 Perl),还有另一种方法。DB2 CLP 作为命令行界面,可通过 DB2 命令(DB2 Command)提供对几乎所有 DB2 管理 API 功能的间接访问。
DB2 UDB 命令行工具是 DB2 UDB 的组件,这些工具支持对 DB2 命令以及 SQL 语句的处理。在 Windows 上可使用三种命令行工具:
DB2 命令中心(Command Center) DB2 命令行处理器(CLP) DB2 命令窗口
您可以通过单击 Start -> Programs -> IBM DB2 -> Command Line Tools找到这些工具。
第一个命令行工具是 DB2 命令中心(图1),它提供一个处理命令和 SQL 语句的 GUI。您可以用交互方式或脚本(批处理)方式工作,或者将两种方式结合使用。通过单击 Start -> Programs -> IBM DB2 -> Command Line Tools -> Command Center启动 DB2 命令中心。
560)this.style.width=560;" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dw="http://www.ibm.com/developerworks/" />
图1是 DB2 命令中心的抓屏。在本例中,我们导入了如清单1所示的样本 DB2 备份脚本。您可以通过从 Script菜单选择 Import来导入脚本。
一般而言,可以把 DB2 命令行处理器(CLP)当作用于调用 DB2 命令的 DB2 提示符 DB2 => ,就象 Windows 命令提示符 C: 用于调用操作系统命令一样。也可以从任一 DB2 命令行工具调用 DB2 系统命令(稍后讨论)和操作系统命令,只要在命令前加一个感叹号 ! 即可。
图2显示了 DB2 CLP 以及关于如何获取 DB2 命令帮助的一些基本信息。单击 Start -> Programs -> IBM DB2 -> Command Line Tools -> Command Line Processor,启动 DB2 CLP。
560)this.style.width=560;" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dw="http://www.ibm.com/developerworks/" />
要了解有关 DB2 UDB V8.1 中 DB2 CLP 新增功能的更多信息,请阅读 Paul C. Zikopoulos 撰写的 DB2 开发者园地文章定制DB2 通用数据库命令行处理器。
您可以把 DB2 命令窗口看成一个 DB2 shell( db2cmd.exe ),它扩展 Windows shell( cmd.exe )以提供对 DB2 命令和 SQL 语句的支持。在 DB2 命令窗口中输入的命令必须是以大写、小写或大小写结合的 DB2 开头。操作系统命令(如 dir )直接被传递到 Windows shell(cmd.exe),不需要感叹号( ! )。
DB2 CLP 与 DB2 命令窗口的主要区别在于 CLP 提供 DB2 命令提示符 DB2 => ,而 DB2 命令窗口提供 Windows 命令提示符,DB2 命令和操作系统命令都可以在其中输入。在 Windows 上用 DB2 命令窗口可以最有效地执行 DB2 UDB 脚本编制,因为它方便地支持对 SQL 语句、DB2 命令、DB2 系统命令和操作系统命令的调用。
提示:如果您试图从 Windows shell 直接运行 DB2 命令,您将得到以下错误消息:
DB21061E Command line environment not initialized.
这表明这种 shell 不能处理 DB2 命令。您只需通过输入 db2cmd.exe 来启动 DB2 命令窗口,以初始化命令环境即可。
您可以设置几种选项来更改 DB2 CLP 的缺省行为。您可以通过输入 list command options 命令获取这些选项的列表,如图3所示。从 DB2 命令窗口调用 DB2 脚本最常用的几个选项将在下面的示例中演示。
560)this.style.width=560;" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dw="http://www.ibm.com/developerworks/" />
有关使用 DB2 CLP 编制 SQL 和 DDL 语句脚本的更多信息,请阅读 Blair Adamache 撰写的 DB2 开发者园地文章DB2 的命令行处理器和脚本编制。DB2 命令选项在 DB2 UDB Command Reference 中也有详细的文档记录。
尽管 DB2 脚本可以包含 SQL 语句、DB2 系统命令和操作系统命令,但它只是有一个或多个 DB2 命令的文本文件。虽然不是必需的,但通过使用适当的文件扩展名形成一个标准的 DB2 脚本命名约定通常是个很好的方法。 表1显示了几种最常用的文件扩展名。
文件扩展名 描述
.db2 包含 DB2 命令的 DB2 脚本
.ddl 包含数据定义语言(DDL)语句的 DB2 脚本
.sql 包含 SQL 语句的 DB2 脚本
作为说明之用, 清单1包含一个非常简单的 DB2 脚本,该脚本使用数个 DB2 命令备份 sample 数据库。可以从任一 DB2 命令行工具执行该脚本。本文中用到的全部脚本都可以下载。这些脚本使用缺省的 DB2 实例(DB2)和样本数据库(SAMPLE)。其中的一些脚本将要求您安装 Windows 资源包(Windows Resource Kit)。
-- -- This is a sample DB2 Backup Script -- ATTACH TO DB2; BACKUP DATABASE SAMPLE; DETACH; TERMINATE;
您可以使用以下语法从 DB2 命令窗口执行以上 DB2 脚本:
db2 -tvf db2backup.db2 -l db2backup.log -r db2backup.rpt
在上面的示例中,使用了以下 DB2 命令选项来执行 DB2 脚本文件( db2backup.db2 ):
-t 指明在缺省情况下用分号(;)终止每条命令
-v 指明应将每条命令显示到标准输出
-f 指明从输入文件读取命令
-l 指明将命令记录到输出文件中
-r 指明将结果保存到报告文件中
使用 -l 选项将所有 DB2 命令记录到日志文件( db2backup.log )并且使用 -r 选项将命令的输出保存到报告文件( db2backup.rpt ),这始终是一个很好的方法。这两个选项的区别在于:
-l 选项记录每条命令的开始和结束并记录日期和时间 -r 选项将每条命令的输出保存到文件中。
同时使用这两个选项可以让您利用报告文件查看脚本的执行摘要,并利用日志文件查看每条命令的详细信息。
也可以从 Windows shell 调用 DB2 命令窗口本身,只需从 Windows shell(命令提示符)输入 db2cmd 即可。它有一些有用的开关,可以在调用它时向它传递这些开关。 表2描述了这些选项:
开关 描述
-c 执行 DB2 命令窗口,然后终止。
-w 一直等到 DB2 命令窗口终止。
-i 从进行调用的 shell 继承环境。
-t 从进行调用的 shell 继承标题。
通过首先调用 DB2 命令窗口,您可以从任一 Windows shell 执行清单1中的脚本,如下面的示例所示:
db2cmd -c -w -i db2 -tvf db2backup.db2 -l db2backup.log -r db2backup.rpt
DB2 命令窗口提供所执行的每条命令的返回码。 表3列出了返回码。
代码 描述
0 成功执行 DB2 命令或 SQL 语句
1 SELECT 或 FETCH 语句没有返回任何行
2 DB2 命令或 SQL 语句警告
4 DB2 命令或 SQL 语句错误
8 命令行处理器系统错误
注:如果您正用交互方式执行语句,那么 DB2 CLP 不会提供每条命令的返回码。
DB2 系统命令是一组命令行实用程序,您可以用来执行那些由于种种原因尚未集成到 DB2 控制中心或其它 GUI 工具的任务。通常从操作系统 shell(如 Windows 命令提示符)调用 DB2 系统命令,但也可以从 DB2 命令中心、DB2 任务中心、DB2 CLP、DB2 命令窗口,当然还可以从您惯用的脚本语言调用。
有近百条 DB2 系统命令可用。请参阅 DB2 Command Reference以获得这些命令的完整列表,以及详细的文档。通读 DB2 UDB 修订包发行说明以查找新的 DB2 系统命令始终是个很好的方法,因为常常都是通过修订包添加新命令或增强现有命令的。
表4是一个非常简短的列表,它列出了一些比较常用的 DB2 系统命令,这些命令在脚本编制时非常有用。乍一看,其中的一些命令可能看起来不太象脚本编制命令,因此提供了对命令的描述,以使您清楚如何在脚本中使用它们。
命令 描述
db2audit DB2 提供一个审计工具来帮助检测对数据未知或不曾预料的访问。可利用该实用程序使安全性审计自动化,如脚本编制方案所述。
db2batch 从平面文件或标准输入读取 SQL 语句,动态地准备并描述语句,然后返回结果集。在设计用于对不同实例和数据库配置参数进行基准测试的脚本中,可使用这一 DB2 命令。在调用该实用程序之前,要重新启动实例并捕获系统信息,如 DB2 注册表、实例和数据库配置。
db2exfmt 格式化说明表的内容。在设计用于 SQL 调优的脚本中,可使用这一 DB2 命令,因为可以用它自动化 SQL 语句的解释、抽取和格式化。用这一 DB2 命令进行脚本编制可允许解释、抽取和格式化大量的 SQL 语句以供以后复查。
db2chkbk 该实用程序可用于测试备份镜像的完整性,并确定是否可以复原该镜像。当在数据库备份脚本的末尾要生成备份完成报告时,该实用程序将非常有用。
db2flsn 返回数据库事务日志文件的名称,该文件包含由指定的日志顺序号(LSN)标识的日志记录。当为了恢复而启用日志保留,而且您正在运行数据复制并需要确定在何处开始修剪事务日志时,这一实用程序作为数据库事务日志修剪脚本的一部分将非常有用。
myfriend2010 发表于:2007.10.30 16:07 ::分类: (db2 ) ::阅读:(636次) ::评论 (0)
===========================================================
探讨SQL语句技巧 优化DB2应用程序性能
===========================================================
本文以IBM的关系数据库管理系统DB2 Universal Database(通用数据库) 版本7.1为背景,与大家共同探讨编写好的SQL语句的技巧,以求DB2应用程序以求DB2应用程序获得更优的性能。
当我们设计一个新的或分析一个现存的系统时,其中所要考虑的一个重要问题就是应用程序的设计问题。即使数据库设计得很好而且还经过优化处理,应用程序设计不适当还是会引起性能问题的 数据库。实践证明,如果应用程序存在设计上的问题,那么修改这些问题比调整数据库配置参数更能改善应用程序的性能。
例如,SQL是一种高级语言,具有很大的灵活性,从数据库中提取相同的数据可以用不同形式的SELECT语句来实现,但是,应用程序的性能却随着SELECT语句形式的不同而大相径庭,这是因为不同形式的SELECT语句具有不同的处理成本。在这种情况下,我们就应该选择那些处理成本低廉的SELECT语句,这样,应用程序才会有较好的性能。
DB2通用数据库本身提供一个SQL编译器,该编译器创建编译后的SQL语句,当该编译器编译SQL语句时,它将重新编写这些SQL语句,以生成一种更容易对其进行优化的形式,这个过程称之为“查询重写(query rewrite)”。
然后,SQL编译器产生许多满足用户查询要求的、可选的执行方案,并根据表、索引、列和函数的统计数字来评估每个方案的执行成本,最后,从中选取执行成本最低的方案,该过程称之为“查询优化(query optimization)”。
有一点很重要,需要我们注意,那就是不管存取方案的优劣,SQL编译器(包括查询重写和优化两个阶段)必须从中选择一个,以产生满足应用程序查询要求的结果集,因此,我们在编写查询代码时,只应查询我们需要的数据,不需要的数据就不要查询,这样做的目的是确保SQL编译器能够选择一个最好的存取方案。
编写SELECT语句时一般遵循以下七个方面的准则:
1、在SELECT列表中仅仅指明需要的列
我们在编写SELECT语句时,尽管有时候不需要用到表中所有的字段,但还是习惯用*(表示引用表中所有的字段)来指定表中所有的列,这样做在编程上确实很简单、方便,但这么做的后果是应用程序返回一些我们不需要的列,系统做一些不必要的处理,做一些无用功,徒耗系统宝贵的软、硬件资源,尤其当表中有很多字段时,这种浪费现象就越加明显;而且,这也不是良好的编程习惯,我们不应提倡。
2、使用谓词来限制返回的行数
在SQL编程语言中,按照评估过程中如何使用谓词、何时使用谓词,我们将谓词划分为四大类(这四类谓词各自有不同的处理成本),按性能由高至低排列如下:
范围界定谓词 索引参数谓词 数据参数谓词 剩余谓词
范围界定谓词是指那些限定索引扫描范围的谓词,它们为索引搜索提供键值的起始值和/或终止值。索引参数谓词不用于界定搜索范围,但可以根据索引对它进行评估,因为谓词中的列是索引中的一部分。例如,假设表staff中的索引定义在name,dept和years三个字段上,执行下面的SELECT语句:
SELECT name,job,salary FROM staff
WHERE name=’John’
dept=10
years>5
头两个谓词(name=’John’和dept=10)是范围界定谓词,而years>5是索引参数谓词,因为单凭上述信息我们无法确定键years的起始值是多少,起始值可以是6,8,10,甚至更大。如果years的谓词是years>=5,那么,它就是范围界定谓词了,因为索引搜索可以从5开始。
数据库管理器在评估这些谓词的时候将利用索引数据,而不是读取数据库中的基本表。这些范围界定谓词和索引参数谓词通过减少需要从表中读取的行的数目来减少存取的数据页的数目。索引参数谓词不影响被存取的索引页的数目。
数据参数谓词是那些不能被索引管理器评估,却能被数据管理服务(DMS)评估的谓词。通常,这种谓词需要从基本表中存取个别行,如果需要的话,数据管理服务还会提取需要的列来评估该谓词。
例如,假设索引定义在表project的projno列上,而不是deptno列上,执行下面的查询:
SELECT projno,projname,repemp FROM project
WHERE deptno=’D11’
ORDER BY projno
谓词“deptno=’D11’”是数据参数谓词,因为没有索引定义在deptno列上,必须存取基本表来评估该谓词。
剩余谓词是指那些除了对基本表进行简单的存取操作之外,还要进行I/O操作的谓词,包括使用子查询的谓词(子查询中带有ANY,ALL,IN或SOME),以及读取LONG VARCHAR或大对象(LOB)数据的谓词(在DB2中,LONG VARCHAR、大对象和表是分开存放的)。
剩余谓词是用关系数据服务(RDS)来进行评估的,而且,它在这四类谓词中成本最昂贵。由于相对范围界定谓词和索引参数谓词来说,剩余谓词和数据参数谓词的成本比较高,所以,我们应该尽可能地限制范围界定谓词和索引参数谓词界定的行数。
我们来看一下DB2的组件:索引管理器,数据管理服务和关系数据服务。图1显示DB2的各个组件和处理这四类谓词的位置。

图1 DB2 UDB组件和谓词
其实,DB2组件很多,图1只是一个简化后的示意图。
关系数据服务(RDS)从应用程序那里接收到SQL请求,并返回结果集;除了剩余谓词外,RDS将所有谓词都发送给数据管理服务(DMS);剩余谓词由RDS进行评估。
DMS评估数据参数谓词。如果SELECT列表中存在一些不能由索引搜索进行评估的列,那么,DMS就会直接扫描数据页。
索引管理器从DMS那里接收、评估范围界定谓词和索引参数谓词,然后,将数据页的行标识符(RID)返回给DMS。
了解各种谓词的定义、转换条件及其使用场所,对我们深入剖析应用程序,提高应用程序性能是有所裨益的。
3、指定FOR UPDATE子句
如果想更新提取的数据,我们应该在游标定义的SELECT语句中指定FOR UPDATE子句。这样做的好处在于,数据库管理器在开始的时候就可以选择适当的加锁级别,例如,使用U(更新)锁,而不是S(共享)锁,这样,当处理后续的UPDATE语句时,就可以省去从S锁转换到U锁的开销了。
指定FOR UPDATE子句的另外一个好处是可以减少应用程序的死锁机会。死锁是这样一种情形:一个以上的应用程序等待另外一个应用程序释放对数据的锁定,而那些等待的应用程序正占据着另外应用程序所需要的数据,并且对该数据也进行了锁定。我们假设两个应用程序按下列顺序同时对同一行进行提取、更新操作:
(1)应用程序1提取该行
(2)应用程序2提取该行
(3)应用程序1更新该行
(4)应用程序2更新该行
在第4步,应用程序2将等待应用程序1完成更新操作,还要等应用程序1释放占据锁定,然后才能开始应用程序2的更新操作。可是,当我们声明一个游标时不指定FOR UPDATE子句,应用程序1就会获得并占据一个S(共享)锁定,对该行加锁(第1步),这意味着第二个应用程序用不着等待也可以获得并占据一个S锁(第2步)。然后,第一个应用程序试图获得一个U(更新)锁以处理更新语句,但是它必须等第二个应用程序释放其正占据着的S锁(第3步)。同时,第二个应用程序也试图获得一个U锁,并且由于第一个应用程序占据着S锁而进入等待状态(第4步)。这种情形就是死锁,造成的后果是应用程序1或应用程序2的交易不得不回滚。
如果在DECLARE CURSOR语句中指定FOR UPDATE子句,当应用程序1提取该行时,将会给该行加上U锁,应用程序2将会等待应用程序1释放U锁,这样,两个应用程序之间就不会发生死锁了。
下面举例说明如何在SELECT语句中使用FOR UPDATE子句。
EXEC SQL DECLARE c1 CURSOR FOR SELECT * FROM employee
FOR UPDATE OF job;
EXEC SQL OPEN c1;
EXEC SQL FETCH c1 INTO …;
If(strcmp(change,“YES”)= =0)
EXEC SQL UPDATE employee SET job = :newjob
WHERE CURRENT OF c1;
EXEC SQL CLOSE c1;
对于CLI编程,我们可以使用函数SQLSetConnectAttr()将DB2 CLI的连接属性SQL_ATTR_ACCESS_MODE的值设置为:SQL_MODE_READ_WRITE,效果是一样的。
4、指定OPTIMIZE FOR n ROWS子句
当我们希望提取的行数远远小于可能返回的行数时,在SELECT语句中指定OPTIMIZE FOR n ROWS子句。基于提取n行的假设,OP
TIMIZE FOR子句会影响查询的优化,同时也决定了通讯缓冲区中行的数目。
SELECT projno,projname,repemp FROM project
WHERE deptno=’D11’ OPTIMIZE FOR 10 ROWS
运用行的分块技术,通过在单一操作中一次性地提取一组行来减轻管理器的负担,这些行存储在缓冲区中,应用程序中的每一个FETCH请求都会从该缓冲区中提取下一行,如果指定OPTIMIZE FOR 10 ROWS,那么,系统会以10行为一组返回给用户。数据库
需要注意的是,OPTIMIZE FOR n ROWS子句既不会限制可以提取的行数,也不会影响提取的结果,但是,该子句会影响应用程序的性能,如果最终提取的行数小于或等于n,该子句会改善性能;否则,如果大于n,性能就会下降。
5、指定FETCH FIRST n ROWS ONLY子句
如果不希望应用程序提取n行以上的记录,我们可以在编程时指定FETCH FIRST n ROWS ONLY子句;反之,如果不指定该子句,结果集中可能就会有很多行(大于n)。注意,该子句不能与FOR UPDATE子句同时使用。
参看下面的例子,程序最多能提取5行。
SELECT projno,projname,repemp FROM project
WHERE deptno=’D11’
FETCH FIRST 5 ROWS ONLY
该子句同OPTIMIZE FOR n ROWS子句一样,也决定通讯缓冲区中行的数目;如果同时指定FETCH FIRST n1 ROWS ONLY子句和OPTIMIZE FOR n2 ROWS子句,则取n1和n2二者中的较小值作为通讯缓冲区的大小。
6、指定FOR FETCH ONLY子句
如果不想更新那些由SELECT语句提取的行,我们可以在SELECT语句中指定FOR FETCH ONLY子句,这么做的好处是,处理应用程序提出的查询请求时可以充分利用行的分块技术,进而改善性能;该子句还能改善数据的并发性,因为使用该子句查询的那些行上不再有独占的锁了。除了FOR FETCH ONLY子句,我们还可以使用FOR READ ONLY子句,二者是同义词,功效一致。
7、避免数据类型转换
我们应尽可能地避免数据类型的转换,特别是数字的数据类型之间的转换。当比较两个值时,使用具有相同数据类型的项目进行比较效率会更高。例如,有两张表:A和B,使用A的A1列和B的B1列进行两表间的连接操作,如下所示:
SELECT * FROM A,B
WHERE A1=B1
如果列A1和B1的数据类型一致,则无需进行数据类型转换;如果不一致,那么,应用程序就会在运行时进行数据类型的转换以比较二者的数值大小,从而影响应用程序的性能。例如,如果A1列的数据类型是decimal,而B1是integer,并且都有一个数值“123”,那么这时就需要进行数据类型转换了,因为表A将“123”存储为“123C”(十六进制表示),而表B存储为“7B”(十六进制表示)。
再者,进行数据类型转换时,由于计算精度的限制,可能会导致错误的发生。
DB2 UDB提供许多数据类型,其中,有用于数字数据的SMALLINT,INTEGER,BIGINT,DECIMAL,REAL,DOUBLE;有用于字符数据的CHAR,VARCHAR,LONG VARCHAR,CLOB;也有用于双字节字符数据的GRAPHIC,VARGRAPHIC,LONG VARGRAPHIC和DBCLOB,等等。由于数据库的存储容量和各种变量的处理成本都取决于数据类型,所以,我们在编程时如何选择适当的数据类型就显得十分重要,以下是选择数据类型时应该遵循的一些准则:
● 对于比较短的列,尽量使用定长的CHAR而不是变长的VARCHAR。虽然,当数据的长度参差不齐时,VARCHAR可以节省数据库存储空间,但是系统需要花费额外的开销去检查每个数据的长度。
● 尽量使用VARCHAR或VARGRAPHIC而不是LONG VARCHAR或LONG VARGRAPHIC。VARCHAR列和LONG VARCHAR列的最大长度差不多,基本一致,VARCHAR列的最大长度是32672字节,LONG VARCHAR列的最大长度是32700字节;同样地,VARGRAPHIC列和LONG VARGRAPHIC列的最大长度也相仿,VARGRAPHIC是16336字节,LONG VARGRAPHIC是16350字节。对于LONG VARCHAR列和LONG VARGRAPHIC列有一些限制,比如,这两列中的数据不能存储在数据库缓冲池中。
● 如果不需要小数部分,则尽量使用整数(SMALLINT,INTEGER,BIGINT)而不是浮点数(REAL或DOUBLE)或十进制数(DECIMAL)。比较而言,整数的处理成本要廉价得多。
● 尽量使用日期--时间(DATE,TIME,TIMESTAMP)而不是字符(CHAR)。日期--时间数据类型会占用较少的数据库存储空间,而且,对于日期--时间数据类型的变量,我们还可以利用系统提供的一些内置函数(如YEAR,MONTH)对其进行计算、转换等处理,一般来说,内置函数要比我们手工编写的函数在性能、效率上都要高一些。
● 尽量使用数字的数据类型而不是字符的数据类型。
凡事都是一分为二,有利有弊的,我们不能既想节省数据库的存储空间,又希望降低应用程序的处理成本,二者只能取其一,不可兼得,这就要求我们在编程时不能仅局限于一点,应该通盘考虑整个应用程序的设计,综合评估,权衡利弊,以求应用程序的性能更优。
结束语
一谈起数据库性能调整、优化,我们脑海中往往就会有这样的概念:优化是系统维护时做的事情,属于后期制作。其实不然,早在编程时就已经存在性能优化的问题了。本文就编写SQL语句时应该注意的一些问题阐述一下笔者的观点,不当之处还请大家批评指正。
myfriend2010 发表于:2007.10.27 15:29 ::分类: (db2 ) ::阅读:(796次) ::评论 (0)
===========================================================
DB2 中游标的使用以及 存储过程的写法
===========================================================
问题1:
什么时候才会发生not found异常 ,以及db2中sqlcode的值是如何变化的?
在db2中,一条select 语句也有可能发生not found异常,譬如
declare sqlcode integer default 0;
declare sql_code integer default 0;
declare classCode varchar(40) ;
select app_class_code into classCode from kf_app_class where app_name='无效记录';
set sql_code=sqlcode;
如果此时没有检索到记录,那么sqlcode的值为100,有的话为0;
我们可以定义NOT FOUND 异常处理
declare sqlcode integer default 0;
declare sql_code integer default 0;
declare classCode varchar(40) ;
begin
declare continue handler for not found
begin
--注如果发生not found那么此时的sqlcode必定为100
set sql_code=sqlcode;/*在这里sqlcode的值为100;*/
--如果再次得到sqlcode的值那么它的值变为0
set sql_code=sqlcode;/*这里sqlcode变成了0,因为上一条语句执行成功了,那么sqlcode变成了0*/
end;
select app_class_code into classCode from kf_app_class where app_name='无效记录';
set sql_code=sqlcode;/*同理此时如果没有取到数据,那么会进declare continue handler ,返回后sqlcode的值也为0*/
end;
所以我们可以通过两种方法来捕获和处理not found
方法1:
begin
declare continue handler for not found
begin
--异常处理代码
end;
sql语句
end;
方法2:
begin
sql语句
if sqlcode=100 then
--异常处理代码
end if;
end;
问题2:
定义了游标,怎么fecth一条记录,怎么进行循环?
Q:定义了游标假设发生not found 异常,那么是在open cursorName的时候还是在fecth的时候发生异常?
A:检验游标中的数据是否取完或者有无记录,应该在fecth的时候,而不是发生在open cursorName的时候,
下面一个例子详细的说明了游标使用过程
begin
declare sqlcode integer default 0;
declare app_code varchar(10);
declare cursor1 cursor for select app_code from kf_app_class ;
open cursor1;
cursorLoop:
loop
fecth cursor1 into app_code ;
if sqlcode=100 then leave cursorLoop;
end if;
end loop;
end;
Q:sqlcode 可以直接用吗?
A:在db2中,如果要使用sqlcode那么必须在使用前declare;
譬如
declare sqlcode integer default 0;
if sqlcode =? then
end if;
附注
db2的其他异常处理
对应 oracle的 when other exceptions
declare exit handler for sqlwaring,sqlexcption
begin
--处理异常
end;
当程序执行exit handler异常处理后,那么会退出程序,不会在接着执行,也就是
declare exit handler for sqlwaring,sqlexcption
begin
--处理异常
end;
sql语句1;
sql语句2;
执行sql语句1发生异常,会进入 exit handler ,然后退出程序,不会在执行 sql语句2
myfriend2010 发表于:2007.10.24 14:27 ::分类: (db2 ) ::阅读:(2070次) ::评论 (0)
===========================================================
DB2 V8.2归档日志技巧
===========================================================
在DB2版本8.2以前,采用用户出口程序的方式进行日志归档操作,从DB2版本8.2开始,DB2集成了日志管理功能,目前支持采用如下三种方式归档日志:
环境:产品: DB2 UDB,平台: 跨平台,版本:版本8.2及以后版本。
在DB2版本8.2以前,采用用户出口程序的方式进行日志归档操作,从DB2版本8.2开始,DB2集成了日志管理功能,目前支持采用如下三种方式归档日志:
DISK:将归档日志存放到磁盘上
TSM:将归档日志存放到TSM服务器
BAR APIs:第三方厂商提供的产品
DB2在版本8.2中增加了如下配置参数:
第一个日志归档方法 (LOGARCHMETH1) = LOGRETAIN
logarchmeth1 的选项 (LOGARCHOPT1) =
第二个日志归档方法 (LOGARCHMETH2) = OFF
logarchmeth2 的选项 (LOGARCHOPT2) =
故障转移日志归档路径 (FAILARCHPATH) =
错误时重试日志归档次数 (NUMARCHRETRY) = 5
日志归档重试延迟(秒) (ARCHRETRYDELAY) = 20
供应商选项 (VENDOROPT) =
下面是关于这些参数的说明:
日志归档方法 1(logarchmeth1)和日志归档方法 2(logarchmeth2)这些参数使数据库管理器将日志文件归档至活动日志路径之外的位置。如果指定这两个参数,每个日志文件均归档两次。这意味着您将拥有两个位于不同位置的归档日志文件副本。 这些参数的有效值包括介质类型,且在某些情况下,包括目标字段。
使用冒号(:)来分隔值。有效的值为:
OFF 指定不使用日志归档方法。如果 logarchmeth1 和logarchmeth2 都设置为 OFF,则认为数据库正在使用循环日志记录,且不可前滚恢复。这是缺省值。
LOGRETAIN 此值仅可用于 logarchmeth1,且等价于将 logretain配置参数设置为 RECOVERY。如果指定此值,将自动更新logretain 配置参数。
USEREXIT 此值仅对 logarchmeth1 有效,且等价于将userexit 配置参数设置为 ON。如果指定此值,将自动更新userexit 配置参数。
DISK 此值后必须紧跟冒号(:),然后是全限定现有路径名,日志文件将在其中归档。例如,如果将 logarchmeth1 设置为 DISK:/u/dbuser/archived_logs,则将归档日志文件放入名为 /u/dbuser/archived_logs 的目录。
注意: 如果正在归档至磁带,可以使用 db2tapemgr 实用程序来存储和检索日志文件。TSM 如果指定不带任何附加配置参数,此值指示应该使用缺省管理类,将日志文件归档在本地 TSM 服务器上。如果此值后紧跟冒号(:)和 TSM 管理类,则使用指定的管理类来归档日志文件。
VENDOR 指定将使用供应商库来归档日志文件。此值后必须紧跟冒号(:)和库的名称。库中提供的 API 必须使用备份并复原供应商产品的 API。 注意:
如果将 logarchmeth1 或 logarchmeth2 设置为 OFF 以外的值,则必须配置数据库以进行前滚恢复。 如果更新 userexit或 logretain 配置参数,将自动更新 logarchmeth1,反之亦然。然而,如果您正在使用 userexit 或 logretain,必须将 logarchmeth2 设置为 OFF。
日志归档选项 1(logarchopt1)、日志归档选项 2(logarchopt2):
指定传递至 TSM 服务器或供应商 API 的字符串。对于 TSM,此字段用于允许数据库检索在不同 TSM 节点或通过不同 TSM用户生成的日志。字符串必须以如下格式提供: "-fromnode=nodename -fromowner=ownername"其中 nodename 是最初归档日志文件的 TSM 节点的名称,ownername 是最初归档日志文件的 TSM 用户的名称。每个日志归档选项字段对应于一个日志归档方法:logarchopt1与 logarchmeth1 配合使用,logarchopt2 与 logarchmeth2 配合使用。
故障转移归档路径(failarchpath)
如果指定的日志归档方法失败,则为归档日志文件指定备用目录。在失败的日志归档方法再次可用之前,此目录是日志文件的临时存储区,此时日志文件将从此目录中移至日志归档方法。通过将日志文件移动至该临时位置,可以避免日志目录发生已满情况。此参数必须是一个全限定现有目录。
出错时的归档重试次数(numarchretry)
指定在日志文件归档到 failarchpath 配置参数指定的路径之前,使用指定的归档方法归档日志文件的尝试次数。如果设置了 failarchpath 配置参数,则只能使用该参数。缺省值为 5。
归档重试延迟(archretrydelay)
指定在上一次尝试失败之后,归档日志文件尝试之间等待的时间量(以秒计)。缺省值为 20。
供应商选项(VENDOROPT)
指定使用第三方厂商进行备份、恢复、归档日志时需要的额外参数配置。参考第三方厂商存储软件的说明配置。
下面我们以一个简单的例子配置DB2将日志归档到磁盘说明如何使用DB2版本8.2提供的新功能:
1、更新数据库SAMPLE的配置参数(请在更新之前确保使用的目录已经建立,而且DB2实例用户有合适的权限):
D:Temp>db2 update db cfg for sample using logarchmeth1 DISK:D:TEMPlogarc1
DB20000I UPDATE DATABASE CONFIGURATION 命令成功完成。
D:Temp>db2 update db cfg for sample using
failarchpath d:templogarc2
DB20000I UPDATE DATABASE CONFIGURATION 命令成功完成。
注意:如果先前你没有设置为归档日志模式,您设置完参数后可能需要先做一个数据库的脱机备份。例如:
db2 backup db sample to
2、查看一下数据库SAMPLE的目前日志归档参数设置:
D:Temp>db2 get db cfg for sample
第一个日志归档方法 (LOGARCHMETH1) = DISK:D:TEMPlogarc1
logarchmeth1 的选项 (LOGARCHOPT1) =
第二个日志归档方法 (LOGARCHMETH2) = OFF
logarchmeth2 的选项 (LOGARCHOPT2) =
故障转移日志归档路径 (FAILARCHPATH) = d:templogarc2
错误时重试日志归档次数 (NUMARCHRETRY) = 5
日志归档重试延迟(秒) (ARCHRETRYDELAY) = 20
供应商选项 (VENDOROPT) =
。。。
3、检查db2diag.log,可以看到参数设置改变的信息:
2004-10-26-19.30.25.245000+480 I14933654H408 LEVEL: Event
PID : 1872 TID : 2592 PROC : db2syscs.exe
INSTANCE: DB2 NODE : 000 DB : SAMPLE
APPHDL : 0-89 APPID: *LOCAL.DB2.041026024848
FUNCTION: DB2 UDB, config/install, sqlfLogUpdateCfgParam, probe:20
CHANGE : CFG DB SAMPLE: "Logarchmeth1" From: "" To: "DISK:D:TEMPlogarc1"
2004-10-26-19.30.47.987000+480 I14934064H404 LEVEL: Event
PID : 1872 TID : 2592 PROC : db2syscs.exe
INSTANCE: DB2 NODE : 000 DB : SAMPLE
APPHDL : 0-89 APPID: *LOCAL.DB2.041026024848
FUNCTION: DB2 UDB, config/install, sqlfLogUpdateCfgParam, probe:20
CHANGE : CFG DB SAMPLE: "Failarchpath" From: "" To: "d:templogarc2"
4、对数据库SAMPLE进行更新操作,以便写满日志文件,触发日志归档。我们通过重复往staff表中插入数据实现:
D:Temp>db2 connect to sample
数据库连接信息
数据库服务器 = DB2/NT 8.2.0
SQL 授权标识 = BIYJ
本地数据库别名 = SAMPLE
D:Temp>db2 insert into staff select * from staff
DB20000I SQL 命令成功完成。
重复执行上述命令。直至有日志文件写满触发日志归档。
5、检查db2diag.log,查看是否有日志归档,你会看到类似下面的内容:
2004-10-26-19.42.13.373000+480 I14935459H319 LEVEL: Warning
PID : 1872 TID : 1884 PROC : db2syscs.exe
INSTANCE: DB2 NODE : 000
FUNCTION: DB2 UDB, data protection, sqlpghck, probe:1390
MESSAGE : ExtNum 1, state 401, baselsn 0000000000FA0000 nextlsn 0000000000FA21E
2004-10-26-19.42.13.403000+480 I14935780H418 LEVEL: Warning
PID : 1872 TID : 1516 PROC : db2syscs.exe
INSTANCE: DB2 NODE : 000
FUNCTION: DB2 UDB, data protection, sqlpgArchiveLogFile, probe:3180
MESSAGE : Successfully archived log file S0000001.LOG to
D:TEMPlogarc1DB2SAMPLENODE0000C0000002 from
C:DB2NODE0000SQL00001SQLOGDIR.
2004-10-26-19.42.13.573000+480 I14936200H316 LEVEL: Warning
PID : 1872 TID : 196 PROC : db2syscs.exe
INSTANCE: DB2 NODE : 000
FUNCTION: DB2 UDB, data protection, sqlpgLoggrInitDelOldLog, probe:1440
MESSAGE : Cleaning up logs from RenameArchNum 1 to delLimit 2
6、检查一下我们的归档日志,就会看到已经归档的文件:
D:Templogarc1DB2SAMPLENODE0000C0000002 的目录
2004-10-26 07:43 下午
2004-10-26 07:43 下午
2004-10-26 07:42 下午 20,480 S0000001.LOG
2004-10-26 07:43 下午 4,104,192 S0000002.LOG
2004-10-26 07:43 下午 4,104,192 S0000003.LOG
2004-10-26 07:43 下午 4,104,192 S0000004.LOG
关于使用TSM服务器和第三方厂商备份软件配置归档日志的方法,请参见DB2 UDB V8.2 信息中心:
http://publib.boulder.ibm.com/infocenter/db2help/index.jsp
myfriend2010 发表于:2007.10.12 16:06 ::分类: (db2 ) ::阅读:(1332次) ::评论 (2)
===========================================================
db2常用管理命令
===========================================================
1. 查看本地节点目录
命令窗口中输入:db2 list node directory
2. 编目一个TCP/IP节点
命令窗口:db2 catalog tcpip node remote server ostype
3. 取消节点编目
db2 uncatalog node
4. 查看系统数据库目录
db2 list database directory
5. 查看本地数据库目录
db2 list database directory on <盘符>
在本地数据库目录中有而系统数据库目录中没有的数据库不能访问,可以在控制中心中选中<数据库>右键单击选择添加,然后输入需要添加的数据库名称或者点击刷新按钮选择数据库,加入数据库后即可以访问。
6. 编目数据库
db2 catalog database as at node
7. 取消数据库编目
db2 uncatalog database
8. 测试远程数据库的连接
db2 connect to user using
9. 设置默认模式
任何用户均可通过设置Current Schema专用寄存器为特定的数据库连接设置默认模式,初始默认值为当前会话用户的权限ID。
set schema =
可以由用户交互式的使用,也可在应用程序中使用,如果用Dynamicrules Bind选项绑定包,这个语句就没有作用。此语句不在事务控制之下。
10. 代码页的设置
在创建数据库时设置字符集
create database using codeset territory
例:
create database dbtest using codeset IBM-437 territory US
也可以设置整个数据库的代码页,在win2000/NT/xp中,在我的电脑-->属性-->高级-->环境变量中添加变量 DB2CODEPAGE = ,例:DB2CODEPAGE = 437 或 DB2CODEPAGE = 1386。或者在IBM DB2命令窗口输入 db2set DB2CODEPAGE=1386,设置后需要重新启动DB2生效。
11. DB2低版本数据到高版本的迁移
先将低版本数据备份使用恢复功能导入高版本数据库,然后在命令窗口输入 db2 migrate database 。
12. 表名或模式中含有引号时访问表
命令窗口:db2 select * from "tabschema"."tabname"
命令行处理器:db2=> select * from "tabschema"."tabname"
13. 导出数据库的表结构生成DDL文件
命令窗口:db2look -d -e -c -o
14. 执行脚本文件
命令窗口:db2 -tvf
15. 代码页的转换
16. 获取当前DB2的版本
select * from sysibm.sysversions
17. DB2表的字段的修改限制?
只能修改VARCHAR2类型的并且只能增加不能减少
alter table alter column set data type varchar(SIZE)
18. 如何查看表的结构?
describe table
or
describe select * from .
19. 如何快速清除一个大表?
ALTER TABLE TABLE_NAME ACTIVE NOT LOGGED INITALLY WITH EMPTY TABLE
20. 如何查看数据库的存储过程?
SELECT * FROM SYSCAT.POCEDURES
21. 如何查看表的约束?
SELECT * FROM SYSCAT.CHECKS WHERE TABNAME =
22. 如何查看表的引用完整约束?
SELECT * FROM SYSCAT.REFERENCES WHERE TABNAME =
23. 如何知道BUFFERPOOLS状况?
select * from SYSCAT.BUFFERPOOLS
24. 如何在命令行下查看修改实例和数据库配置参数?
查看实例配置参数: db2 get dbm cfg
修改实例配置参数: db2 update dbm cfg using 参数名 新值
查看数据库配置参数: db2 get db cfg for
修改数据库配置参数: db2 update db cfg for using 参数名 新值
25. 如何修改缓冲区?
增加缓冲区: create bufferpool size [pagesize 4096] {[not] EXTENDED STORAGE}
修改缓冲区: alter bufferpool size {[not] EXTENDED STORAGE}
删除缓冲区: drop bufferpool
如果缓冲区大小设置为 -1 表示缓冲池的页面数目由数据库配置参数buffpage决定。
注意: 数据库配置参数buffpage仅对缓冲区大小设置为 -1 的缓冲池起作用。
26. 多个字段时如何不通过使用select子句使用in/not in
select * from tabschema.tabname where (colA, colB, colC) [not] in (values (valueA1, valueB1, valueC1), (valueA2, valueB2, valueC2), ...(valueAn, valueBn, valueCn))
27. 查看当前连接到数据库的应用
db2 list application [show detail]
28. 如何确认DB2数据库的一致性
db2dart /DB
/DB表示检查整个数据库的一致性
29. 测试SQL语句的性能
db2batch -d -f [-a userid/passwd] [-r ]
-r 选项表示将查询结果输出到一个文件中。
30. 导出某个表的数据
export to
如:导出用户表
export to c:user.ixf of ixf select * from user
31. 导入数据
import from
:导入用户表。导入时可以直接建立新表。如果有该表存在也可以用INSERT 插入,或者用UPDATE更新
import from c:user.ixf of ixf [Create/Insert into / update] tablename
myfriend2010 发表于:2007.10.12 13:21 ::分类: (db2 ) ::阅读:(1249次) ::评论 (0)
===========================================================
DB2归档模式及与DB2复制相关问题
===========================================================
该文简单介绍了DB2归档模式,并说明了如何设置归档模式及其与DB2复制相关的问题。
 
1. DB2日志简介
1.1. 日志类型
1.1.1. 活动日志(ACTIVE LOG)
功能类似于ORACLE的online redo log, 该日志包含尚未提交或回滚的事务单元的相关信息,以及已提交但尚未写入数据库文件的事务的信息。
具体又分两种
l 主日志 数量由参数LOGPRIMARY决定,预先分配
l 从日志 当主日志不够时,临时分配最多LOGSECOND数目个从日志
1.1.2. 存档日志(ARCHIVED LOG)
存在于归档模式。
1.1.2.1. 联机存档日志(ONLINE ARCHIVED LOG)
它们是驻留在数据库活动日志目录(“online”)中、普通数据库活动不再需要的日志文件。
1.1.2.2. 脱机存档日志(OFFLINE ARCHIVED LOG)
它们是已经从数据库日志目录移到脱机存储位置(如备份服务器)、普通数据库活动不需要的日志文件
这两者的不同仅在于联机归档日志存在于活动日志目录下,而脱机的不是
1.2. 日志模式
1.2.1. 循环日志模式
如图所示,预先分配好的若干个主日志循环利用,当不够的时候,临时申请若干个从日志
1.2.2. 归档日志模式
当开启归档模式后,日志将不会被覆盖,而是不停新产生。如果不设LOGARCHMETH1参数的话,归档日志将仍然待原目录,就成为联机归档日志。如下图:
而如果,设置LOGARCHMETH1参数到另外一个目录的话,归档后的日志将被自动移动到新目录下,即被称为脱机归档日志,如下图:
2. DB2归档模式设定
1. 修改参数LOGRETAIN为recovery (缺省为N)
Db2 update db cfg for TEST using logretain recovery
2. 将数据库做一次全备
Db2 BACKUP DATABASE TEST TO "C:test"
3. 修改USER_EXIT参数
a) 可以通过图形界面;控制中心-》数据库》DBNAME》右键》配置数据库记录向导
b) 通过命令行
Db2 UPDATE DB CFG FOR TEST USING logarchmeth1 "DISK:C:testMYLOG"
这样日志就被自动归档到C:testMYLOG目录下了。
3. DB2日志跟ORACLE日志的比较
有两个比较大的不同点:
1. DB2要求活动日志被覆盖或者归档之前必须保证里面的事务已经commit或者rollback了,也就是说,如果一个事务太大,超过了主日志加从日志的和的话,将会报日志满错误。而ORACLE没这个要求,只可能在归档模式时,空间满了才会报日志满错误。
2. 对于归档模式而言,DB2的活动日志总是新分配的,不象oracle,在线日志总是重用的
4. 与复制相关的问题
1. 如果DB2启用复制并且作为数据源后,必须使用归档日志模式,DB2复制是从日志或者归档日志里捕获需要的表的修改信息的。
2. 如果复制进程中途断掉,经过一段时间再启用时,这时可能相应的表修改信息已经被归档了,这时db2将从归档日志(可能联机归档日志,也可能是脱机归档日志)里面将信息去找。
3. 这就涉及到一个问题,归档日志不会无限期的放到归档目录下,如何设定归档日志存放时间呢?如果时间过短,复制的capture进程可能会发生找不到相应日志,从而失败的问题。存放时间太长的话,需要的归档空间又太多。这就需要根据实际情况,两方面均衡的考虑了。
4. 如果真的发生了找不到日志的情况,可以有两种方法
a) 将日志从别处拷回
b) 将复制完全刷新
对单向复制而言,复制完全刷新这个选项就已经够了。但对双向复制而言,完全刷新的话,意味着从节点自上次刷新之后的修改就完全丢失了,所以最好将日志拷回来。
 
myfriend2010 发表于:2007.10.12 13:19 ::分类: (db2 ) ::阅读:(1540次) ::评论 (1)
===========================================================
如何使用REORG TABLE命令优化数据库性能?
===========================================================
总结了一下REORG的操作经验
当数据库里某个表中的记录变化量很大时,需要在表上做REORG操作来优化数据库性能。
值得注意的是,针对数据库对象的大量操作,如反复地删除表,存储过程,会引起系统表中数据的频繁改变,在这种情况下,也要考虑对系统表进行REORG操作。
由于DB2使用CBO作为数据库的优化器,数据库对象的状态信息对数据库使用合理的ACCESS PLAN至关重要。
一个完整的REORG表的过程应该是由下面的步骤组成的:
RUNSTATS -> REORGCHK -> REORG -> RUNSTATS -> BIND或REBIND
0 执行下面命令前要先连接数据库
1 RUNSTATS
由于在第二步中REORGCHK时可以对指定的表进行RUNSTATS操作(在REORGCHK时指定UPDATE STATISTICS),所以第一步事实上是可以省略的。
2 REORGCHK
REORGCHK命令的语法如下:
>>-REORGCHK----+----------------------------+------------------->
| .-UPDATE--. |
'--+-CURRENT-+---STATISTICS--'
>-----+---------------------------+----------------------------><
| .-USER-------. |
'-ON TABLE--+-SYSTEM-----+--'
+-ALL--------+
'-table-name-'
REORGCHK是根据统计公式计算表是否需要重整。
对于每个表有3个统计公式,对索引有3个统计公式(版本8开始有5个公式),如果公式计算结果该表需重整,在输出的REORG字段中相应值为*,否则为-。
如果数据库中数据量比较大,在生产系统上要考虑REORGCHK的执行时间可能较长,需安排在非交易时间执行。
可以分为对系统表和用户表两部分分别进行REORGCHK:
1) 针对系统表进行REORGCHK
db2 reorgchk update statistics on table system
使用UPDATE STATISTICS参数指定数据库首先执行RUNSTATS命令。
2) 针对用户表进行REORGCHK
db2 reorgchk update statistics on table user
下面是执行的部分结果
db2 reorgchk update statistics on table user
执行 RUNSTATS ....
表统计信息:
F1: 100 * OVERFLOW / CARD < 5
F2: 100 * (Effective Space Utilization of Data Pages) > 70
F3: 100 * (Required Pages / Total Pages) > 80
SCHEMA NAME CARD OV NP FP ACTBLK TSIZE F1 F2 F3 REORG
----------------------------------------------------------------------------------------
DB2INST1 STAFF - - - - - - - - -*-
...
索引统计信息:
F4: CLUSTERRATIO 或正常化的 CLUSTERFACTOR > 80
F5: 100 * (KEYS * (ISIZE + 9) + (CARD - KEYS) * 5) / ((NLEAF - NUM EMPTY LEAFS) * INDEXPAGESIZE) > 50
F6: (100 - PCTFREE) * ((INDEXPAGESIZE - 96) / (ISIZE + 12)) ** (NLEVELS - 2) * (INDEXPAGESIZE - 96) / (KEYS * (ISIZE + 9) + (CARD - KEYS) * 5) < 100
F7: 100 * (NUMRIDS DELETED / (NUMRIDS DELETED + CARD)) < 20
F8: 100 * (NUM EMPTY LEAFS / NLEAF) < 20
SCHEMA NAME CARD LEAF ELEAF LVLS ISIZE NDEL KEYS F4 F5 F6 F7 F8 REORG
-------------------------------------------------------------------------------------------------
表:DB2INST1.STAFF
DB2INST1 ISTAFF - - - - - - - - - - - - -----
...
从上面的例子来看,对于表DB2INST1.STAFF,根据统计公式F2计算结果,有必要对表进行REORG。
3 REORG TABLE
REORG TABLE命令的语法如下:
>>-REORG TABLE--table-name----+--------------------+------------>
'-INDEX--index-name--'
>-----+-----------------------+--------------------------------><
'-USE--tablespace-name--'
执行REORG可以考虑分为表上有索引和没有索引两种情况:
1) 如果表上有索引
如表名为DB2INST1.STAFF,索引名为DB2INST1.ISTAFF,命令如下:
db2 reorg table db2inst1.staff index db2inst1.istaff use tempspace1
建议REORG时使用USE参数指定数据重排时使用的临时表空间,否则,REORG工作将会在表所在表空间中原地执行。
如果表上有多个索引,INDEX参数值请使用最为重要的索引名。
2) 如果表上没有索引
如表名为DB2INST1.STAFF, SYSIBM.SYSTABLES
db2 reorg table db2inst1.staff use tempspace1
db2 reorg table sysibm.systables use tempspace1
4 RUNSTATS
RUNSTATS命令的语法如下:
>>-RUNSTATS ON TABLE--table-name-------------------------------->
>-----+-+--------------------------------------------------------------------+-+>
| '-WITH DISTRIBUTION--+--------------------------------------------+--' |
| '-AND--+----------+--+-INDEXES ALL--------+--' |
| '-DETAILED-' '-INDEX--index-name--' |
'-+--------------------------------------------------+-------------------'
'--+-AND-+---+----------+--+-INDEXES ALL--------+--'
'-FOR-' '-DETAILED-' '-INDEX--index-name--'
>-----+--------------------------+-----------------------------><
| .-CHANGE----. |
'-SHRLEVEL--+-REFERENCE-+--'
如果表名为DB2INST1.STAFF,表上有索引,则可以用下面的例子完成RUNSTATS命令:
db2 runstats on table db2inst1.staff with distribution and detailed indexes all
5 (可选) 上面命令完成后可以重复第二步,检查REORG的结果,如果需要,可以再次执行REORG和RUNSTATS命令。
6 BIND或REBIND
RUNSTATS命令运行后,应对数据库中的PACKAGE进行重新联编,简单地,可以使用db2rbind命令来完成。
db2rbind命令的语法如下:
>>-db2rbind--database--/l logfile----+------+------------------->
'-all--'
.-conservative--.
>-----+-------------------------+--/r--+-any-----------+-------><
'-/u userid--/p password--'
例如,如果数据库名为SAMPLE,执行:
db2rbind sample -l db2rbind.out
myfriend2010 发表于:2007.10.10 14:36 ::分类: (db2 ) ::阅读:(979次) ::评论 (0)
===========================================================
八月十五的雨
===========================================================
八月十五的雨
断肠人的天涯!
夜色弥漫,一个人漫步大街上,感受身边来来往往的人群,
仰或行色匆匆,仰或戏笑怒骂,仰或仗酒宣情、豪言壮语!
唯独自己孑然一身,似乎身处喧嚣中的冷清!又似乎容不下这个世界!
突然眼睛有点涩,手触及,竟是。。。。泪水!
好想哭!虽然从来没有 哭过!
我不要这份冷清!我不要女友离我而去!
为何....原本欢乐的聚会,突然一场云烟!
为何....和你不到2句的话,就遭你横眉冷对的残待!
曾经体贴大方,微笑宛尔的你哪儿去了????
好累!
做了这么多,只换回身体上的累以及泪~!
是你腻了?? 就连给我的爱也变成了施舍?
还是我累了??
至少也曾经有过两个人的快乐。。。。。
来来往往的人啊!
有谁知这寂寥、孤独、无助的我!
心灵低处的
裂口很深,-------------痛!
断肠的痛,断肠的人,断肠的天涯!
飘起了雨滴!
点点滴滴,合着泪!
是天际感应到了我心中的苦楚?
天的同情??
天!!--------------------------------
八月中秋
月圆
人------------------不圆!
夜色欺人!
我独不醉!
myfriend2010 发表于:2007.09.26 15:48 ::分类: (db2 ) ::阅读:(26821次) ::评论 (0)
===========================================================
OLTP 应用程序的 DB2 调优技巧
===========================================================
DB2 Universal Database®(UDB)是第一个支持多媒体和 Web 的关系数据库管理系统,它的功能非常强大,足以满足大公司的需求,并且它非常灵活,足以满足中小企业的要求。DB2 产品系列软件和因特网技术的结合使我们可以方便地跨不同平台访问信息、使用信息并且保证信息安全。全世界有 30 多万家公司的 6000 多万个 DB2 用户依赖于 IBM 数据管理解决方案。
DB2 UDB 为大多数需要电子商务的应用程序(比如电子商务、企业资源计划、客户关系管理、供应链管理、Web 自助服务和商业智能)提供支持。这是一种可伸缩的、工业级数据库,非常适合用作电子商务发展过程中的数据管理基础。
联机事务处理(Online transaction processing,OLTP)是一类能为面向事务应用程序提供便利的应用程序,并可用来管理面向事务的应用程序,它通常用于处理许多行业的数据输入和检索事务,这些行业包括银行、航空、邮购、超市和制造业。通常,OLTP 工作负载包括许多并发运行的短事务。如今的联机事务处理日益要求支持跨网络以及可能包括多家公司的事务。因此,新的 OLTP 软件使用了客户机/服务器处理和代理软件,这种软件允许事务在一个网络的不同计算机平台上运行。
在任何一种数据库系统中,性能是最重要的因素之一。本文根据由运行 OLTP 类型的性能基准测试程序(TPC-C、TPC-W、Trade2 等)所得到的经验,着重讨论了许多 DB2 性能调优技巧。虽然数据库应用程序的性能会受许多因素影响,但是我们着重讨论配置而不是诸如容量规划、数据库设计或应用程序设计之类的因素。
本文的组织结构如下:
有关性能的一些基本要素
更新目录统计信息,这部分强调收集和维护最新数据库统计信息的重要性,缺少这项工作常常是导致许多性能问题的源头所在。
监控和调优数据库配置参数,这部分按照重要性的顺序描述了一列数据库管理器参数和数据库参数。通常,没必要尝试列表中的所有参数以实现性能目标。可以只尝试其中位于列表顶部的那几个,以查看是否有性能方面的改进。
有了这些技巧,就可以启动自己的 OLTP 应用程序并使其拥有非常好的运行性能。
1. 有足够的内存。
o 对于 32 位系统,每个 CPU 至少使用 512 MB 的 RAM,最高可达每台机器 4 GB,以支持大量并发用户所需的缓冲池、DB2 代理程序和其它共享内存对象。(请参阅 缓冲池大小(BUFFPAGE)”一节以获取有关缓冲池的更多信息。)可能需要更多的内存来支持在本地运行或作为存储过程运行的应用程序。在 AIX® 上 JFS 文件高速缓存可以使用额外的内存来补充缓冲池。
o 对于 64 位系统,缓冲池实际上可以是任何大小。但是,对于使用大型数据库的大多数电子商务 OLTP 应用程序,缓冲池大小实际上不需要超过 8 GB。越大当然越好,但是在某一点,当缓冲池命中率达到 98+% 时,会随内存的增加命中率反而下降。并发用户的数目(它影响 DB2 代理程序的数量)决定需要多少内存。
o 每个用户连接至数据库(即 DB2 代理程序)所需的内存数量取决于应用程序所执行的 SQL 语句的性质 - 比如打开的并发游标数以及所需的排序和临时空间的数量。对于 OLTP 应用程序,所需的排序和临时空间会比较少,一次只打开少数并发游标。
o 经验:对于每个 DB2 代理程序,在 UNIX 中最少使用 1 MB 内存,在 Windows 中最少使用 500 KB 内存。如果使用了受防护的存储过程,那么除了运行存储过程应用程序所需的内存之外,每个用户连接还有两个 DB2 代理程序。
2. 有足够的 I/O 处理能力。
o 必须有足够的磁盘设备来确保充分的 I/O 并行性,以支持大容量的并发事务。对于中等工作负载而言,每个 CPU 至少应当有 5 到 10 个磁盘,对于高 I/O OLTP 工作负载而言,至少要有 20 个磁盘。操作系统(包括调页空间)、DB2 日志和 DB2 表空间应当拥有各自的专用磁盘。应当有多个磁盘用于 DB2 日志、表和索引。
o 估计良好性能所需的 I/O 处理能力的正确方式,实际上是制作事务原型并找出每个事务需要多少 I/O,以及每秒需要处理多少事务。然后找出磁盘控制器和磁盘子系统的 I/O 速率以帮助确定需要多少控制器和磁盘。
3. 有足够的网络带宽。
必须有足够大的网络带宽以支持工作负载。请确保网络或任何中间集线器都不会成为瓶颈。当支持远程访问时这一点尤为重要。例如,T1 线路支持 1.544 Mb/s,这仅为 0.193 MB/s,而通常的 10 Mb/s 以太局域网可以支持 1.25 MB/s,吞吐量为 T1 线路的 6 倍。在 UNIX 上使用诸如 netstat 这样的命令可以监控连接上的流量。
4. 使用 DB2 控制中心(DB2 Control Center)的 DB2 性能配置向导(DB2 Performance Configuration Wizard)来设置初始的 DB2 数据库管理器(Database Manager)和数据库配置(Database Configuration)参数。
这个工具会询问您一系列有关工作负载性质的问题,以便确定配置参数值的起始设置。您可以修改这些参数以满足生产工作负载的需要。
5. 适当地为表列建立索引。
o 确保查询中进行连接操作的列都有索引。
o 如果为 ORDER BY 和 GROUP BY 所涉及的列建立了索引,那么可以提高性能。
o 也可以将经常被访问的数据作为 INCLUDE 子句中的列包含在索引中。
o 根据所使用的表和 SQL 语句,使用索引顾问程序(Index Advisor)(也称为索引向导 (Index Wizard),可以从 DB2 控制中心调用该程序)来帮助确定使用一组合适的索引。
6. 确保应用程序持有锁的时间尽可能短。
o 当用户操作涉及多个交互作用时,每个交互作用应当提交自己的事务并且应当在将活动返回给用户之前释放所有锁。通过尽可能晚地启动事务的第一个 SQL 语句(它启动一个事务)并使事务的更新(插入、更新和删除,这些操作要用到互斥锁)尽可能接近提交阶段,从而使事务的持续时间尽可能的短。
o 使用 DB2 注册表参数 DB2_RR_TO_RS,通过不锁定插入或更新行的下一个键,可以改进并发性。如果对同一组表进行操作的任何程序都没有使用隔离级别 RR(可重复读,Repeatable Read),那么就可以使用上述操作。使用 DB2 快照(DB2 Snapshot)监控死锁和锁等待的数目。
7. 使用存储过程或复合 SQL 使网络成本降到最低。
o 将用于 SQL 语句的网络往返通信次数降至最低,可以减少网络等待时间和上下文切换,这样可以使应用程序持锁的时间更短。通常,当 OLTP 事务有 4 个或 5 个以上语句时应当使用存储过程。
o 另一方面,如果应用程序逻辑中涉及了某个复杂的 CPU 密集型处理,那么将它放在运行于数据库服务器上的存储过程中会用光数据库服务器上的额外 CPU 周期,从而牺牲一些数据库操作。在这种情况下,要么不使用存储过程,要么在客户机端执行一部分逻辑,而在存储过程中执行其余的逻辑。
8. 有效地使用 SQL。
o 通常,如果一条 SQL 语句能完成任务,那么就不使用多条 SQL 语句。当通过在查询中设置更多谓词来提供更详细的搜索条件时,优化器就有机会作出更好的选择。您还应该使查询具有可选择性,这样数据库就不会返回您不需要的行和列。例如,使用 SQL 来过滤您想要的行;不用返回所有行,然后要求应用程序执行过滤操作。
9. 分析存取方案。
o 使用可视化说明(Visual Explain)或 db2exfmt 来分析每一条 SQL 语句。请确保使用合适的索引,从而在选择和连接(join)表时,将必须在内部访存的行数减到最少。
RUNSTATS 实用程序用于更新系统目录表中的统计信息,以帮助查询优化过程。如果没有这些统计信息,数据库管理器可能会做出对 SQL 语句的性能产生不利影响的决定。RUNSTATS 实用程序允许您收集表和/或索引中所包含数据的统计信息。使用 RUNSTATS 实用程序收集基于表和索引数据的统计信息,以便为下列情形中的存取方案选择过程提供精确的信息:
· 当向表装入数据并创建了合适的索引时。
· 当用 REORG 实用程序重新组织表时。
· 当存在大量影响表及其索引的更新、删除和插入操作时。(此处的“大量”可能意味着 10% 到 20% 的表和索引数据都受到了影响。)
· 在绑定性能至关重要的应用程序之前。
· 当您希望将新的和以前的统计信息进行比较时。定期进行统计使您能够在早期阶段发现性能问题。
· 当预取数量发生变化时。
· 当您已经使用了 REDISTRIBUTE NODEGROUP 实用程序时。
当对 SQL 查询进行优化时,SQL 编译器所做出的决定会受到优化器的数据库内容模型的重大影响。优化器使用该数据模型来估计可以用于解决某个特定查询的其它存取路径的成本。数据模型中的关键元素是一组统计信息,该统计信息收集了有关数据库中所包含的数据和系统目录表中所存储的数据的信息。这包括表、别名(nickname)、索引、列和用户定义的函数(UDF)的统计信息。数据统计信息中的变化会引起对存取方案的选择发生变化,该存取方案作为访问所期望数据的最有效方法。
下面列举了一些统计信息,这些统计信息可以帮助给优化器定义数据模型:
· 表中的页数和非空的页数。
· 从原始页移到其它(溢出)页的程度。
· 表中的行数。
· 有关单个列的统计信息,比如一列中唯一值的数量。
· 一个索引的群集程度;即,表中行的物理顺序与索引的符合程度。
· 有关索引的统计信息,比如索引级别的数量和每个索引中叶子页的数量。
· 经常使用的列值的出现次数。
· 列值在列中所有值中的分布状况。
· 用户定义的函数(UDF)的成本估计。
RUNSTATS 可以帮助您确定对数据库的更改与性能之间的关系。统计信息显示出表中的数据分布状况。常规使用时,RUNSTATS 提供了在一段时期内有关表和索引的数据,从而随着时间的流逝,可以确定数据模型的性能趋势。在使用 RUNSTATS 之后需要重新绑定使用静态 SQL 的应用程序,这样查询优化器就可以选择新统计信息所给出的最佳存取方案。但是,对于使用动态 SQL 的应用程序(比如大多数供应商应用程序)而言,没必要进行重新绑定,因为语句的优化是根据统计信息在运行时进行的。当有关表的统计信息不准确时,可能会造成性能问题。最糟的情况是,某个特定的 SQL 语句可能会造成 DB2 使用表扫描而不是使用索引扫描。
只有当进行显式的请求时,对象的统计信息才会在系统目录表中被更新。有几种方法可以更新部分或全部统计信息:
· 使用 RUNSTATS(运行统计信息,run statistics)实用程序。
· 使用带有指定的统计信息收集选项的 LOAD。
· 对针对一组预先定义的目录视图进行操作的 SQL UPDATE 语句进行编码。
· 使用“reorgchk update statistics”命令。
当您不完全知道所有表名或表名实在太多时,进行 RUNSTATS 的最简单方法就是使用“db2 reorgchk update statistics”命令。正确的脚本如下:
db2 -v connect to DB_NAME
db2 -v "select tbname, nleaf, nlevels, stats_time from sysibm.sysindexes"
db2 -v reorgchk update statistics on table all
db2 -v "select tbname, nleaf, nlevels, stats_time from sysibm.sysindexes"
db2 -v terminate
我们上面所选的示例不需要表名。这一命令对所有表执行 RUNSTATS。
记住: 在填充数据库之后再运行 RUNSTATS 实用程序。
如果您知道表名并且想避免对大量表运行 RUNSTATS 实用程序(因为这样做可能要花很长时间),那么一次对一张表进行 RUNSTATS 更为可取。命令如下:
db2 -v runstats on table
TAB_NAME and indexes all
这个命令将收集该表及其所有索引(基本级别)的统计信息。
要查看是否对数据库执行了 RUNSTATS,一种快捷方法便是查询一些系统目录表。例如,如上面的脚本所示,可以运行下面这条命令:
db2 -v "select tbname, nleaf, nlevels, stats_time from sysibm.sysindexes"
如果还未运行 RUNSTATS,您会看到 nleaf 和 nlevels 列为“-1”且 stats_time 列为“-”。如果已经运行了 RUNSTATS,则这些列包含实际的数字,并且如果运行过 RUNSTATS,则 stats_time 列将包含时间戳记。如果您认为 stats_time 中所示时间离现在已有很长一段时间,那就该再次运行 RUNSTATS。
下面这些有关数据库配置调优的技巧将使您在 OLTP 环境中取得非常好的性能,同时使您能够避免显而易见的“陷阱”。在配置参数中,数据库管理器配置参数需要重新启动数据库管理器,而为了使更改生效,大多数数据库配置参数都要求应用程序重新连接到数据库。
这里描述的配置参数包括:
· 缓冲池大小
· 日志缓冲区大小
· 应用程序堆大小
· 排序堆大小和排序堆阈值
· 代理程序的数目
· 锁
· 活动应用程序的最大数目
· 异步页清除程序的数目
· I/O 服务器的数目
· 编入组中的提交数目
缓冲池是内存中的一块存储区域,用于临时读入和更改数据库页(包含表行或索引项)。缓冲池的用途是为了提高数据库系统的性能。从内存访问数据要比从磁盘访问数据快得多。因此,数据库管理器需要从磁盘读取或写入磁盘的次数越少,性能就越好。对一个或多个缓冲池进行配置之所以是调优的最重要方面,是因为连接至数据库的应用程序的大多数数据(不包括大对象和长字段数据)操作都在缓冲池中进行。
缺省情况下,应用程序使用缓冲池 IBMDEFAULTBP,它是在创建数据库时创建的。当 SYSCAT.BUFFERPOOLS 目录表中该缓冲池的 NPAGES 值为 -1 时,DB2 数据库配置参数 BUFFPAGE 控制着缓冲池的大小。否则会忽略 BUFFPAGE 参数,并且用 NPAGES 参数所指定的页数创建缓冲池。
对于仅使用一个缓冲池的应用程序,将 NPAGES 更改成 -1,这样 BUFFPAGE 就可以控制该缓冲池的大小。这使得更新和报告缓冲池大小以及其它 DB2 数据库配置参数变得更加方便。
确保可以使用数据库配置中的 BUFFPAGE 参数来控制缓冲池大小之后,将该参数设置成合适的值。根据数据库的大小和应用程序的性质将该参数设置成一个合理的大值,这种做法很安全。通常,该参数的缺省值非常小,可能满足不了要求。请考虑下列情况:
· 一开始,如果您的机器上有足够大的内存,请将 BUFFPAGE 设置成 40000 个页(160 MB),或者等于机器总内存的 10%。
· 对于大型 OLTP 数据库,在保持系统稳定的同时为缓冲池留出尽可能多的内存。一开始,先尝试使用 1.6 GB 的内存,然后尝试用更多内存。
运行下面这个脚本,以便:
1. 验证目录值
2. 启用数据库配置参数 BUFFPAGE
3. 更新所有数据库的 BUFFPAGE 值。
4.
db2 -v connect to DB_NAME
db2 -v select * from syscat.bufferpools
db2 -v alter bufferpool IBMDEFAULTBP size -1
db2 -v connect reset
db2 -v update db cfg for dbname using BUFFPAGE bigger_value
db2 -v terminate
要确定数据库的缓冲池大小是否由 BUFFPAGE 参数所决定,请运行:
db2 -v connect to DB_NAME
db2 -v SELECT * from SYSCAT.BUFFERPOOLS
db2 -v connect reset
db2 -v terminate
检查结果。如果每个缓冲池都有一个为“-1”的 NPAGES 值,那么缓冲池大小是由数据库配置中的 BUFFPAGE 参数控制的。
要确定缓冲池大小是否足够大,请在运行应用程序时收集数据库和/或缓冲池的快照。类似于下面的脚本为您提供这些所需的信息:
db2 -v update monitor switches using bufferpool on
db2 -v get monitor switches
db2 -v reset monitor all
-- run your application --
db2 -v get snapshot for all databases > snap.out
db2 -v get snapshot for dbm >> snap.out
db2 -v get snapshot for all bufferpools >> snap.out
db2 -v reset monitor all
db2 -v terminate
请确保您在断开数据库连接之前发出“db2 -v get snapshot”。当最后一个应用程序与数据库断开连接时,该数据库停止运行,同时所有快照统计信息将会丢失。要确保一直存在使数据库处于正常运行状态的连接,请使用下列方法之一:
· 在收集快照的窗口中保持一个单独的连接。
· 使用 DB2 ACTIVATE DATABASE 命令。
在数据库快照或缓冲池快照的快照输出中,查找下列“logical reads”和“physical reads”,这样就可以计算出缓冲池命中率,它可以帮助您调优缓冲池:
-- Related lines from a sample of bufferpool snapshots --
Buffer pool data logical reads = 702033
Buffer pool data physical reads = 0
Buffer pool data writes = 414
Buffer pool index logical reads = 168255
Buffer pool index physical reads = 0
缓冲池命中率表明数据库管理器不需要从磁盘装入页(即该页已经在缓冲池中)就能处理页请求的时间百分比。缓冲池的命中率越高,使用磁盘 I/O 的频率就越低。按如下计算缓冲池命中率:
(1 - ((buffer pool data physical reads + buffer pool index physical reads) /
(buffer pool data logical reads + pool index logical reads))
) * 100%
这个计算考虑了缓冲池高速缓存的所有页(索引和数据)。理想情况下,该比率应当超过 95%,并尽可能接近 100%。要提高缓冲池命中率,请尝试下面这些方法:
· 增加缓冲池大小。
· 考虑分配多个缓冲池,如果可能的话,为每个经常被访问的大表所属的表空间分配一个缓冲池,为一组小表分配一个缓冲池,然后尝试一下使用不同大小的缓冲池以查看哪种组合会提供最佳性能。
如果已分配的内存不能帮助提高性能,那么请避免给缓冲池分配过多的内存。应当根据取自测试环境的快照信息来决定缓冲池的大小。
LOGBUFSZ 是一个数据库配置参数。它是用于日志缓冲区的参数。它允许您指定数据库共享内存的大小以用作在将日志记录写到磁盘之前这些记录的缓冲区。当下列事件之一发生时会将日志记录写到磁盘:
· 事务提交。
· 日志缓冲区已满。
· 其它某个内部数据库管理器事件发生时。
将日志记录存在缓冲区将产生更加有效的日志文件 I/O,这是因为这样一来可以降低将日志记录写到磁盘的频率,同时每次可写更多的日志记录。如果对专用的日志磁盘有相当多的读操作,或者希望有较高的磁盘利用率,那么可以增加这个缓冲区的大小。当增加这个参数的值时,也要考虑 DBHEAP 参数,因为日志缓冲区使用的空间由 DBHEAP 参数所控制。
我们发现该参数的缺省值为 8(4KB 页),这对于 OLTP 数据库而言通常不够大。LOGBUFSZ 的最佳值为 128 个或 256 个 4KB 页。例如,可以使用下面这个命令来更改该参数值:
db2 -v update database cfg for DB_NAME using LOGBUFSZ 256
db2 -v terminate
通过查看下面这个示例中所示各行,使用数据库快照来确定 LOGBUFSZ 参数的值是否为最佳值:
Log pages read = 0
Log pages written = 12644
一般而言,“log pages read”和“log pages written”之比应当尽可能小。理想情况下,“log pages read”的值应为 0,而“log pages written”的值应很大。当 log pages read 太多时,意味着需要一个较大的 LOGBUFSZ。
APPHEAPSZ 是一个数据库配置参数,它定义了代表某个特定代理程序或子代理程序的数据库管理器可以使用的私有内存页数。在为应用程序初始化代理程序或子代理程序时分配堆。分配的堆大小是处理给予代理程序或子代理程序的请求所需的最小值。当代理程序或子代理程序需要更多的堆空间以处理较大的 SQL 语句时,数据库管理器将按照需要分配内存,所分配的内存大小最大可达到该参数所指定的最大值。
下面这条命令可以将缺省值(DB2 EE 为 128 个 4KB 页,DB2 EEE 为 64 个 4KB 页)更改成最佳值:
db2 -v update db cfg for DB_NAME using applheapsz 256
db2 -v terminate
当应用程序接收到一个表明应用程序堆中存储空间不够的错误时,应该增加 APPHEAPSZ 的值。
SORTHEAP 是一个数据库配置参数,它定义了私有排序所使用的私有内存页的最大数目,或共享排序所使用的共享内存页的最大数目。如果排序是私有排序,那么该参数影响代理程序私有内存。如果排序是共享排序,那么该参数影响数据库的共享内存。每个排序都有单独的由数据库管理器按需分配的排序堆。在排序堆中对数据进行排序。如果由优化器来指导排序堆大小的分配,那么用优化器提供的信息来分配的排序堆的大小要小于由该参数所指定的排序堆大小。
SHEAPTHRES 是一个数据库管理器配置参数。私有和共享排序所使用内存的来源不一样。共享排序内存区的大小是在第一次连接到数据库时根据 SHEAPTHRES 值以静态方式预先确定的。私有排序内存区的大小是不受限制的。对于私有排序和共享排序,应用 SHEAPTHRES 参数的方式不同:
· 对于私有排序,SHEAPTHRES 是对私有排序在任何给定的时间可以消耗的全部内存的实例级“软”限制。当实例的总私有排序内存消耗量达到这一限制时,为其它进入的私有排序请求而分配的内存会大大减少。
· 对于共享排序,SHEAPTHRES 是对共享排序在任何给定的时间可以消耗的全部内存的数据库级“硬”限制。当达到这一限制时,不允许有其它共享排序内存请求,直到总的共享内存消耗量回落到 SHEAPTHRES 所指定的限制以下。
使用排序堆的操作示例包括内存中表的散列连接和操作。阈值的显式定义防止数据库管理器将过多数量的内存用于大量排序。
· 使用数据库系统监视器来跟踪排序活动。
· 使用合适的索引使排序堆的使用降到最低。
· 当需要频繁进行大型排序时,增加 SORTHEAP 的值。
· 如果增加 SORTHEAP,请确定是否还需要调整数据库管理器配置文件中的 SHEAPTHRES 参数。
· 优化器用排序堆大小来确定存取路径。在更改该参数后请考虑重新绑定应用程序(使用 REBIND PACKAGE 命令)。
· 理想情况下,应当将排序堆阈值(SHEAPTHRES)参数合理地设置为在数据库管理器实例中设置的 SORTHEAP 参数最大值的倍数。该参数至少应当是实例中任何数据库所定义的最大 SORTHEAP 的两倍。
要更改 SORTHEAP 和 SHEAPTHRES 的值,请运行以下命令:
-- SORTHEAP should be changed for individual database --
db2 -v update db cfg for DB_NAME using SORTHEAP a_value
-- SHEAPTHRES is a database manager parameter --
db2 -v update dbm cfg using SHEAPTHRES b_value
db2 -v terminate
OLTP 应用程序不应该执行大型排序。大型排序在 CPU 和 I/O 资源方面的成本太高了。通常,SORTHEAP 大小的缺省值(256 个 4KB 页)就足够了。事实上,对于高并发性 OLTP,您可能希望降低这个缺省值。当需要进一步研究时,可以发出下面这条命令:
myfriend2010 发表于:2007.09.20 19:47 ::分类: (db2 ) ::阅读:(37815次) ::评论 (6)
===========================================================
db2job生成时报DBA1177N 错误的解决过程!
===========================================================
问:当 DB2 的用户启动 DB2 任务中心时,有时会遇到如下错误信息:DBA1177N 不能与“工具目录数据库” "<数据库名>" 建立数据库连接。SQLCODE=1013
而进一步的 SQLCODE=1013 表明:SQL1013N 找不到数据库别名或数据库名 "<名称>"。
解释:命令中指定的数据库名或别名不是现有的数据库,或在(客户机或服务器)数据库目录中找不到该数据库。
解决;
get admin cfg
得到如下字段的配置
EXEC_EXP_TASK、SCHED_ENABLE、SMTP_SERVER、TOOLSCAT_DB、TOOLSCAT_INST、TOOLSCAT_SCHEMA、User ID
用如下命令将它置为空
update admin cfg using <参数> <值>
然后db2admin stop
db2admin start
就可以!
解答:(从网上找的资料)
在 DB2 任务中心里创建的任务是存放在工具目录数据库中,由 DB2 管理服务器(DAS)的调度程序来管理的。调度程序作为 DB2 的一个代理进程对工具目录数据库进行读取,然后在其指定的时间执行。调度程序可从 DB2 管理服务器配置文件中获取到工具目录数据库的位置,以及调度程序是否被启用的信息。当工具目录数据库创建后, DB2 将自动修改 DAS 配置参数中相应的 SCHED_ENABLE,TOOLSCAT_DB,TOOLSCAT_INST 和 TOOLSCAT_SCHEMA 的状态,以便在不用重新启动 DAS 的情况下启用调度程序和定义工具目录数据库的位置。下面一段配置参数的内容就是在创建了工具目录数据库之后利用 “ get admin cfg ” 命令取得的:
Execute Expired Tasks (EXEC_EXP_TASK) = NO
Scheduler Mode (SCHED_ENABLE) = ON
SMTP Server (SMTP_SERVER) =
Tools Catalog Database (TOOLSCAT_DB) = TOOLSDB
Tools Catalog Database Instance (TOOLSCAT_INST) = DB2
Tools Catalog Database Schema (TOOLSCAT_SCHEMA) = TOOLSDB
Scheduler User ID =
其中:
SCHED_ENABLE - 表明调度程序是否被管理服务器启动。
TOOLSCAT_DB - 表明调度程序所使用的工具目录数据库,此数据库必须在由 TOOLSCAT_INST 指定的实例的目录数据库中。
TOOLSCAT_INST - 表明调度程序使用的工具目录数据库的本地实例名,它与 TOOLSCAT_DB 和 TOOLSCAT_SCHEMA 一起用于标识工具目录数据库。
TOOLSCAT_SCHEMA - 表明调度程序使用的工具目录数据库的模式名。此模式名用来唯一标识在数据库内的一套工具目录表和视图。
如果 DAS 被删除后又重新创建,则上述 DAS 的参数将被重新置回缺省值,即:
Execute Expired Tasks (EXEC_EXP_TASK) = NO
Scheduler Mode (SCHED_ENABLE) = OFF
SMTP Server (SMTP_SERVER) =
Tools Catalog Database (TOOLSCAT_DB) =
Tools Catalog Database Instance (TOOLSCAT_INST) =
Tools Catalog Database Schema (TOOLSCAT_SCHEMA) =
Scheduler User ID =
此时任何试图启动任务中心的操作都会返回上述 DBA1177N 的错误信息。当用户使用:
update admin cfg using <参数> <值>
的命令将上述各参数重新配置成删除之前的值后,重新启动任务中心,便可成功打开任务中心,最终解决该问题。
myfriend2010 发表于:2007.09.15 11:42 ::分类: (db2 ) ::阅读:(934次) ::评论 (0)
===========================================================
DB2十佳性能调优技巧
===========================================================
内容
提要 本文总结了针对DB2性能调优的十个宝典,对于DBA非常有帮助.
正文 每隔大约几个星期,我们就会接到苦恼的 DBA 们的电话,抱怨有关性能的问题。“我们 Web 站点速度慢得像蜗牛一样”,他们叫苦道,“我们正在失去客户,情况严重。你能帮忙吗?”为了回答这些问题,我为我的咨询公司开发了一个分析流程,它能让我们很快找到性能问题的原因,开发出补救措施并提出调整意见。这些打电话的人极少询问费用和成本 - 他们只关心制止损失。当 DB2 或电子商务应用程序的运行不能达到预期的性能时,组织和财务的收益将遭受极大的损失。
为了帮助 DB2 DBA 避免性能灾难并获得高性能,我为我们的客户、用户和 DB2 专家同行总结了一套故障诊断流程。以下详细说明在 Unix、Windows 和 OS/2 环境下使用 DB2 UDB 的电子商务 OLTP 应用程序的 10 条最重要的性能改善技巧 - 并在本文的结束部分作出总结。
10. 监视开关
确保已经打开监视开关。如果它们没有打开,您将无法获取您需要的性能信息。要打开该监视开关,请发出以下命令:
db2 "update monitor switches using
lock ON sort ON bufferpool ON uow ON
table ON statement ON"
9. 代理程序
确保有足够的 DB2 代理程序来处理工作负载。要找出代理程序的信息,请发出命令:
db2 "get snapshot for database manager"
并查找以下行:
High water mark for agents registered = 7
High water mark for agents waiting for a token = 0
Agents registered= 7
Agents waiting for a token= 0
Idle agents= 5
Agents assigned from pool= 158
Agents created from empty Pool = 7
Agents stolen from another application= 0
High water mark for coordinating agents= 7
Max agents overflow= 0
如果您发现 Agents waiting for a token 或 Agents stolen from another application 不为 0,那么请增加对数据库管理器可用的代理程序数(MAXAGENTS 和/或 MAX_COORDAGENTS 取适用者)。
8. 最大打开的文件数
DB2 在操作系统资源的约束下尽量做一个“优秀公民”。它的一个“优秀公民”的行动就是给在任何时刻打开文件的最大数设置一个上限。数据库配置参数 MAXFILOP 约束 DB2 能够同时打开的文件最大数量。当打开的文件数达到此数量时,DB2 将开始不断地关闭和打开它的表空间文件(包括裸设备)。不断地打开和关闭文件减缓了 SQL 响应时间并耗费了 CPU 周期。要查明 DB2 是否正在关闭文件,请发出以下命令:
db2 "get snapshot for database on DBNAME"
并查找以下的行:
Database files closed = 0
如果上述参数的值不为 0,那么增加 MAXFILOP 的值直到不断打开和关闭文件的状态停止。使用以下命令:
db2 "update db cfg for DBNAME using MAXFILOP N"
7. 锁
LOCKTIMEOUT 的缺省值是 -1,这意味着将没有锁超时(对 OLTP 应用程序,这种情况可能会是灾难性的)。尽管如此,我还是经常发现许多 DB2 用户用 LOCKTIMEOUT = -1。将 LOCKTIMEOUT 设置为很短的时间值,例如 10 或 15 秒。在锁上等待过长时间会在锁上产生雪崩效应。
首先,用以下命令检查 LOCKTIMEOUT 的值:
db2 "get db cfg for DBNAME"
并查找包含以下文本的行:
Lock timeout (sec) (LOCKTIMEOUT) = -1
如果值是 -1,考虑使用以下命令将它更改为 15 秒(一定要首先询问应用程序开发者或您的供应商以确保应用程序能够处理锁超时):
db2 "update db cfg for DBNAME using LOCKTIMEOUT 15"
您同时应该监视锁等待的数量、锁等待时间和正在使用锁列表内存(lock list memory)的量。请发出以下命令:
db2 "get snapshot for database on DBNAME"
查找以下行:
Locks held currently= 0
Lock waits= 0
Time database waited on locks (ms)= 0
Lock list memory in use (Bytes)= 576
Deadlocks detected= 0
Lock escalations= 0
Exclusive lock escalations= 0
Agents currently waiting on locks= 0
Lock Timeouts= 0
如果 Lock list memory in use (Bytes) 超过所定义 LOCKLIST 大小的 50%,那么在 LOCKLIST 数据库配置中增加 4k 页的数量。
6. 临时表空间
为了改善 DB2 执行并行 I/O 和提高使用 TEMPSPACE 的排序、散列连接(hash join)和其它数据库操作的性能,临时表空间至少应该在三个不同的磁盘驱动器上拥有三个容器。
要想知道您的临时表空间具有多少容器,请发出以下命令:
db2 "list tablespaces show detail"
查找与以下示例类似的 TEMPSPACE 表空间定义:
Tablespace ID= 1
Name= TEMPSPACE1
Type= System managed space
Contents= Temporary data
State= 0x0000
Detailed explanation: Normal
Total pages= 1
Useable pages= 1
Used pages= 1
Free pages= Not applicable
High water mark (pages)= Not applicable
Page size (bytes)= 4096
Extent size (pages)= 32
Prefetch size (pages)= 96
Number of containers= 3
注意 Number of containers 的值是 3,而且 Prefetch size 是 Extent size 的三倍。为了得到最佳的并行 I/O 性能,重要的是 Prefetch size 为 Extent size 的倍数。这个倍数应该等于容器的个数。
要查找容器的定义,请发出以下命令:
db2 "list tablespace containers for 1 show detail"
1 指的是 tablespace ID #1,它是刚才所给出的示例中的 TEMPSPACE1。
5. 内存排序
OLTP 应用程序不应该执行大的排序。它们在 CPU、I/O 和所用时间方面的成本极高,而且将使任何 OLTP 应用程序慢下来。因此,256 个 4K 页(1MB)的缺省 SORTHEAP 大小(1MB)应该是足够了。您也应该知道排序溢出的数量和每个事务的排序数。
请发出以下命令:
Db2 "get snapshot for database on DBNAME"
并查找以下行:
Total sort heap allocated= 0
Total sorts = 1
Total sort time (ms)= 8
Sort overflows = 0
Active sorts = 0
Commit statements attempted = 3
Rollback statements attempted = 0
Let transactions = Commit statements attempted + Rollback
statements attempted
Let SortsPerTX= Total sorts / transactions
Let PercentSortOverflows = Sort overflows * 100 / Total sorts
如果 PercentSortOverflows ((Sort overflows * 100) / Total sorts ) 大于 3 个百分点,那么在应用程序 SQL 中会出现严重的或意外的排序问题。因为正是溢出的存在表明发生了大的排序,所以理想的情况是发现没有排序溢出或至少其百分比小于一个百分点。
如果出现过多的排序溢出,那么“应急”解决方案是增加 SORTHEAP 的大小。然而,这样做只是掩盖了真实的性能问题。相反,您应该确定引起排序的 SQL 并更改该 SQL、索引或群集来避免或减少排序开销。
如果 SortsPerTX 大于 5 (作为一种经验之谈),那么每个事务的排序数可能很大。虽然某些应用程序事务执行许多小的组合排序(它们不会溢出并且执行时间很短),但是它消耗了过多的 CPU。当 SortsPerTX 很大时,按我的经验,这些机器通常会受到 CPU 的限制。确定引起排序的 SQL 并改进存取方案(通过索引、群集或更改 SQL)对提高事务吞吐率是极为重要的。
4. 表访问
对于每个表,确定 DB2 为每个事务读取的行数。您必须发出两个命令:
db2 "get snapshot for database on DBNAME"
db2 "get snapshot for tables on DBNAME"
在发出第一个命令以后,确定发生了多少个事务(通过取 Commit statements attempted 和 Rollback statements attempted 之和 - 请参阅技巧 3)。
在发出第二个命令以后,将读取的行数除以事务数(RowsPerTX)。在每个事务中,OLTP 应用程序通常应该从每个表读取 1 到 20 行。如果您发现对每个事务有成百上千的行正被读取,那么发生了扫描操作,也许需要创建索引。(有时以分布和详细的索引来运行 runstats 也可提供了一个解决的办法。)
“get snapshot for tables on DBNAME”的样本输出如下:
Snapshot timestamp = 09-25-2000
4:47:09.970811
Database name= DGIDB
Database path= /fs/inst1/inst1/NODE0000/SQL00001/
Input database alias= DGIDB
Number of accessed tables= 8
Table List
Table Schema= INST1
Table Name= DGI_
SALES_ LOGS_TB
Table Type= User
Rows Written= 0
Rows Read= 98857
Overflows= 0
Page Reorgs= 0
Overflows 的数量很大就可能意味着您需要重组表。当由于更改了行的宽度从而 DB2 必须在一个不够理想的页上定位一个行时就会发生溢出。
3. 表空间分析
表空间快照对理解访问什么数据以及如何访问是极其有价值的。要得到一个表空间快照,请发出以下命令:
db2 "get snapshot for tablespaces on DBNAME"
对每个表空间,回答以下问题:
平均读取时间(ms)是多少?
平均写入时间(ms)是多少?
异步(预取)相对于同步(随机)所占的物理 I/O 的百分比是多少?
每个表空间的缓冲池命中率是多少?
每分钟读取多少物理页面?
对于每个事务要读取多少物理和逻辑页面?
对于所有表空间,回答以下问题:
哪个表空间的读取和写入的时间最慢?为什么?是因为其容器在慢速的磁盘上吗?容器大小是否相等?
对比异步访问和同步访问,访问属性是否和期望的一致?随机读取的表应该有随机读取的表空间,这是为了得到高的同步读取百分比、通常较高的缓冲池命中率和更低的物理 I/O 率。
对每个表空间,确保预取大小等于数据块大小乘以容器数。请发出以下命令:
db2 "list tablespaces show detail"
如果需要,可以为一个给定表空间改变预取大小。可以使用以下命令来检查容器定义:
db2 "list tablespace containers for N show detail"
在此,N 是表空间标识号。
2. 缓冲池优化
我时常发现一些 DB2 UDB 站点,虽然机器具有 2、4 或 8GB 内存,但是 DB2 数据库却只有一个缓冲池(IBMDEFAULTBP),其大小只有 16MB!
如果在您的站点上也是这种情况,请为 SYSCATSPACE 目录表空间创建一个缓冲池、为 TEMPSPACE 表空间创建一个缓冲池以及另外创建至少两个缓冲池:BP_RAND 和 BP_SEQ。随机访问的表空间应该分配给用于随机访问的缓冲池(BP_RAND)。顺序访问(使用异步预取 I/O)的表空间应该分配给用于顺序访问的缓冲池(BP_SEQ)。根据某些事务的性能目标,您可以创建附加的缓冲池;例如,您可以使一个缓冲池足够大以存储整个“热”(或者说访问非常频繁的)表。当涉及到大的表时,某些 DB2 用户将重要表的索引放入一个索引(BP_IX)缓冲池取得了很大成功。
太小的缓冲池会产生过多的、不必要的物理 I/O。太大的缓冲池使系统处在操作系统页面调度的风险中并消耗不必要的 CPU 周期来管理过度分配的内存。正好合适的缓冲池大小就在“太小”和“太大”之间的某个平衡点上。适当的大小存在于回报将要开始减少的点上。如果您没有使用工具来自动进行回报减少分析,那么您应该在不断增加缓冲池大小上科学地测试缓冲池性能(命中率、I/O 时间和物理 I/O 读取率),直到达到最佳的缓冲池大小。因为业务一直在变动和增长,所以应该定期重新评估“最佳大小”决策。
1. SQL 成本分析
一条糟糕的 SQL 语句会彻底破坏您的一整天。我不止一次地看到一个相对简单的 SQL 语句搞糟了一个调整得很好的数据库和机器。对于很多这些语句,天底下(或在文件中)没有 DB2 UDB 配置参数能够纠正因错误的 SQL 语句导致的高成本的情况。
更糟糕的是,DBA 常常受到种种束缚:不能更改 SQL(可能是因为它是应用程序供应商提供的,例如 SAP、PeopleSoft 或 Siebel)。这给 DBA 只留下三条路可走:
1. 更改或添加索引
2. 更改群集
3. 更改目录统计信息
另外,如今健壮的应用程序由成千上万条不同的 SQL 语句组成。这些语句执行的频率随应用程序的功能和日常的业务需要的不同而不同。SQL 语句的实际成本是它执行一次的成本乘以它执行的次数。
每个 DBA 所面临的重大的任务是,识别具有最高“实际成本”的语句的挑战,并且减少这些语句的成本。
通过本机 DB2 Explain 实用程序、一些第三方供应商提供的工具或 DB2 UDB SQL Event Monitor 数据,您可以计算出执行一次 SQL 语句所用的资源成本。但是语句执行频率只能通过仔细和耗时地分析 DB2 UDB SQL Event Monitor 的数据来了解。
在研究 SQL 语句问题时,DBA 使用的标准流程是:
1. 创建一个 SQL Event Monitor,写入文件:
$> db2 "create event monitor SQLCOST for statements write to ..."
2. 激活事件监视器(确保有充足的可用磁盘空间):
$> db2 "set event monitor SQLCOST state = 1"
3. 让应用程序运行。
4. 取消激活事件监视器:
$> db2 "set event monitor SQLCOST state = 0"
5. 使用 DB2 提供的 db2evmon 工具来格式化 SQL Event Monitor 原始数据(根据 SQL 吞吐率可能需要数百兆字节的可用磁盘空间):
$> db2evmon -db DBNAME -evm SQLCOST
> sqltrace.txt
6. 浏览整个已格式化的文件,寻找显著大的成本数(一个耗时的过程):
$> more sqltrace.txt
7. 对已格式化的文件进行更完整的分析,该文件试图标识唯一的语句(独立于文字值)、每个唯一语句的频率(它出现的次数)和其总 CPU、排序以及其它资源成本的总计。如此彻底的分析在 30 分钟的应用程序 SQL 活动样本上可能要花一周或更多的时间。
要减少确定高成本 SQL 语句所花的时间,您可以考虑许多可用的信息来源:
从技巧 4,务必要计算在每个事务中从每个表中读取的行数。如果产生的数字看上去很大,那么 DBA 可以在 SQL Event Monitor 格式化输出中搜索有关的表名称(这将缩小搜索范围而且节省一些时间),这样也许能够找出有问题的语句。
从技巧 3,务必计算每个表空间的异步读取百分比和物理 I/O 读取率。如果一个表空间的异步读取百分比很高并远远超过平均的物理 I/O 读取率,那么在此表空间中的一个或更多的表正在被扫描。查询目录并找出哪些表被分配到可疑的表空间(每个表空间分配一个表提供最佳性能检测),然后在 SQL Event Monitor 格式化输出中搜索这些表。这些也可能有助于缩小对高成本 SQL 语句的搜索范围。
尝试观察应用程序执行的每条 SQL 语句的 DB2 Explain 信息。然而,我发现高频率、低成本语句经常争用机器容量和能力来提供期望的性能。
如果分析时间很短而且最大性能是关键的,那么请考虑使用供应商提供的工具(它们能够快速自动化识别资源密集的 SQL 语句的过程)。Database-GUYS Inc. 的 SQL-GUY 工具提供精确、实时且均衡的 SQL 语句的成本等级分析。
继续调节
最佳性能不仅需要排除高成本 SQL 语句,而且需要确保相应的物理基础结构是适当的。当所有的调节旋钮都设置得恰到好处、内存被有效地分配到池和堆而且 I/O 均匀地分配到各个磁盘时,才可得到最佳性能。虽然量度和调整需要时间,但是执行这 10 个建议的 DBA 将非常成功地满足内部和外部的 DB2 客户。因为电子商务的变化和增长,即使是管理得最好的数据库也需要定期的微调。DBA 的工作永远都做不完!
快速回顾最棒的 10 个技巧
1. 对工作负载使用足够的代理程序。
2. 不允许 DB2 不必要地关闭和打开文件。
3. 不允许长期的锁等待。
4. 确保数据库的 TEMPSPACE 表空间的并行 I/O 能力。
5. 保守地管理 DB2 排序内存并不要以大的 SORTHEAP 来掩盖排序问题。
6. 分析表的访问活动并确定具有特别高的每个事务读取行数或溢出数的表。
7. 分析每个表空间的性能特性,并寻求改善读取时间最慢、等待时间最长、物理 I/O 读取率最高、命中率最差的表空间性能以及与所期望的不一致的访问属性。
8. 创建多个缓冲池,有目的地将表空间分配到缓冲池以便于共享访问属性。
9. 检查 DB2 UDB SQL Event Monitor 信息以找到哪个 SQL 语句消耗计算资源最多并采取正确的措施。
10. 一旦排除了高成本 SQL,马上重新评估配置和物理设计设置。
myfriend2010 发表于:2007.09.04 21:17 ::分类: (db2 ) ::阅读:(919次) ::评论 (0)
===========================================================
DB2编程序技巧
===========================================================
1 DB2编程
1.1 建存储过程时CREATE 后一定不要用TAB键 3
1.2 使用临时表 3
1.3 从数据表中取指定前几条记录 3
1.4 游标的使用 4
注意commit和rollback 4
游标的两种定义方式 4
修改游标的当前记录的方法 5
1.5 类似DECODE的转码操作 5
1.6 类似CHARINDEX查找字符在字串中的位置 5
1.7 类似DATEDIF计算两个日期的相差天数 5
1.8 写UDF的例子 5
1.9 创建含IDENTITY值(即自动生成的ID)的表 6
1.10 预防字段空值的处理 6
1.11 取得处理的记录数 6
1.12 从存储过程返回结果集(游标)的用法 6
1.13 类型转换函数 8
1.14 存储过程的互相调用 8
1.15 C存储过程参数注意 8
1.16 存储过程FENCE及UNFENCE 8
1.17 SP错误处理用法 9
1.18 IMPORT用法 9
1.19 VALUES的使用 9
1.20 给SELECT 语句指定隔离级别 10
1.21 ATOMIC及NOT ATOMIC区别 10
2 DB2编程性能注意 10
2.1 大数据的导表 10
2.2 SQL语句尽量写复杂SQL 10
2.3 SQL SP及C SP的选择 10
2.4 查询的优化(HASH及RR_TO_RS) 11
2.5 避免使用COUNT(*) 及EXISTS的方法 11
3 DB2表及SP管理 12
3.1 看存储过程文本 12
3.2 看表结构 12
3.3 查看各表对SP的影响(被哪些SP使用) 12
3.4 查看SP使用了哪些表 12
3.5 查看FUNCTION被哪些SP使用 12
3.6 修改表结构 12
4 DB2系统管理 13
4.1 DB2安装 13
4.2 创建DATABASE 14
4.3 手工做数据库远程(别名)配置 14
4.4 停止启动数据库实例 14
4.5 连接数据库及看当前连接数据库 14
4.6 停止启动数据库HEAD 15
4.7 查看及停止数据库当前的应用程序 15
4.8 查看本INSTANCE下有哪些DATABASE 15
4.9 查看及更改数据库HEAD的配置 16
4.9.1 改排序堆的大小 16
4.9.2 改事物日志的大小 16
4.9.3 出现程序堆内存不足时修改程序堆内存大小 16
4.10 查看及更改数据库实例的配置 16
4.10.1 打开对锁定情况的监控。 16
4.10.2 更改诊断错误捕捉级别 17
4.11 DB2环境变量 17
4.12 DB2命令环境设置 17
4.13 改变隔离级别 17
4.14 管理DBINSTANCE的参数 18
4.15 升级后消除版本问题 18
4.16 查看数据库表的死锁 18
1 DB2编程
1.1 建存储过程时Create 后一定不要用TAB键
create procedure
的create后只能用空格,而不可用tab健,否则编译会通不过。
切记,切记。
1.2 使用临时表
要注意,临时表只能建在user tempory tables space 上,如果database只有system tempory table space是不能建临时表的。
另外,DB2的临时表和sybase及oracle的临时表不太一样,DB2的临时表是在一个session内有效的。所以,如果程序有多线程,最好不要用临时表,很难控制。
建临时表时最好加上 with replace选项,这样就可以不显示的drop 临时表,建临时表时如果不加该选项而该临时表在该session内已创建且没有drop,这时会发生错误。
1.3 从数据表中取指定前几条记录
select * from tb_market_code fetch first 1 rows only
但下面这种方式不允许
select market_code into v_market_code
from tb_market_code fetch first 1 rows only;
选第一条记录的字段到一个变量以以下方式代替
declare v_market_code char(1);
declare cursor1 cursor for select market_code from tb_market_code
fetch first 1 rows only for update;
open cursor1;
fetch cursor1 into v_market_code;
close cursor1;
1.4 游标的使用
注意commit和rollback
使用游标时要特别注意如果没有加with hold 选项,在Commit和Rollback时,该游标将被关闭。Commit 和Rollback有很多东西要注意。特别小心
游标的两种定义方式
一种为
declare continue handler for not found
begin
set v_notfound = 1;
end;
declare cursor1 cursor with hold for select market_code from tb_market_code for update;
open cursor1;
set v_notfound=0;
fetch cursor1 into v_market_code;
while v_notfound=0 Do
--work
set v_notfound=0;
fetch cursor1 into v_market_code;
end while;
close cursor1;
这种方式使用起来比较复杂,但也比较灵活。特别是可以使用with hold 选项。如果循环内有commit或rollback 而要保持该cursor不被关闭,只能使用这种方式。
1.5 类似decode的转码操作
oracle中有一个函数 select decode(a1,'1','n1','2','n2','n3') aa1 from
db2没有该函数,但可以用变通的方法
select case a1
when '1' then 'n1'
when '2' then 'n2'
else 'n3'
end as aa1 from
1.6 类似charindex查找字符在字串中的位置
Locate(‘y’,’dfdasfay’)
查找’y’ 在’dfdasfay’中的位置。
1.7 类似datedif计算两个日期的相差天数
days(date(‘2001-06-05’)) – days(date(‘2001-04-01’))
days 返回的是从 0001-01-01 开始计算的天数
1.8 写UDF的例子
C写见sqllibsamplescliudfsrv.c
1.9 创建含identity值(即自动生成的ID)的表
建这样的表的写法
CREATE TABLE test
(t1 SMALLINT NOT NULL
GENERATED ALWAYS AS IDENTITY
(START WITH 500, INCREMENT BY 1),
t2 CHAR(1));
在一个表中只允许有一个identity的column
1.10 预防字段空值的处理
SELECT DEPTNO ,DEPTNAME ,COALESCE(MGRNO ,'ABSENT'),ADMRDEPT
FROM DEPARTMENT
COALESCE函数返回()中表达式列表中第一个不为空的表达式,可以带多个表达式。
和oracle的isnull类似,但isnull好象只能两个表达式。
1.11 取得处理的记录数
declare v_count int;
update tb_test set t1=’0’
where t2=’2’;
--检查修改的行数,判断指定的记录是否存在
get diagnostics v_ count=ROW_COUNT;
只对update,insert,delete起作用.
不对select into 有效
1.12 从存储过程返回结果集(游标)的用法
1、建一sp返回结果集
CREATE PROCEDURE DB2INST1.Proc1 ( )
LANGUAGE SQL
result sets 2(返回两个结果集)
------------------------------------------------------------------------
-- SQL 存储过程
------------------------------------------------------------------------
P1: BEGIN
declare c1 cursor with return to caller for
select market_code
from tb_market_code;
--指定该结果集用于返回给调用者
declare c2 cursor with return to caller for
select market_code
from tb_market_code;
open c1;
open c2;
END P1
2、建一SP调该sp且使用它的结果集
CREATE PROCEDURE DB2INST1.Proc2 (
out out_market_code char(1))
LANGUAGE SQL
------------------------------------------------------------------------
-- SQL 存储过程
------------------------------------------------------------------------
P1: BEGIN
declare loc1,loc2 result_set_locator varying;
--建立一个结果集数组
call proc1;
--调用该SP返回结果集。
associate result set locator(loc1,loc2) with procedure proc1;
--将返回结果集和结果集数组关联
allocate cursor1 cursor for result set loc1;
allocate cursor2 cursor for result set loc2;
--将结果集数组分配给cursor
fetch cursor1 into out_market_code;
--直接从结果集中赋值
close cursor1;
END P1
3、动态SQL写法
DECLARE CURSOR C1 FOR STMT1;
PREPARE STMT1 FROM
'ALLOCATE C2 CURSOR FOR RESULT SET ?';
4、注意:
一、 如果一个sp调用好几次,只能取到最近一次调用的结果集。
二、 allocate的cursor不能再次open,但可以close,是close sp中的对应cursor。
1.13 类型转换函数
select cast ( current time as char(8)) from tb_market_code
1.14 存储过程的互相调用
目前,c sp可以互相调用。
Sql sp 可以互相调用,
Sql sp 可以调用C sp,
但C sp 不可以调用Sql sp(最新的说法是可以)
1.15 C存储过程参数注意
create procedure pr_clear_task_ctrl(
IN IN_BRANCH_CODE char(4),
IN IN_TRADEDATE char(8),
IN IN_TASK_ID char(2),
IN IN_SUB_TASK_ID char(4),
OUT OUT_SUCCESS_FLAG INTEGER )
DYNAMIC RESULT SETS 0
LANGUAGE C
PARAMETER STYLE GENERAL WITH NULLS(如果不是这样,sql 的sp将不能调用该用c写的存储过程,产生保护性错误)
NO DBINFO
FENCED
MODIFIES SQL DATA
EXTERNAL NAME 'pr_clear_task_ctrl!pr_clear_task_ctrl'@
1.16 存储过程fence及unfence
fence的存储过程单独启用一个新的地址空间,而unfence的存储过程和调用它的进程使用同一个地址空间。
一般而言,fence的存储过程比较安全。
但有时一些特殊的要求,如要取调用者的pid,则fence的存储过程会取不到,而只有unfence的能取到。
1.17 SP错误处理用法
如果在SP中调用其它的有返回值的,包括结果集、临时表和输出参数类型的SP,
DB2会自动发出一个SQLWarning。而在我们原来的处理中对于SQLWarning都
会插入到日志,这样子最后会出现多条SQLCODE=0的警告信息。
处理办法:
定义一个标志变量,比如DECLARE V_STATUS INTEGER DEFAULT 0,
在CALL SPNAME之后, SET V_STATUS = 1,
DECLARE CONTINUE HANDLER FOR SQLWARNING
BEGIN
IF V_STATUS <> 1 THEN
--警告处理,插入日志
SET V_STATUS = 0;
END IF;
END;
1.18 import用法
db2 import from gh1.out of DEL messages err.txt insert into db2inst1.tb_dbf_match_ha
注意要加schma
1.19 values的使用
如果有多个 set 语句给变量付值,最好使用values语句,改写为一句。这样可以提高效率。
但要注意,values不能将null值付给一个变量。
values(null) into out_return_code;
这个语句会报错的。
1.20 给select 语句指定隔离级别
select * from tb_head_stock_balance with ur
1.21 atomic及not atomic区别
atomic是将该部分程序块指定为一个整体,其中任何一个语句失败,则整个程序块都相当于没做,包括包含在atomic块内的已经执行成功的语句也相当于没做,有点类似于transaction。
2 DB2编程性能注意
2.1 大数据的导表
应该是export后再load性能更好,因为load不写日志。
比select into 要好。
2.2 SQL语句尽量写复杂SQL
尽量使用大的复杂的SQL语句,将多而简单的语句组合成大的SQL语句对性能会有所改善。
DB2的SQL Engieer对复杂语句的优化能力比较强,基本上不用当心语句的性能问题。
Oracle 则相反,推荐将复杂的语句简单化,SQL Engieer的优化能力不是特别好。
这是因为每一个SQL语句都会有reset SQLCODE和SQLSTATE等各种操作,会对数据库性能有所消耗。
一个总的思想就是尽量减少SQL语句的个数。
2.3 SQL SP及C SP的选择
首先,C的sp的性能比sql 的sp 的要高。
一般而言,SQL语句比较复杂,而逻辑比较简单,sql sp 与 c sp 的性能差异会比较小,这样从工作量考虑,用SQL写比较好。
而如果逻辑比较复杂,SQL比较简单,用c写比较好。
2.4 查询的优化(HASH及RR_TO_RS)
db2set DB2_HASH_JOIN=Y (HASH排序优化)
指定排序时使用HASH排序,这样db2在表join时,先对各表做hash排序,再join,这样可以大大提高性能。
剧沈刚说做实验,7个一千万条记录表的做join取10000条记录,再没有索引的情况下 72秒。
db2set DB2_RR_TO_RS=Y
该设置后,不能定义RR隔离级别,如果定义RR,db2也会自动降为RS.
这样,db2不用管理Next key,可以少管理一些东西,这样可以提高性能。
2.5 避免使用count(*) 及exists的方法
1、首先要避免使用count(*)操作,因为count(*)基本上要对表做全部扫描一遍,如果使用很多会导致很慢。
2、exists比count(*)要快,但总的来说也会对表做扫描,它只是碰到第一条符合的记录就停下来。
如果做这两中操作的目的是为
select into 服务的话,就可以省略掉这两步。
直接使用select into 选择记录中的字段。
如果是没有记录选择到的话,db2 会将 sqlcode=100 和 sqlstate=’20000’
如果是有多条记录的话,db2会产生一个错误。
程序可以创建 continue handler for exception
continue handler for not found
来检测。
这是最快速的方法。
3、如果是判断是不是一条,可以使用游标来计算,用一个计数器,累加,达到预定值后就离开。这个速度也比count(*) 要快,因为它只要扫描到预定值就不再扫描了,不用做全表的scan,不过它写起来比较麻烦。
3 DB2表及sp管理
3.1 看存储过程文本
select text from syscat.procedures where procname='PROC1';
3.2 看表结构
describe table syscat.procedures
describe select * from syscat.procedures
3.3 查看各表对sp的影响(被哪些sp使用)
select PROCNAME from SYSCAT.PROCEDURES where SPECIFICNAME in(select dname from sysibm.sysdependencies where bname in ( select PKGNAME from syscat.packagedep where bname='TB_BRANCH'))
3.4 查看sp使用了哪些表
select bname from syscat.packagedep where btype='T' and pkgname in(select bname from sysibm.sysdependencies where dname in (select specificname from syscat.procedures where procname='PR_CLEAR_MATCH_DIVIDE_SHA'))
3.5 查看function被哪些sp使用
select PROCNAME from SYSCAT.PROCEDURES where SPECIFICNAME in(select dname from sysibm.sysdependencies where bname in ( select PKGNAME from syscat.packagedep where bname in (select SPECIFICNAME from SYSCAT.functions where funcname='GET_CURRENT_DATE')))
使用function时要注意,如果想drop 掉该function必须要先将调用该function的其它存储过程全部drop掉。
必须先创建function,调用该function的sp才可以创建成功。
3.6 修改表结构
一次给一个表增加多个字段
db2 "alter table tb_test add column t1 char(1) add column t2 char(2) add column t3 int"
4 DB2系统管理
4.1 DB2安装
在Windows 98 下安装db2 7.1 或其他版本,如果有Jdbc错误或者是Windwos 98不能启动,则将autoexec.bat 中的内容用如下内容替换:
C:PROGRA~1TRENDP~1PCSCAN.EXE C: C:WINDOWSCOMMAND /NS /WIN95
rem C:WINDOWSCOMMAND.COM /E:32768
REM [Header]
REM [CD-ROM Drive]
REM [Miscellaneous]
REM [Display]
set PATH=%PATH%;C:MSSQLBINN;C:PROGRA~1SQLLIBBIN;C:PROGRA~1SQLLIBFUNCTION;C:PROGRA~1SQLLIBSAMPLESREPL;C:PROGRA~1SQLLIBHELP
IF EXIST C:PROGRA~1IBMIMNNQIMQENV.BAT CALL C:PROGRA~1IBMIMNNQIMQENV.BAT
IF EXIST C:PROGRA~1IBMIMNNQIMNENV.BAT CALL C:PROGRA~1IBMIMNNQIMNENV.BAT
set DB2INSTANCE=DB2
set CLASSPATH=.;C:PROGRA~1SQLLIBjavadb2java.zip;C:PROGRA~1SQLLIBjava untime.zip;C:PROGRA~1SQLLIBjavasqlj.zip;C:PROGRA~1SQLLIBin
set MDIS_PROFILE=C:PROGRA~1SQLLIBMETADATAPROFILES
set LC_ALL=ZH_CN
set INCLUDE=C:PROGRA~1SQLLIBINCLUDE;C:PROGRA~1SQLLIBLIB;C:PROGRA~1SQLLIBTEMPLATESINCLUDE
set LIB=C:PROGRA~1SQLLIBLIB
set DB2PATH=C:PROGRA~1SQLLIB
set DB2TEMPDIR=C:PROGRA~1SQLLIB
set VWS_TEMPLATES=C:PROGRA~1SQLLIBTEMPLATES
set VWS_LOGGING=C:PROGRA~1SQLLIBLOGGING
set VWSPATH=C:PROGRA~1SQLLIB
set VWS_FOLDER=IBM DB2
set ICM_FOLDER=信息目录管理器
4.2 创建Database
create database head using codeset IBM-eucCN territory CN;
这样可以支持中文。
4.3 手工做数据库远程(别名)配置
db2 catalog tcpip node node1 remote 172.28.200.200 server 50000
db2 catalog db head as test1 at node node1
然后既可使用:
db2 connect to test1 user … using …
连上head库了
4.4 停止启动数据库实例
db2start
db2stop (force)
4.5 连接数据库及看当前连接数据库
连接数据库
db2 connect to head user db2inst1 using db2inst1
当前连接数据库
db2 connect
4.6 停止启动数据库head
db2 activate db head
db2 deactivate db head
要注意的是,如果有连接,使用deactivate db 不起作用。
如果是用activate db启动的数据库,一定要用deactivate db才会停止该数据库。(当然如果是db2stop也会停止)。
使用activate db,这样可以减少第一次连接时的等待时间。
Database如果不是使用activate db启动而是通过连接数据库而启动的话,当所有的连接都退出后,db也就自动停止。
4.7 查看及停止数据库当前的应用程序
查看应用程序:
db2 list applications show detail
授权标识 | 应用程序名 | 应用程序句柄 | 应用程序标识 | 序号# | 代理程序 | 协调程序 | 状态 | 状态更改时间 | DB 名 | DB 路径| | 节点号 | pid/线程
其中:1、应用程序标识的第一部分是应用程序的IP地址,不过是已16进制表示的。
2、pid/线程即是在unix下看到的线程号。
停止应用程序:
db2 "force application(236)"
db2 “force application all”
其中:该236是查看中的应用程序句柄。
4.8 查看本instance下有哪些database
db2 LIST DATABASE DIRECTORY [ on /home/db2inst1 ]
4.9 查看及更改数据库head的配置
请注意,在大多数情况下,更改了数据的配置后,只有在所有的连接全部断掉后才会生效。
查看数据库head的配制
db2 get db cfg for head
更改数据库head的某个设置的值
4.9.1 改排序堆的大小
db2 update db cfg for head using SORTHEAP 2048
将排序堆的大小改为2048个页面,查询比较多的应用最好将该值设置比较大一些。
4.9.2 改事物日志的大小
db2 update db cfg for head using logfilsiz 40000
该项内容的大小要和数据库的事物处理相适应,如果事物比较大,应该要将该值改大一点。否则很容易处理日志文件满的错误。
4.9.3 出现程序堆内存不足时修改程序堆内存大小
db2 update db cfg for head using applheapsz 40000
该值不能太小,否则会没有足够的内存来运行应用程序。
4.10 查看及更改数据库实例的配置
查看数据库实例配置
db2 get dbm cfg
更改数据库实例配制
4.10.1 打开对锁定情况的监控。
db2 update dbm cfg using dft_mon_lock on
4.10.2 更改诊断错误捕捉级别
db2 update dbm cfg using diaglevel 3
0 为不记录信息
1 为仅记录错误
2 记录服务和非服务错误
缺省是3,记录db2的错误和警告
4 是记录全部信息,包括成功执行的信息
一般情况下,请不要用4,会造成db2的运行速度非常慢
4.11 db2环境变量
db2 重装后用如下方式设置db2的环境变量,以保证sp可编译
将set_cpl 放到AIX上, chmod +x set_cpl, 再运行之
set_cpl的内容
db2set DB2_SQLROUTINE_COMPILE_COMMAND="xlc_r -g
-I$HOME/sqllib/include SQLROUTINE_FILENAME.c
-bE:SQLROUTINE_FILENAME.exp -e SQLROUTINE_ENTRY
-o SQLROUTINE_FILENAME -L$HOME/sqllib/lib -lc -ldb2
db2set DB2_SQLROUTINE_KEEP_FILES=1
4.12 db2命令环境设置
db2=>list command options
db2=>update command options using C off--或on,只是临时改变
db2=>db2set db2options=+c --或-c,永久改变
4.13 改变隔离级别
DB2SET DB2_SQLROUTINE_PREPOPTS=CS|RR|RS|UR
交互环境更改session的隔离级别,
db2 change isolation to UR
请注意只有没有连接数据库时可以这样来改变隔离级别。
4.14 管理dbinstance的参数
get db cfg for head(db)
get dbm cfg(instance)
4.15 升级后消除版本问题
db2 bind @db2ubind.lst
db2 bind @db2cli.lst
4.16 查看数据库表的死锁
再用命令中心查询数据时要注意,如果用了交互式查询数据,命令中心将会给所查的记录加了s锁.这时如果要update记录,由于update要使用x锁,排它锁,将会处于锁等待.
首先,将监视开关打开
db2 update dbm cfg using dft_mon_lock on
快照
db2 get snapshot for Locks on cleardb >snap.log
tables
bufferpools
tablespaces
database
然后再看snap.log中的内容即可。
对Lock可根据Application handle(应用程序句柄)看每个应用程序的锁的情况。
监视完毕后,不要忘了将监视器关闭
db2 update dbm cfg using dft_mon_lock off
myfriend2010 发表于:2007.09.04 21:10 ::分类: (db2 ) ::阅读:(587次) ::评论 (0)
===========================================================
DB2 基础: 物化查询表简介
===========================================================
DB2 基础: 物化查询表简介
"
物化查询表(MQT)的定义是以一次查询的结果为基础的。MQT 可以显著提高查询的性能。本文将介绍 MQT、总结表(summary)和 staging 表,并通过一些实用的例子展示如何创建和使用物化查询表。
物化查询表(MQT)是一种以一次查询的结果为基础定义的表。包含在物化查询表中的数据来自定义物化查询表时所基于的一个或多个表。而 总结表(也称自动总结表,AST)对于 IBM® DB2® Universal Database™(UDB)for Linux、 UNIX® 和 Windows®(DB2 UDB)的用户来说应该感到比较熟悉,它们可以看作是特殊的 MQT。fullselect 是总结表定义的一部分,它包含一个 GROUP BY 子句,该子句总结 fullselect 中所引用表中的数据。
您可以将 MQT 看作一种物化的视图。视图和 MQT 都是基于一个查询来定义的。每当视图被引用时,视图所基于的查询便会运行。但是,MQT 实际上则是将查询结果保存为数据,您可以使用 MQT 中的这些数据,而不是使用底层表中的数据。
物化查询表可以显著提高查询的性能,尤其是提高复杂查询的性能。如果优化器确定查询或查询的一部分可以用一个 MQT 来解决,那么就会重写查询,以便利用 MQT。
MQT 可以在创建表时定义,或者定义为系统维护的 MQT,或者定义为用户维护的 MQT。下面的几个小节将介绍这两种类型的 MQT,另外再介绍总结表和 staging 表。后面的例子要求连接到 SAMPLE 数据库。如果您系统上还没有创建 SAMPLE 数据库,那么可以通过在命令行提示符下输入 db2sampl 命令来创建这个数据库。
系统维护的 MQT
这种物化查询表中的数据是由系统维护的。当创建这种类型的 MQT 时,可以指定表数据是 REFRESH IMMEDIATE 还是 REFRESH DEFERRED。通过 REFRESH 关键字可以指定如何维护数据。DEFERRED 的意思是,表中的数据可以在任何时候通过 REFRESH TABLE 语句来刷新。不管是 REFRESH DEFERRED 还是 REFRESH IMMEDIATE 类型的系统维护的 MQT,对它们的 insert、update 或 delete 操作都是不允许的。但是,对于 REFRESH IMMEDIATE 类型的系统维护的 MQT,可以通过 对底层表的更改(即 insert、update 或 delete 操作)来更新。
清单 1 展示了一个创建 REFRESH IMMEDIATE 类型的系统维护的 MQT 的例子。这个表名为 EMP,它基于 SAMPLE 数据库中的底层表 EMPLOYEE 和 DEPARTMENT。由于 REFRESH IMMEDIATE MQT 要求查询的 select 列表中引用的每个表中至少有一个惟一键,所以我们首先在 EMPLOYEE 表的 EMPNO 列上定义一个惟一性约束,另外还在 DEPARTMENT 表的 DEPTNO 列上定义一个惟一性约束。DATA INITIALLY DEFERRED 子句的意思是,在执行 CREATE TABLE 语句的时候,并不将数据插入到表中。MQT 被创建好之后,就处于检查暂挂在对它执行 SET INTEGRITY 语句之前,不能查询它。IMMEDIATE CHECKED 子句规定,根据用于定义该 MQT 的查询对数据进行检查,并刷新数据。NOT INCREMENTAL 子句规定对整个表进行完整性检查。通过查询 EMP 物化查询表发现,它现在已经填入了数据。
清单 1. 创建由系统维护的 MQT
connect to sample
...
alter table employee add unique (empno)
alter table department add unique (deptno)
create table emp as (select e.empno, e.firstnme, e.lastname, e.phoneno, d.deptno,
substr(d.deptname, 1, 12) as department, d.mgrno from employee e, department d
where e.workdept = d.deptno)
data initially deferred refresh immediate
set integrity for emp immediate checked not incremental
select * from emp
EMPNO FIRSTNME LASTNAME PHONENO DEPTNO DEPARTMENT MGRNO
------ ------------ --------------- ------- ------ ------------ ------
000010 CHRISTINE HAAS 3978 A00 SPIFFY COMPU 000010
000020 MICHAEL THOMPSON 3476 B01 PLANNING 000020
000030 SALLY KWAN 4738 C01 INFORMATION 000030
000050 JOHN GEYER 6789 E01 SUPPORT SERV 000050
000060 IRVING STERN 6423 D11 MANUFACTURIN 000060
000070 EVA PULASKI 7831 D21 ADMINISTRATI 000070
000090 EILEEN HENDERSON 5498 E11 OPERATIONS 000090
000100 THEODORE SPENSER 0972 E21 SOFTWARE SUP 000100
000110 VINCENZO LUCCHESSI 3490 A00 SPIFFY COMPU 000010
000120 SEAN O'CONNELL 2167 A00 SPIFFY COMPU 000010
000130 DOLORES QUINTANA 4578 C01 INFORMATION 000030
...
000340 JASON GOUNOT 5698 E21 SOFTWARE SUP 000100
32 record(s) selected.
connect reset
用户维护的 MQT
这种物化查询表中的数据是由用户维护的。只有 REFRESH DEFERRED 物化查询表可以定义为 MAINTAINED BY USER。不能对用户维护的 MQT 发出 REFRESH TABLE 语句(用于系统维护的 MQT)。但是,用户维护的 MQT 却 允许对它们执行 insert、update 或 delete 操作。
清单 2 展示了一个创建 REFRESH DEFERRED 类型的用户维护的 MQT 的例子。这个表名为 ONTARIO_1995_SALES_TEAM,它基于数据库 SAMPLE 中的底层表 EMPLOYEE 和 SALES。同样,DATA INITIALLY DEFERRED 子句的意思是,在执行 CREATE TABLE 语句的时候,并不将数据插入到表中。MQT 被创建之后,便处于检查暂挂状态在对它执行 SET INTEGRITY 语句之前,不能查询它。MATERIALIZED QUERY IMMEDIATE UNCHECKED 子句规定,该表将启用完整性检查,但是不必检查它是否违反了完整性约束,便可以使之脱离检查暂挂状态。
接下来,为了填充数据到 MQT 中,我们将导入从 EMPLOYEE 和 SALES 表中导出的数据。用于导出数据的查询与用于定义 MQT 的查询是一致的。然后,我们将插入另外一条记录到 ONTARIO_1995_SALES_TEAM 表中。
通过查询 ONTARIO_1995_SALES_TEAM 物化查询表发现,它现在已经填入了刚才导入的和插入的数据,这表明用户维护的 MQT 的确可以直接被修改。
清单 2. 创建由用户维护的 MQT
connect to sample
...
create table ontario_1995_sales_team as (select distinct e.empno, e.firstnme,
e.lastname, e.workdept, e.phoneno, 'Ontario' as region,
year(s.sales_date) as year from employee e, sales s
where e.lastname = s.sales_person and year(s.sales_date) = 1995
and left(s.region, 3) = 'Ont')
data initially deferred refresh deferred maintained by user
set integrity for ontario_1995_sales_team materialized query immediate
unchecked
export to ontario_1995_sales_team.del of del
select distinct e.empno, e.firstnme, e.lastname, e.workdept, e.phoneno,
'Ontario' as region, year(s.sales_date) as year from employee e,
sales s
where e.lastname = s.sales_person and year(s.sales_date) = 1995
and left(s.region, 3) = 'Ont'
...
Number of rows exported: 2
import from ontario_1995_sales_team.del of del insert into
ontario_1995_sales_team
...
Number of rows committed = 2
insert into ontario_1995_sales_team
values ('006900', 'RUSS', 'DYERS', 'D44', '1234', 'Ontario', 1995)
select * from ontario_1995_sales_team
EMPNO FIRSTNME LASTNAME WORKDEPT PHONENO REGION YEAR
------ ------------ --------------- -------- ------- ------- -----------
000110 VINCENZO LUCCHESSI A00 3490 Ontario 1995
000330 WING LEE E21 2103 Ontario 1995
006900 RUSS DYERS D44 1234 Ontario 1995
3 record(s) selected.
connect reset
物化查询表(MQT)的定义是以一次查询的结果为基础的。MQT 可以显著提高查询的性能。本文将介绍 MQT、总结表(summary)和 staging 表,并通过一些实用的例子展示如何创建和使用物化查询表。
物化查询表(MQT)是一种以一次查询的结果为基础定义的表。包含在物化查询表中的数据来自定义物化查询表时所基于的一个或多个表。而 总结表(也称自动总结表,AST)对于 IBM® DB2® Universal Database™(UDB)for Linux、 UNIX® 和 Windows®(DB2 UDB)的用户来说应该感到比较熟悉,它们可以看作是特殊的 MQT。fullselect 是总结表定义的一部分,它包含一个 GROUP BY 子句,该子句总结 fullselect 中所引用表中的数据。
您可以将 MQT 看作一种物化的视图。视图和 MQT 都是基于一个查询来定义的。每当视图被引用时,视图所基于的查询便会运行。但是,MQT 实际上则是将查询结果保存为数据,您可以使用 MQT 中的这些数据,而不是使用底层表中的数据。
物化查询表可以显著提高查询的性能,尤其是提高复杂查询的性能。如果优化器确定查询或查询的一部分可以用一个 MQT 来解决,那么就会重写查询,以便利用 MQT。
MQT 可以在创建表时定义,或者定义为系统维护的 MQT,或者定义为用户维护的 MQT。下面的几个小节将介绍这两种类型的 MQT,另外再介绍总结表和 staging 表。后面的例子要求连接到 SAMPLE 数据库。如果您系统上还没有创建 SAMPLE 数据库,那么可以通过在命令行提示符下输入 db2sampl 命令来创建这个数据库。
系统维护的 MQT
这种物化查询表中的数据是由系统维护的。当创建这种类型的 MQT 时,可以指定表数据是 REFRESH IMMEDIATE 还是 REFRESH DEFERRED。通过 REFRESH 关键字可以指定如何维护数据。DEFERRED 的意思是,表中的数据可以在任何时候通过 REFRESH TABLE 语句来刷新。不管是 REFRESH DEFERRED 还是 REFRESH IMMEDIATE 类型的系统维护的 MQT,对它们的 insert、update 或 delete 操作都是不允许的。但是,对于 REFRESH IMMEDIATE 类型的系统维护的 MQT,可以通过 对底层表的更改(即 insert、update 或 delete 操作)来更新。
清单 1 展示了一个创建 REFRESH IMMEDIATE 类型的系统维护的 MQT 的例子。这个表名为 EMP,它基于 SAMPLE 数据库中的底层表 EMPLOYEE 和 DEPARTMENT。由于 REFRESH IMMEDIATE MQT 要求查询的 select 列表中引用的每个表中至少有一个惟一键,所以我们首先在 EMPLOYEE 表的 EMPNO 列上定义一个惟一性约束,另外还在 DEPARTMENT 表的 DEPTNO 列上定义一个惟一性约束。DATA INITIALLY DEFERRED 子句的意思是,在执行 CREATE TABLE 语句的时候,并不将数据插入到表中。MQT 被创建好之后,就处于检查暂挂(check pending)状态(请参阅 DB2 基础: 阐明表和表空间的状态),在对它执行 SET INTEGRITY 语句之前,不能查询它。IMMEDIATE CHECKED 子句规定,根据用于定义该 MQT 的查询对数据进行检查,并刷新数据。NOT INCREMENTAL 子句规定对整个表进行完整性检查。通过查询 EMP 物化查询表发现,它现在已经填入了数据。
清单 1. 创建由系统维护的 MQT
connect to sample
...
alter table employee add unique (empno)
alter table department add unique (deptno)
create table emp as (select e.empno, e.firstnme, e.lastname, e.phoneno, d.deptno,
substr(d.deptname, 1, 12) as department, d.mgrno from employee e, department d
where e.workdept = d.deptno)
data initially deferred refresh immediate
set integrity for emp immediate checked not incremental
select * from emp
EMPNO FIRSTNME LASTNAME PHONENO DEPTNO DEPARTMENT MGRNO
------ ------------ --------------- ------- ------ ------------ ------
000010 CHRISTINE HAAS 3978 A00 SPIFFY COMPU 000010
000020 MICHAEL THOMPSON 3476 B01 PLANNING 000020
000030 SALLY KWAN 4738 C01 INFORMATION 000030
000050 JOHN GEYER 6789 E01 SUPPORT SERV 000050
000060 IRVING STERN 6423 D11 MANUFACTURIN 000060
000070 EVA PULASKI 7831 D21 ADMINISTRATI 000070
000090 EILEEN HENDERSON 5498 E11 OPERATIONS 000090
000100 THEODORE SPENSER 0972 E21 SOFTWARE SUP 000100
000110 VINCENZO LUCCHESSI 3490 A00 SPIFFY COMPU 000010
000120 SEAN O'CONNELL 2167 A00 SPIFFY COMPU 000010
000130 DOLORES QUINTANA 4578 C01 INFORMATION 000030
...
000340 JASON GOUNOT 5698 E21 SOFTWARE SUP 000100
32 record(s) selected.
connect reset
用户维护的 MQT
这种物化查询表中的数据是由用户维护的。只有 REFRESH DEFERRED 物化查询表可以定义为 MAINTAINED BY USER。不能对用户维护的 MQT 发出 REFRESH TABLE 语句(用于系统维护的 MQT)。但是,用户维护的 MQT 却 允许对它们执行 insert、update 或 delete 操作。
清单 2 展示了一个创建 REFRESH DEFERRED 类型的用户维护的 MQT 的例子。这个表名为 ONTARIO_1995_SALES_TEAM,它基于数据库 SAMPLE 中的底层表 EMPLOYEE 和 SALES。同样,DATA INITIALLY DEFERRED 子句的意思是,在执行 CREATE TABLE 语句的时候,并不将数据插入到表中。MQT 被创建之后,便处于检查暂挂状态(请参阅 DB2 基础: 阐明表和表空间的状态),在对它执行 SET INTEGRITY 语句之前,不能查询它。MATERIALIZED QUERY IMMEDIATE UNCHECKED 子句规定,该表将启用完整性检查,但是不必检查它是否违反了完整性约束,便可以使之脱离检查暂挂状态。
接下来,为了填充数据到 MQT 中,我们将导入从 EMPLOYEE 和 SALES 表中导出的数据。用于导出数据的查询与用于定义 MQT 的查询是一致的。然后,我们将插入另外一条记录到 ONTARIO_1995_SALES_TEAM 表中。
通过查询 ONTARIO_1995_SALES_TEAM 物化查询表发现,它现在已经填入了刚才导入的和插入的数据,这表明用户维护的 MQT 的确可以直接被修改。
清单 2. 创建由用户维护的 MQT
connect to sample
...
create table ontario_1995_sales_team as (select distinct e.empno, e.firstnme,
e.lastname, e.workdept, e.phoneno, 'Ontario' as region,
year(s.sales_date) as year from employee e, sales s
where e.lastname = s.sales_person and year(s.sales_date) = 1995
and left(s.region, 3) = 'Ont')
data initially deferred refresh deferred maintained by user
set integrity for ontario_1995_sales_team materialized query immediate
unchecked
export to ontario_1995_sales_team.del of del
select distinct e.empno, e.firstnme, e.lastname, e.workdept, e.phoneno,
'Ontario' as region, year(s.sales_date) as year from employee e,
sales s
where e.lastname = s.sales_person and year(s.sales_date) = 1995
and left(s.region, 3) = 'Ont'
...
Number of rows exported: 2
import from ontario_1995_sales_team.del of del insert into
ontario_1995_sales_team
...
Number of rows committed = 2
insert into ontario_1995_sales_team
values ('006900', 'RUSS', 'DYERS', 'D44', '1234', 'Ontario', 1995)
select * from ontario_1995_sales_team
EMPNO FIRSTNME LASTNAME WORKDEPT PHONENO REGION YEAR
------ ------------ --------------- -------- ------- ------- -----------
000110 VINCENZO LUCCHESSI A00 3490 Ontario 1995
000330 WING LEE E21 2103 Ontario 1995
006900 RUSS DYERS D44 1234 Ontario 1995
3 record(s) selected.
connect reset
总结表
您应该记得,总结表是一种特殊类型的 MQT,它们的 fullselect 包含一个 GROUP BY 子句,该子句总结 fullselect 中所引用表中的数据。清单 3 展示了一个简单的创建总结表的例子。该表名为 SALES_SUMMARY,它基于 SAMPLE 数据库中的底层表 SALES。同样,DATA INITIALLY DEFERRED 子句的意思是,在执行 CREATE TABLE 语句的时候,并不将数据插入到表中。REFRESH DEFERRED 子句的意思是,在任何时候都可以用 REFRESH TABLE 语句刷新该表中的数据。当这个 MQT 刚创建且还没有发出 REFRESH TABLE 语句的时候,对它的查询将返回一个错误。而执行了 REFRESH TABLE 语句之后,对它的查询可以成功运行。
在对 SALES 表执行插入操作,再刷新总结表之后,对总结表的查询表明,对底层表的更改已经反映到总结表中:销售员 Lee 在 Ontario-South 地区的总销售量增加了 100。类似地,在对底层表执行 update 或 delete 操作之后,也可以在总结表中观察到相应的变化。
清单 3. 创建总结表
connect to sample
...
create table sales_summary as (select sales_person, region, sum(sales)
as total_sales
from sales group by sales_person, region)
data initially deferred refresh deferred
select * from sales_summary
SALES_PERSON REGION TOTAL_SALES
--------------- --------------- -----------
SQL0668N Operation not allowed for reason code "1" on table
"MELNYK.SALES_SUMMARY". SQLSTATE=57016
refresh table sales_summary
select * from sales_summary
SALES_PERSON REGION TOTAL_SALES
--------------- --------------- -----------
GOUNOT Manitoba 15
GOUNOT Ontario-North 1
GOUNOT Ontario-South 10
GOUNOT Quebec 24
LEE Manitoba 23
LEE Ontario-North 8
LEE Ontario-South 34
LEE Quebec 26
LUCCHESSI Manitoba 3
LUCCHESSI Ontario-South 8
LUCCHESSI Quebec 3
11 record(s) selected.
insert into sales values ('06/28/2005', 'LEE', 'Ontario-South', 100)
refresh table sales_summary
select * from sales_summary
SALES_PERSON REGION TOTAL_SALES
--------------- --------------- -----------
...
LEE Ontario-North 8
LEE Ontario-South 134
LEE Quebec 26
...
11 record(s) selected.
update sales set sales = 50 where sales_date = '06/28/2005' and
sales_person = 'LEE'
and region = 'Ontario-South'
refresh table sales_summary
select * from sales_summary
SALES_PERSON REGION TOTAL_SALES
--------------- --------------- -----------
...
LEE Ontario-North 8
LEE Ontario-South 84
LEE Quebec 26
...
11 record(s) selected.
delete from sales where sales_date = '06/28/2005' and sales_person = 'LEE'
and region = 'Ontario-South'
refresh table sales_summary
select * from sales_summary
SALES_PERSON REGION TOTAL_SALES
--------------- --------------- -----------
...
LEE Ontario-North 8
LEE Ontario-South 34
LEE Quebec 26
...
11 record(s) selected.
connect reset
staging 表
如果 REFRESH DEFERRED MQT 有一个相关联的 staging 表,那么可以对其执行增量刷新。staging 表 收集更改,以便应用这些更改,使得 MQT 与它的底层表同步。可以使用 CREATE TABLE 语句创建一个 staging 表。然后,当 MQT 的底层表被修改时,变化就会传播过来,并立即被添加到 staging 表中。其思想是,使用 staging 表增量式地刷新 MQT,而不是从头开始重新生成 MQT。增量式维护这种方式可以显著提高性能。当刷新操作完成时,staging 表就会被删除。
staging 表被创建之后,便处于悬挂(不一致)状态。在开始收集底层表上的更改之前,它必须脱离这种状态。为此,可以使用 SET INTEGRITY 语句。
清单 4 展示了一个使用有关联总结表的 staging 表的例子。总结表名为 EMP_SUMMARY,它基于 SAMPLE 数据库中的底层表 EMPLOYEE。您应该还记得,DATA INITIALLY DEFERRED 子句的意思是,在执行 CREATE TABLE 语句的时候,并不将数据插入到表中。而 REFRESH DEFERRED 子句的意思是,在任何时候都可以使用 REFRESH TABLE 语句刷新该表中的数据。staging 表名为 EMP_SUMMARY_S,它与总结表 EMP_SUMMARY 相关联。PROPAGATE IMMEDIATE 子句规定,在 insert、update 或 delete 操作中对底层表做出的任何更改,都将被累积在 staging 表中。对于这两个表,都发出 SET INTEGRITY 语句,以便使它们都脱离悬挂状态。
不出所料,此时对总结表的查询没有返回任何数据。REFRESH TABLE 语句返回一条警告,提示说 "integrity of non-incremental data remains unverified"。这也不值得惊讶。再次查询总结表,仍然没有返回任何数据。但是,当我们插入新的一行数据到底层的 EMPLOYEE 表之后,再次查询 staging 表 EMP_SUMMARY_S 便返回一行记录,这行数据与刚才插入的数据是一致的。staging 表中有三个列与其底层总结表中的三列相同,另外还有两个由系统使用的列:GLOBALTRANSID(每个被传播的行对应的全局事务 ID)和 GLOBALTRANSTIME(事务的时间戳)。再次查询总结表,又是没有返回数据,但是当执行了 REFRESH TABLE 语句之后,查询得以成功运行。
清单 4. 使用有关联总结表的 staging 表
connect to sample
...
create table emp_summary as (select workdept, job, count(*) as count
from employee group by workdept, job)
data initially deferred refresh deferred
create table emp_summary_s for emp_summary propagate immediate
set integrity for emp_summary materialized query immediate unchecked
set integrity for emp_summary_s staging immediate unchecked
select * from emp_summary
WORKDEPT JOB COUNT
-------- -------- -----------
0 record(s) selected.
refresh table emp_summary
SQL1594W Integrity of non-incremental data remains unverified by the
database manager. SQLSTATE=01636
select * from emp_summary
WORKDEPT JOB COUNT
-------- -------- -----------
0 record(s) selected.
insert into employee
values ('006900', 'RUSS', 'L', 'DYERS', 'D44', '1234', '1960-05-05',
'FIELDREP', 5, 'M', '1940-04-02', 10000, 100, 1000)
select * from emp_summary_s
WORKDEPT JOB COUNT GLOBALTRANSID GLOBALTRANSTIME
-------- -------- ----------- -------------------... -----------------------------...
D44 FIELDREP 1 x'00000000000000CD' x'20050822201344536158000000'
1 record(s) selected.
select * from emp_summary
WORKDEPT JOB COUNT
-------- -------- -----------
0 record(s) selected.
refresh table emp_summary
SQL1594W Integrity of non-incremental data remains unverified by the database
manager. SQLSTATE=01636
select * from emp_summary
WORKDEPT JOB COUNT
-------- -------- -----------
D44 FIELDREP 1
1 record(s) selected.
connect reset
结束语
在 SYSCAT.TABDEP 系统编目视图中,对于一个物化查询表在其他对象上的每个依赖关系,都有相应的一行。您可以查询这个视图,获得对我们创建的 MQT(清单 5)的依赖关系的总结。MQT 有一个值为 'S' 的 DTYPE。TABNAME 列列出 MQT 的名称,BNAME 列列出相应的 MQT 所依赖的数据库对象的名称。BTYPE 列显示对象类型:'T' 表示表,'I' 表示索引,'F' 表示函数实例。
清单 5. 查询 SYSCAT.TABDEP 系统编目视图,以查看 MQT 在其他数据库对象上的依赖关系
connect to sample
...
select substr(tabname,1,24) as tabname, dtype, substr(bname,1,24) as bname, btype
from syscat.tabdep where tabschema = 'MELNYK' and dtype = 'S'
TABNAME DTYPE BNAME BTYPE
------------------------ ----- ------------------------ -----
EMP S DEPARTMENT T
EMP S EMPLOYEE T
EMP S SQL050829104058970 I
EMP S SQL050829104058800 I
EMP_SUMMARY S EMPLOYEE T
ONTARIO_1995_SALES_TEAM S LEFT1 F
ONTARIO_1995_SALES_TEAM S SALES T
ONTARIO_1995_SALES_TEAM S EMPLOYEE T
SALES_SUMMARY S SALES T
9 record(s) selected.
connect reset
myfriend2010 发表于:2007.09.04 16:47 ::分类: (db2 ) ::阅读:(709次) ::评论 (0)
===========================================================
让db2系统定时runstats、reorg
===========================================================
让db2系统定时runstats、reorg
Q:定期runstats、reorg
A:在db2 v8.2以上可以使用 CALL SYSPROC.ADMIN_CMD来实现,
这里主要讲在v8.2以前的版本中利用shell或者批处理来实现同样的功能
因为在以前的版本中存储过程中是不能使用DDL操作语句的!(这点对于oracle刚转过来的人来说很是郁闷的)
然后可以利用db2自带的配置自动维护来做,但是java做的东西比较让人感觉头痛!尤其是速度和莫名的错误!
本代码使用操作系统的脚本来实现这部分功能!
1.windows下
如下:
下一个cmd文件s.cmd
内容如下:
db2 connect to ccp_dm
db2 -x "select 'runstats on table '||rtrim(tabschema)||'.'||tabname||' on all columns' from sysstat.tables where card=-1">tab.sql
db2 -f tab.sql
--其中where后的条件可以修改
然后就是定制任务:用windos的定制任务!每周或者每月运行,这个就不讲了哈!
这部分经测试,通过!
不过能,这里只提到了runstats,对于reorg同理也可以实现!
2.
非windows下(这个是从网上搞得,没有测试过):
一:#!/usr/bin/ksh
#DB2V8统计更新脚本 by Ray001 2006/09/06
if [ $# -ne 3 ]
then
echo "Usage:$0 DBNAME USER PASSWD!"
exit 1
fi
DBNAME=$1
USER=$2
PASSWD=$3
rm -f tab.tmp
rm -f ind.tmp
db2 connect to $DBNAME user $USER using $PASSWD
db2 -x "select tabschema,tabname from sysstat.tables where card=-1">tab.tmp
if [ $? -ne 0 ]
then
if [ ! -s tab.tmp ]
then
echo "NO TABLES NEED TO BE PROCESS"
#exit 0
else
echo "SELECT SYSSTAT.TABLES ERROR"
exit 1
fi
fi
db2 -x "select tabschema,tabname,indschema,indname from sysstat.indexes where nl
eaf=-1">ind.tmp
if [ $? -ne 0 ]
then
if [ ! -s ind.tmp ]
then
echo "NO INDEXES NEED TO BE PROCESS"
#exit 0
else
echo "SELECT SYSSTAT.INDEXES ERROR"
exit 1
fi
fi
while read TABSCHEMA TABNAME
do
echo "runstats on table $TABSCHEMA.$TABNAME"
db2 "runstats on table $TABSCHEMA.$TABNAME"
donewhile read TABSCHEMA TABNAME INDSCHEMA INDNAME
do
echo "runstats on table $TABSCHEMA.$TABNAME for index $INDSCHEMA.$INDNAME"
db2 "runstats on table $TABSCHEMA.$TABNAME for index $INDSCHEMA.$INDNAME"
donedb2 terminate
rm -f tab.tmp
rm -f ind.tmp
二:
回到主题。若是要做DB2 RUNSTATS的话,我的习惯是写一个简单的SHELL SCRIPT,如下:
/home/db2inst/Scripts > cat runstats.sh
#! /usr/bin/ksh
. $HOME/.profile
db2 -v connect to mydb
for TABSCHEMA in DB2INST
do
for TABNAME in $(db2 -x "select tabname from syscat.tables where tabschema='$TABSCHEMA'")
do
db2 -v "runstats on table $TABSCHEMA.$TABNAME and indexes all"
done
done
/home/db2inst/Scripts > ./runstats.sh
connect to mydb
myfriend2010 发表于:2007.08.23 16:38 ::分类: (db2 ) ::阅读:(2195次) ::评论 (1)
===========================================================
db2开发人员必读之---DB2中多种常用功能的解决方法
===========================================================
DB2中多种常用功能的解决方法
【导读】描述了多种常用功能的解决方法,而这些功能并不完全符合关系誓约。
简介
关系模型是一件美好事物。对它妥协是牵强附会,就象给米开朗琪罗的大卫扣上一顶棒球帽一样。然而,不属于纯关系模型的事物可能最终出现在您的数据库或应用程序中。如果您以修道士般的严肃态度看待关系誓约,那么不必继续阅读本文。对那些可能希望享受在狂野地带漫步的人而言,本文将带您到 RDBMS 的红灯区。请继续阅读本文以发现如何:
存储派生值
给每行编号以创建一个人工键
检索由 DB2® 生成的标识值
给结果集中的行编号
请求数据然后截断结果集
删除表中所有行而不记入日志
用视图和重命名表命令“删除”列
加宽 varchar 列
学习何时使用真的视图以及汇总表(名声不太好的实现视图)
学习声明的临时表与公共表表达式之间的差异
这些技术中的一些技术可以改进性能,就象您可能在 RDBMS 参考手册中看到的实用建议,它建议您使数据符合第四范式,然后在实现设计前做一些妥协以取得需要的性能。其它一些技术会使应用程序程序员的工作更简单,并且带来性能上意想不到的效果。
派生值
您可能在关于关系数据库的大学课程中的某处学到不要存储派生值。毕竟,可以在组装结果集时计算这些值,从而避免数据库中的冗余数据,并获得正确答案。DB2 在版本 7 中引入生成的列有以下几个原因。
请求数据的用户可能正在使用您没有控制权的应用程序。如果他们正在使用只需移动和点击鼠标就可以完成工作的应用程序进行 SELECT * 操作,他们可能没有意识到他们真正希望看到的是 COMPENSATION,并且必须将 COMMISSION 和 SALARY 列中的值相加。一个生成的列允许您存储这个值,并保持它的准确性:
create table employee
(name char(10), salary dec(10,2), commission dec(10,2),
compensation dec(11,2)
generated always as (commission + salary))
通过下面的 SQL 语句来保持 COMPENSATION 列的准确性:
insert into employee (name, salary, commission) values ('Blair',5,10)
update employee set salary=0
您需要唯一地标识每一行。我们将在稍后讨论这一点。
要求不区分大小写来创建索引,接下来就介绍这一点。
区分大小写
区分大小写是功能强大的,而且如果 RDBMS 知道 Greenland 与 greenland 不匹配,它会搜索得更快。然而,用户如果提交对“Macinnis”的搜索,他们可能实际上希望您的应用程序返回“MacInnis”。对于名称搜索,您可能要考虑在 NAME 列上创建一个索引。然而,DB2 索引中的值也是区分大小写的。让 MacInnis=Macinnis 很简单,只要使用 UPPER 或 UCASE 函数即可:
SELECT NAME FROM EMPLOYEE WHERE UPPER(NAME) = 'MACINNIS'
但是,这会强制进行表扫描,而且您得不到索引的好处。这就是引入生成的列的用途所在:如果标准访问方法是关于名称的搜索,那么使用生成的列来以大写格式存储名称:
CREATE TABLE EMPLOYEE (NAME VARCHAR(10),
NAME_UP
GENERATED ALWAYS AS (UPPER(name)))
现在在这个列的大写版本上创建索引:
CREATE INDEX NAME_IND ON EMPLOYEE ( NAME_UP )
该查询可以获得索引的好处,并避免了表扫描:
SELECT NAME FROM EMPLOYEE WHERE UPPER(NAME) = 'MACINNIS'
让我们看看如何用生成的列来枚举行。我们为什么要给行编号?关系理论告诉我们行与列没有内在的顺序:您可以在请求数据时指定顺序。但人们喜欢给事物编号,从书中的页号到运动衫上的号码。您可能知道在计算机科学中数据被看成表格式关系模型。您的用户有多少学会查看 Lotus 和 Excel 电子表格中的表格式数据(屏幕左边有向下递增的行号)呢?大多数关系数据库管理系统都有内部 RID(行标识)或 TID(元组标识)。OS/390® 上的 DB2 和 Oracle 将这一点具体化,使程序无需知道内容就可以方便地标识行。我们没有具体化 Windows/UNIX/OS/2 上 DB2 的行标识,因为我们允许它改变:潜在主键中的一个危险特性。DB2 的确有其它方法将一列作为人工主键使用。
在您借助任何这些唯一标识每一行的基本方法之前,请尽力找到真实的主键:问自己这个问题:“如果我们把每一行都写在纸上,应如何唯一标识它;假定客户或供应商打电话询问状态 — 我们怎样才能找到他们所询问的数据?”如果您在每张纸上都打上日期和时间戳记,那么这就是主键。
生成行标识
让我们从由其它数据库迁移到 DB2 的应用程序开始。如果移自 SQL Server,您可能厌倦了关于关系纯洁性的说教并希望了解 IDENTITY。下面是如何用 DB2 v7 创建 IDENTITY 列:
CREATE TABLE T1
(C1 DECIMAL(15,0) GENERATED BY DEFAULT AS IDENTITY
(START WITH 10),
C2 INTEGER)
还有在内存中高速缓存标识值的选项,这使插入更快,但如果您的系统在生成 IDENTITY 值时遭受硬件或软件崩溃,那么将在标识序列中留下间隔。缺省情况是一次增加整数 1,但您也可以按其它值(2 和 10 等)增加。插入后,您会对生成的值自然地产生好奇。为了应用程序的下一段逻辑,您可能需要知道这个值。在发行说明(Windows 上 x:sqllib elease.txt)中记录的名为 IDENTITY_VAL_LOCAL() 的函数可为您检索这个值。
IDENTITY 在每个表中是唯一的。那些 Oracle 迷将很高兴得知 DB2 的版本 7,修订包 3 将把 SEQUENCE 列带入 DB2。序列在整个数据库中是独一无二的 — 这对于在多个表中使用的值很有用。您也可以在序列中循环以重用这些值。SEQUENCE 和 IDENTITY 不是数据类型:它们使用象 SMALLINT、INTEGER 或小数位是零的 DEC 那样的现有数据类型。INT 和 BIGINT 是最好的选择,它们能给您良好的性能和适当的数值范围。还允许负值。
生成人工主键还有其它方法。如果一次只有一位用户访问表(并且一次只插入一行),则触发器很不错。将您的主键列定义为缺省非空值,这样当在 INSERT 中没有指定它时,它就得到一个虚设的值(触发器将重写这个虚设的值):
CREATE TRIGGER AutoIncrement NO CASCADE BEFORE
INSERT ON Foobar
REFERENCING NEW AS n
FOR EACH ROW MODE DB2SQL SET (n.col1) =
(SELECT COALESCE(MAX(col1),0) + 1 FROM Foobar )
DB2 还有一个名为 GENERATE_UNIQUE 的函数。这个函数将节点号(用于多分区数据库)与时间戳记结合,因此它可以与企业扩展版本(EEE)一起使用。IDENTITY 和 SEQUENCE 在 DB2 的下一个主要版本出现前还不能与 EEE 一起使用。GENERATE_UNIQUE 有两个缺点:数据类型(CHAR(13) FOR BIT DATA)不是按顺序递增,并且不象数值数据类型那样易于使用。
更简单的解决方案是标量子查询表达式:
INSERT INTO Foobar (key_col, ...)
VALUES (COALESCE((SELECT MAX(key_col) FROM Foobar) +1, 0) ...)
获得一屏数据
这些方法对于那些在数据库和应用程序投入生产以前有机会进行一些设计工作的模式和应用程序来说是不错的。但您还记得那两个以 A(ARIES(航班订票环境仿真)和 ACID(原子性、一致性、隔离和持久性))开头的 4.5 字母单词吗?如果您预定了航班,那么您希望他们在您到达机场时记得这回事。这就是持久性:有用的数据是持久的。这意味着即使您定义了一个好的主键,有些人可能会查询结果集的“前二十行”,而不管结果集中有多少行。更糟的情况是有人要求您显示第 21 行到 40 行。但等一下,您会提出异议,关系表中的行没有顺序!对于希望在他们的 Netscape 浏览器中一次看到二十行的用户而言,您就好象在说冰岛语。DB2 允许您实时地给结果集排序,并可以从该结果集的开始或结尾部分提取任意数量的行:
SELECT NAME FROM ADDRESS
ORDER BY NAME
FETCH FIRST 10 ROWS ONLY
SELECT NAME FROM ADDRESS
ORDER BY NAME DESC
FETCH FIRST 10 ROWS ONLY
ORDER BY 将强制在内存中对整个结果集进行排序,所以,为了提高 DB2 服务器性能,我们不这么做(尽管只向客户机发送 10 行可能会提高网络性能)。如果您不关心顺序并且只想知道至少有 10 行符合结果集,则清除 ORDER BY 以省去 DB2 服务器上的排序:
SELECT NAME FROM ADDRESS
FETCH FIRST 10 ROWS ONLY
于是现在我们已看到您给行编号并且任意选择了一个子集。假设我们因某些性能上的好处而给行编号,这必将破坏关系模型。我们几乎完全妥协了,并且已经犯了关系七宗罪中的六宗。还有一条关系誓约您没有触犯:让我们实时地给行编号,牺牲掉性能和关系纯洁性吧。我们如何证明这样做的正确性呢?在因特网上谴责它吧。
向使用浏览器的客户显示公司数据显然证明了违背对关系纯洁性和性能推崇所作的承诺。您可以用 rownum 或 rank 函数实时地给结果集赋予行号。下面我们为用来记录地址的表中的行排序,并选择第 11 行到第 20 行。结果集由名称和实时创建的名为 rn 的列(它给行编号)组成:
SELECT * FROM (SELECT NAME, rownumber() OVER
(ORDER BY NAME)
AS rn FROM ADDRESS)
AS tr WHERE rn BETWEEN 11 and 20
rank 更为复杂,并且它允许您以排序的顺序标识联系,对于足球联赛非常理想:
create table football (team char(10), points int)
insert into football values ('United', 20)
insert into football values ('Arsenal', 20)
insert into football values ('Liverpool', 10)
select rank() over
(order by points desc) as place,
team, points
from football
PLACE TEAM POINTS
1 United 20
1 Arsenal 20
3 Liverpool 10
清空表 — 无需通知日志记录程序(截断表)
现在你已经得到了很多精巧的方法来处理你的数据了,我们再来学习一个小把戏。其他的数据库产品有被称为“截断表”的功能,即在不进行日志记录的情况下删除表中的所有数据,而保留表的结构(如果不想保留表结构,我们就使用 DROP TABLE 命令了)。如果想在 DB2 中得到这种功能,可以执行带有 REPLACE 选项的 LOAD 命令,并使用一个 0 字节的文件作为导入数据源,由于 DB2 的 LOAD 操作是不做日志的,所以可以通过这个小骗局来达到我们的目的。
猜测游戏和镜屋
您的表很不错 — 为什么要从视图访问它?这样做有许多理由:
列级别安全性:排除那些您不希望用户在定义视图的 SELECT 中看到的列。
行级别安全性:除非您定义一个视图,否则 Windows/UNIX/OS/2 上的 DB2 v7 不允许您限制对表中某些行的访问(如果您希望限制对允许用户看到的内容的更新,请记得加上 check 选项):
create view london_football as
select * from football
where team in ('Arsenal','Aston Villa')
with check option
设想这一点对于“人力资源”应用程序的作用:用户可以查看薪水在 $nn,nnn 以下的雇员,给他们加薪而加薪后的薪水不会在 $nn,nnn 以上。
DROP COLUMN:DB2 不允许您删除一个列。我可以想到您希望删除列的三个理由:
回收空间:如果您希望这样做,可以导出您希望保存的数据,删除那个表,用您需要的那些列重新创建表,然后装入这个表。这是否代价高昂?当然是,但是回收空间需要这样或者 REORG TABLE。这些本来就是代价高昂的操作。
这个列不再是行的逻辑部分:例如,您意识到您的雇员可能有两个地址,并且停止跟踪雇员(employee)表中的地址(雇员表和雇员地址(employee_address)表之间现在有 n:m 关系)。在雇员表上创建一个不包含地址列的视图。
如果您真的要用新奇的方法,可以使用 RENAME TABLE 命令给基表一个新的名称,然后将原始表名作为该视图的名称。您的视图也可以连接雇员表中的有用列和从雇员地址获得的地址。现在我们回到了关系的正道。
列变宽了。如果它是 VARCHAR,那您运气不错。DB2 允许您将 VARCHAR 列最多加宽至表空间(tablespace)中定义的页大小宽度(缺省的 4K 页大小为 4,005,而在 32K 页上最多为 32,672):
create table t2 (col1 varchar(10))
alter table t2 alter column col1 set data type varchar(12)
我很喜欢这个视图,所以我实现它
如果派生列对您来说还不够坏,整个派生表怎么样?使它与基表中的数据匹配或不匹配(以及使每个 SELECT 成为潜在的错读)的能力又如何?Oracle 称这些为实现的视图。DB2 称它们为自动汇总表,在特殊情况下称为复制汇总表。如果经常被问到一个问题(SELECT MAX(ORDERS) FROM LEADS),或者经常组装一个聚集(SELECT COUNT(FRANCHISES) FROM STORES WHERE STATE=’TEXAS’),那么或许值得将结果集存储在磁盘上,这样 DB2 就不必每天重新计算它二十次:特别当几天前的数据足以准确地支持基于查询的决策时。
让我们从想知道哪个客户订购最多的贪婪的销售经理开始。他们在名为 LEADS 的表中跟踪这一项,推断出客户过去所下订单的数目可能有助于确定哪些销售线索最有可能变为真实的销售。这个问题每天会被问几次(如果您预感这正在发生并且需要验证它,您可以使用名为 Query Patroller 的 DB2 工具查看来自用户的查询)。SELECT MAX() 通常需要一个表扫描,这会强制 DB2 查看表中的每一行。如果您有许多线索,则需要扫描许多行才能找到一个值。定义一个汇总表允许 DB2 将这个值存储在磁盘上,这样 DB2 只用读一行就可以得到答案:
create summary table leads_max
(MAX_ORDERS) as (SELECT MAX(ORDERS) FROM LEADS )
DATA INITIALLY DEFERRED
REFRESH DEFERRED
创建汇总表后,用这条命令填充它:
REFRESH TABLE LEADS_MAX
用户不必了解汇总表。DB2 优化器会决定何时使用基本表,何时使用汇总表。请注意 REFRESH DEFERRED 子句:您正在告诉 DB2 旧数据在汇总表中是可接受的。这在您不需要准确答案或当前答案时是合适的。它适合构建一个业务计划,但对于要怎样存储银行余额,它就不适合了。请参阅 SQL Reference 中的特殊寄存器 CURRENT REFRESH AGE 以及 Administration Guide 中的“Creating a Summary Table”一节,以了解在答案可以“足够接近”、无需精确时,如何为汇总表中的旧数据设置容忍度。
REFRESH DEFERRED 是总结只读表上数据的理想选择。多分区数据库的特殊汇总表称为复制汇总表。您将在 DB2 EEE 中使用它以在每个分区都有小型表(或只读表)的副本。在 EEE 中,您通常将最大的表(称为事实表)分布到所有的分区。大量使用的连接键(如客户号码)应该作为分区键使用。DB2 将数据进行散列处理以对它分区。这意味着较少使用的连接键(如国家/地区或部门)可能会以次优化方式分布。当您在多分区数据库中连接数据时,与组合的连接更快(例如,CUSTOMER 和 COUNTRY 表中所有 COUNTRY 为 Argentina 的行都在同一分区)。如果 COUNTRY 不是分区键,这是不可能的。要获得组合,您可以将较小的表限制在一个分区,然后创建一个将它复制到其它分区的复制汇总表。这一策略在所复制的表较小或很少有更改时奏效(如果您在经常更改国名的国家做生意的话,要避免这么做)。如果表确实很小(如各大洲的列表),不要费心去复制它:DB2 将把它传送到所有分区并在连接期间将它保留在内存中。不要担心通过名称连接到副本:判断副本表何时可以提高性能是 DB2 的工作。
通过使汇总表 REFRESH IMMEDIATE,可以将它们用于动态数据。这有比 REFRESH DEFERRED 更严格的规则,所以请仔细阅读 SQL Reference。在首次创建汇总表之后,您仍必须使用 REFRESH TABLE 语句:
CREATE SUMMARY TABLE LEADS_BY_STATE
(NUM_LEADS, GRP_STATE)
AS (SELECT COUNT(ORDERS), STATE FROM LEADS GROUP BY STATE)
DATA INITIALLY DEFERRED
REFRESH IMMEDIATE
REFRESH TABLE LEADS_BY_STATE
也可以这样
我们现在已研究了两种视图。作为标准视图,视图定义存储在数据库中(在 SYSCAT.VIEWS.TEXT 中)而数据只存储在基表中。我们可以通过创建汇总表使得在这个数据上执行 SELECT 操作更快,这是以冗余数据为代价,它消耗更多磁盘空间并使得 INSERT、UPDATE 和 DELETE 更慢(或让基表和汇总表不同步,至少在下一次刷新以前是这样)。还有另一个极端:创建一个仅在数据库连接期间存在的聚集,或者甚至和 SQL 语句的生命期一样短。第一个称为 DECLARED TEMPORARY TABLE,第二个称为 COMMON TABLE EXPRESSION,也称为 TEMPORARY RESULT TABLE。一个声明的临时表需要一个 USER TEMPORARY TABLESPACE,您可以用 CREATE TABLESPACE 命令创建它(请参阅 SQL Reference)。您可以将这个临时表声明为应用程序运行时数据的保留位置。
DECLARE GLOBAL TEMPORARY TABLE table1
(column1 INT, column2 INT)
NOT LOGGED
您用模式 SESSION 限定表,因为它属于您连接到数据库时创建的会话:
INSERT INTO SESSION.TABLE1 VALUES (4,5)
SELECT * FROM SESSION.TABLE1
您可能希望这个临时表与现有表匹配,因此您可以用现有表的 SELECT 语句填充它。如果这样的话,使用 LIKE 创建它:
DECLARE GLOBAL TEMPORARY TABLE TEMP_EMP
LIKE EMPLOYEE
NOT LOGGED
INSERT INTO SESSION.TEMP_EMP
SELECT * FROM EMPLOYEE
当您断开连接时,DB2 将删除这个临时表。对于某些更临时的东西,DB2 支持公共表表达式,它允许您定义只存在于一条语句的表。公共表表达式还是另一个细微问题的答案:给一个不是以动词开始的 SQL 语句命名:
WITH COMPENSATION AS
(SELECT SUM(SALARY+COMMISSION)
AS TOTAL FROM EMPLOYEE)
SELECT TOTAL FROM COMPENSATION
您现在已被护送出红灯区。公共表表达式并不违背关系原则:它不要求 DB2 存储派生数据,也不添加人工列。如果一定要从这个故事引出一个寓意的话,假定用计算机解决一个问题有 n 种方法。一种方法可能成本最低,一种方法对您而言最快,一种方法对用户而言最快,而另一种方法对于继承您的设计以进行维护和添加新功能的开发人员而言最快。至于哪种选择最好,就作为习题留给读者吧。
myfriend2010 发表于:2007.08.18 16:40 ::分类: (db2 ) ::阅读:(690次) ::评论 (0)
===========================================================
联邦数据库的使用过程!
===========================================================
首先呢非常非常感谢diablo2和wangzhonnew和pub的很多人对我最近以来的帮助和鼓励!
联邦数据库的理解就不说了哈!
下边就一个例子来配置:
在3.40上创建基于4.5的联邦数据库的过程:
1.设置联邦数据库开关
db2 update dbm cfg using federated yes
db2stop
db2start
db2
2.为远程数据库创建“包装器”:
create wrapper drda
--drda为名称
3.
定义联邦服务器
create server tstsvr
type DB2/AIX --数据库类型
version 8.1 --版本
wrapper drda authorization "db2admin" password "...." options(NODE 'SERVER',dbname 'DW');
--
authorization 为远程数据库用户
-- password 为密码
--NODE 为远程实例映射到本地的node
--dbname为远程实例下的数据库名
commit;
4.为联邦者认证创建用户映射
-- create user mapping for "DB2ADMIN" server tstsvr options(remote_authid 'DB2ADMIN',remote_password '....');
-- commit;
CREATE USER MAPPING FOR "DB2ADMIN" --db2admin为本地用户
SERVER TSTSVR
OPTIONS
(REMOTE_AUTHID 'db2admin',--远程用户名和3一致
REMOTE_PASSWORD 777400419419456990610222 --远程秘密和3一致,不过这边有一个加密的过程
);
5. 表别名 - 访问远程表的“门票”
create nickname CUST_TYPE_C1_Z for tstsvr.db2admin.CUST_GROUP_C1_Z;
commit;
6.测试如下:
select * from CUST_TYPE_C1_Z;
--auther:z.x.t
--前提:用quest center在3.40上配置了关于4.5的catalog,如果没有quest center也可以用命令来配置
--如下:
1。创建节点实例
CATALOG TCPIP NODE server
REMOTE 192.168.4.5
SERVER 50000
REMOTE_INSTANCE db2
OSTYPE NT;
2。创建实例下的数据库
CATALOG DATABASE dw
AS dw
AT NODE SERVER
AUTHENTICATION SERVER;
参考:http://www.mp3sea.net/DB2/2007-3-22/LianBang-ShuJuKuHuCaoZuoXing-Di-1-BuBan-ygac0271.htm
myfriend2010 发表于:2007.08.18 11:01 ::分类: (db2 ) ::阅读:(27389次) ::评论 (0)
===========================================================
为什么客户端连服务器总是报错SQL30081N错?
===========================================================
为什么客户端连服务器总是报错SQL30081N错?
问题已经基本搞清!
在网上找了很久,觉得这份帖子比较精辟。
[url]http://beta.xmu.cn/modules.php?op=m...article&sid=111[/url]
当你遇到无法连接DB2的问题时,首先要了解整个层次模型,多层模型将会涉及一个或多个中间层,会给故障定位增加难度。另外,诸如操作系统、DB2版本及补丁级别、通讯协议也是要了解的。
一个基本的故障解决方法是:如果是客户端上的应用遇到问题,那么用DB2命令行来测试是否可以连接到DB2服务器。如果是三层结构,那么直接在中间层上尝试连接DB2服务器。
通常,有关通讯的故障会出现以下信息:
SQL30081N A communication error has been detected. Communication
protocol being used: "TCP/IP". Communication API being used: "SOCKETS".
Location where the error was detected: "". Communication function
detecting the error: "connect". Protocol specific error code(s):
"10061", "*", "*". SQLSTATE=08001
如果问题是持续的,那会比较好解决,有可能是配置的问题,或者网络通讯。如果问题是间断性的,那可能涉及网络故障、连接池中代理太少。
如果你是远程客户端遇到问题,那么先测试服务器本地是否可以连到DB2 Server.如果还是无法连接,那么查看DB2服务器是否正常工作。如果可以连接,说明网络通讯故障,或者远程客户端配置有问题。
检查服务器的配置情况如下:
验证存在的DB2数据库
db2 list db directory
db2 list db directory show detail
验证实例使用的通讯协议,查看DB2COMM变量
db2set -all
查看数据库管理器的配置,查看SVCENAME(特指tcpip协议)
db2 get dbm cfg
查看/etc/services中,有无与上面对应SVCENAME的端口,例如:
db2cDB2 50000/tcp
要确认服务器是否在监听,可以用netstat -an 来查看端口是否处于LISTEN状态
检查客户端的配置如下:
验证远程服务器实例配置
db2 list node directory
db2 list node directory show detail
ping hostname来验证通讯
使用telnet hostname port来验证是否能连到实例
另外,DB2提供了一个PCT工具来专门解决有关通讯的故障,如果上面的方法还没有解决你的问题,那么请参阅相关资料来使用它。
--------------------------------------------------------------------------------
作者:cq_1390263 时间:06-01-13 09:17
检查服务器的配置情况如下:
验证存在的DB2数据库
db2 list db directory
db2 list db directory show detail
验证实例使用的通讯协议,查看DB2COMM变量
db2set -all
查看数据库管理器的配置,查看SVCENAME(特指tcpip协议)
db2 get dbm cfg
查看/etc/services中,有无与上面对应SVCENAME的端口,例如:
db2cDB2 50000/tcp
要确认服务器是否在监听,可以用netstat -an 来查看端口是否处于LISTEN状态
(来源IBM教材)
为远程连接而准备 DB2 服务器
在 DB2 客户机能够连接到数据库以前,必须确保正确设置了服务器端通信。要准备将服务器用于 TCP/IP 和 NetBIOS 连接:
设置 DB2 概要文件注册表 DB2COMM,以使实例支持指定的通信,如下所示:
db2set DB2COMM=TCPIP,NETBIOS
在数据库管理器配置文件中为每个受支持的协议设置必需的信息。
对于 TCP/IP,为每个支持 TCP/IP 的实例分配一个端口号。名为 services 的文件包含在系统上定义的服务及其端口号。该文件的位置取决于平台。例如,在 UNIX 上,它通常被存储在 /etc 中。
由于一个端口号只能被一个服务使用,所以建议将 services 文件用作维护所有服务及其相关端口号列表的中央位置。要把 TCP 端口 50000 保留给名为 db2icdb2 的服务,可将以下行追加到 services 文件:
db2icdb2 50000/tcp
更新数据库管理器配置文件,以便 DB2 将把与服务 db2icdb2 相关的端口号用于您正在使用的实例:
db2 update database manager configuration using svcename db2icdb2
如果选择不使用 services 文件,只需用正确的端口号更新 svcename:
db2 update database manager configuration using svcename 50000
对于 NetBIOS,只需在数据库管理器配置文件中输入 NetBIOS 工作站名称(nname):
db2 update database manager configuration using nname DB2NTSERV
参数 svcename 和 nname 不能联机配置。先停止实例然后重新启动它,以便能够使用新值:
db2stop
db2start
myfriend2010 发表于:2007.08.16 10:58 ::分类: (db2 ) ::阅读:(936次) ::评论 (1)
===========================================================
DB2服务器链接中几种遇到的出错的解决
===========================================================
1、DB2中几种遇到的SQL1032N出错的解决
在使用DB2以来,碰到了几次出现提示SQL1032N错误,每次出错时出错信息大概如下:
11/21/2004 22:15:33 0 0 SQL1042C 发生意外的系统错误。
SQL1032N 未发出启动数据库管理器的命令。 SQLSTATE=57019。
每次出现问题后,都到网上找了很多资料,也问了许多人,费了些力才搞定的。几次出错的原因和解决方法都不尽相同,解决后我也只做了个简单的记录。一直想把它们写下来,方便方便后来也遇到同样问题,跟我一样到处查找的人,中间也写了一些废话,比如我如何查找错误,甚至于作了哪些无用功。
第一种SQL1032N出错,是某天DB2的实例突然无法启动了,用db2start就提示大概如下的出错信息:
12/30/2004 11:28:39 0 0 SQL1042C 发生意外的系统错误。
SQL1032N 未发出启动数据库管理器的命令。 SQLSTATE=57019。
初次遇到这种问题,还以为会不会是数据库没起来,情急之下什么命令比如激活数据库只类的,都拿来试了试,实例都起不来,当时运行这些命令,肯定都是不行的了。
后来突然发现,在开启机器的时候,提示有个服务出错了没启动,由此推想应该就是在Window服务里设置为自动启动的DB2实例服务没有正常启动,我在服务里面手动启动它,提示这样的错误:
WINDOWS不能在本地计算机启动DB2-DB2-0.有关更多信息,查阅系统事件日志.并参考特定服务代码-8000.
查看事件管理器,有这样的记录:
DB2-DB2-0服务因4294959296服务性错误而停止.来源SERVICE CONTROL 事件ID:7024
做了这么多,全都是无用功,只限于知道了服务没起来,等于没找。
之后通过各方询问,终于找到了原因:License到期了。
在db2cmd界面下运行db2licm -l,可以很明显的看到许可证已经过期了。
知道原因所在了,剩下的,就是自己想办法去解决这个问题了。
小结:直到现在,在有些论坛中,还很经常看到有人发这种帖子来问,至少我在两个月内就碰到了三次这种帖子。所以,如果不是可以确定已经有永久授权的情况下,发生这种情况,用db2licm -l查一下,也不算坏事。
还有一种情况,跟前面的差不多
也是在启动实例的时候出现如上的SQL1032N错误。在windows NT服务中无法启动DB2-DB0服务,同时提示:
出错1069,登陆失败错误。
这个错误比较简单,是用来启动服务的用户名或密码错误。只需要在服务的属性中,选择登陆选项卡,选择用户,并填好密码,重新启动服务就可以了。
小结:这种情况,一般发生在切换用户登陆NT系统或者更改了DB2用户的密码的情况下。
第三种情况是这样的:
最开始,是突然DB2的客户端连接不上server了,提示如下:
C:Documents and SettingsAdministrator>db2 connect to fjdldw user install using install3211
SQL30081N 检测到通信错误。正在使用的通信协议:"TCP/IP"。正在使用的通信API:
"SOCKETS"。检测到错误的位置:"10.142.12.1"。检测到错误的通信函数:"connect"。协
议特定的错误代码:"10061"、"*"、"*"。 SQLSTATE=08001
我本来还以为真是什么TCP/IP协议的问题,去查找了很多与SQL30081N错误相关的信息,都无法解决问题。后来到了在服务器上检查,发现DB2实例未起来。
用db2start命令,仍是提示:
D:ProgramSQLLIBBIN>db2start
12/30/2004 11:28:39 0 0 SQL1042C 发生意外的系统错误。
SQL1032N 未发出启动数据库管理器的命令。 SQLSTATE=57019
用db2 get dbm cfg查看配置文件,因未作过其他操作,所以没有什么异常
查看相应实例下的db2diag.log文件,摘取真正有用的部分出错日志:
Failed to create the memory segment used for communication with fenced routines. If re-starting db2, ensure no db2fmp processes were on the instance prior to start. Otherwise, you can ajust this value through DB2_FMP_COMM_HEAPSZ db2set value, or by decreasing your ASLHEAPSZ setting.
依据ensure no db2fmp processes were on the instance prior to start,将任务管理器里的db2fmp进程全部杀掉,然后重新启动实例。db2start,OK!
小结:后来查了一查,db2fmp进程用于执行受保护的存储过程,或者自定义函数。这次出错的原因,一直没有弄清楚。但是,通过这次解决,可以说明一点,出了错误,查查db2diag.log文件,总是不会错的。^_^
2、DB2许可证过期问题解决 && Eclipse之中jdbc调用DB2
最笨的办法是将系统日期向前调。
使用的连接字符串如"jdbc:db2://10.10.50.194:50000/ebank",在获取连接时出现异常如下:“com.ibm.db2.jcc.c.DisconnectException: encoding not supported!!”。在搜索Google未果后只好自己硬着头皮找办法解决。发现另外一个同事在WSAD中连接正常(我用的Eclipse),灵机一动将引用的JRE从Sun的标准JDK1.4.2换成了WSAD带的IBM的JDK1.4,连接时正常!又是一个JDK的问题啊。
只之后可能会出现一个license的问题,需要将DB2之中的几个db2jcc_license_cisuz.jar以及db2jcc_license_cu.jar加入到项目之中去。
但是这样仍然存在Timestamp从数据库之中不能用,ResultSet.getTimestamp()读出来的问题?如何解决?
耗了我将近一天的时间的采用"com.ibm.db2.jcc.DB2Driver"连接DB2数据库的时候,读取Timestamp类型的数据的时候老是出现异常的情况,报告出现ArrayOutofIndex什么的错误。今天,终于把它给解决了,原来,使用的DB2 V8.1之中带的db2jcc.jar包是不正确的,改成了DB2 V8.2之中的带的db2jcc.jar包程序就运行正确了。
经验,JDBC连接DB2数据库的时候出现的很多的奇怪的问题是由包不对所导致的,遇到这种问题一定要检查所使用的驱动的包是否正确。
3、SQL30081N 检测到通信错误。正在使用的通信协议:"TCP/IP"。正在使用的通信API:"SOCKETS"。检测到错误的位置:"192.168.1.12"。检测到错误的通信函数:"connect"。协议特定的错误代码:"10061"、"*"、"*"。 SQLSTATE=08001
遇到该问题,有以下几种方法去查找原因:
一、看看端口号有没有配置正确,看一下配置参数svcename跟services文件中配置的db2端口号是否一致,windows一般用50000,unix/linux一般用60000
二、连接出错首先看看服务器ip 和端口写对没有
ip如果没错就要看看服务器的db2服务端口对不对。另外对于服务器下面这些也要注意
检查服务器的配置情况如下:
验证存在的DB2数据库
db2 list db directory
db2 list db directory show detail
验证实例使用的通讯协议,查看DB2COMM变量
db2set -all
查看数据库管理器的配置,查看SVCENAME(特指tcpip协议)
db2 get dbm cfg
查看/etc/services中,有无与上面对应SVCENAME的端口,例如:
db2cDB2 50000/tcp
要确认服务器是否在监听,可以用netstat -an 来查看端口是否处于LISTEN状态
myfriend2010 发表于:2007.08.16 10:54 ::分类: (db2 ) ::阅读:(2436次) ::评论 (0)
===========================================================
关于DB2的10 佳性能技巧-转
===========================================================
每隔大约几个星期,我们就会接到苦恼的 DBA 们的电话,抱怨有关性能的问题。“我们 Web 站点速度慢得像蜗牛一样”,他们叫苦道,“我们正在失去客户,情况严重。你能帮忙吗?”为了回答这些问题,我为我的咨询公司开发了一个分析流程,它能让我们很快找到性能问题的原因,开发出补救措施并提出调整意见。这些打电话的人极少询问费用和成本 - 他们只关心制止损失。当 DB2 或电子商务应用程序的运行不能达到预期的性能时,组织和财务的收益将遭受极大的损失。
为了帮助 DB2 DBA 避免性能灾难并获得高性能,我为我们的客户、用户和 DB2 专家同行总结了一套故障诊断流程。以下详细说明在 Unix、Windows 和 OS/2 环境下使用 DB2 UDB 的电子商务 OLTP 应用程序的 10 条最重要的性能改善技巧 - 并在本文的结束部分作出总结。
10. 监视开关
确保已经打开监视开关。如果它们没有打开,您将无法获取您需要的性能信息。要打开该监视开关,请发出以下命令:
db2 "update monitor switches using lock ON sort ON bufferpool ON uow ON table ON statement ON"
9. 代理程序
确保有足够的 DB2 代理程序来处理工作负载。要找出代理程序的信息,请发出命令:
db2 "get snapshot for database manager"
并查找以下行:
High water mark for agents registered = 7 High water mark for agents waiting for a token = 0 Agents registered= 7 Agents waiting for a token= 0 Idle agents= 5 Agents assigned from pool= 158 Agents created from empty Pool = 7 Agents stolen from another application= 0 High water mark for coordinating agents= 7 Max agents overflow= 0
如果您发现Agents waiting for a token或Agents stolen from another application不为 0,那么请增加对数据库管理器可用的代理程序数(MAXAGENTS 和/或 MAX_COORDAGENTS取适用者)。
8. 最大打开的文件数
DB2 在操作系统资源的约束下尽量做一个“优秀公民”。它的一个“优秀公民”的行动就是给在任何时刻打开文件的最大数设置一个上限。数据库配置参数MAXFILOP约束 DB2 能够同时打开的文件最大数量。当打开的文件数达到此数量时,DB2 将开始不断地关闭和打开它的表空间文件(包括裸设备)。不断地打开和关闭文件减缓了 SQL 响应时间并耗费了 CPU 周期。要查明 DB2 是否正在关闭文件,请发出以下命令:
db2 "get snapshot for database on DBNAME"
并查找以下的行:
Database files closed = 0
如果上述参数的值不为 0,那么增加MAXFILOP的值直到不断打开和关闭文件的状态停止。使用以下命令:
db2 "update db cfg for DBNAME using MAXFILOP N"
7. 锁
LOCKTIMEOUT的缺省值是 -1,这意味着将没有锁超时(对 OLTP 应用程序,这种情况可能会是灾难性的)。尽管如此,我还是经常发现许多 DB2 用户用LOCKTIMEOUT= -1。将LOCKTIMEOUT设置为很短的时间值,例如 10 或 15 秒。在锁上等待过长时间会在锁上产生雪崩效应。
首先,用以下命令检查LOCKTIMEOUT的值:
db2 "get db cfg for DBNAME"
并查找包含以下文本的行:
Lock timeout (sec) (LOCKTIMEOUT) = -1
如果值是 -1,考虑使用以下命令将它更改为 15 秒(一定要首先询问应用程序开发者或您的供应商以确保应用程序能够处理锁超时):
db2 "update db cfg for DBNAME using LOCKTIMEOUT 15"
您同时应该监视锁等待的数量、锁等待时间和正在使用锁列表内存(lock list memory)的量。请发出以下命令:
db2 "get snapshot for database on DBNAME"
查找以下行:
Locks held currently= 0 Lock waits= 0 Time database waited on locks (ms)= 0 Lock list memory in use (Bytes)= 576 Deadlocks detected= 0 Lock escalations= 0 Exclusive lock escalations= 0 Agents currently waiting on locks= 0 Lock Timeouts= 0
如果Lock list memory in use (Bytes)超过所定义LOCKLIST大小的 50%,那么在LOCKLIST数据库配置中增加 4k 页的数量。
6. 临时表空间
为了改善 DB2 执行并行 I/O 和提高使用TEMPSPACE的排序、散列连接(hash join)和其它数据库操作的性能,临时表空间至少应该在三个不同的磁盘驱动器上拥有三个容器。
要想知道您的临时表空间具有多少容器,请发出以下命令:
db2 "list tablespaces show detail"
查找与以下示例类似的TEMPSPACE表空间定义:
Tablespace ID= 1 Name= TEMPSPACE1 Type= System managed space Contents= Temporary data State= 0x0000 Detailed explanation: Normal Total pages= 1 Useable pages= 1 Used pages= 1 Free pages= Not applicable High water mark (pages)= Not applicable Page size (bytes)= 4096 Extent size (pages)= 32 Prefetch size (pages)= 96 Number of containers= 3
注意Number of containers的值是 3,而且Prefetch size是Extent size的三倍。为了得到最佳的并行 I/O 性能,重要的是Prefetch size为Extent size的倍数。这个倍数应该等于容器的个数。
要查找容器的定义,请发出以下命令:
db2 "list tablespace containers for 1 show detail"
1 指的是tablespace ID #1,它是刚才所给出的示例中的TEMPSPACE1。
5. 内存排序
OLTP 应用程序不应该执行大的排序。它们在 CPU、I/O 和所用时间方面的成本极高,而且将使任何 OLTP 应用程序慢下来。因此,256 个 4K 页(1MB)的缺省SORTHEAP大小(1MB)应该是足够了。您也应该知道排序溢出的数量和每个事务的排序数。
请发出以下命令:
Db2 "get snapshot for database on DBNAME"
并查找以下行:
Total sort heap allocated= 0 Total sorts = 1 Total sort time (ms)= 8 Sort overflows = 0 Active sorts = 0 Commit statements attempted = 3 Rollback statements attempted = 0 Let transactions = Commit statements attempted + Rollback statements attempted Let SortsPerTX= Total sorts / transactions Let PercentSortOverflows = Sort overflows * 100 / Total sorts
如果PercentSortOverflows ((Sort overflows * 100) / Total sorts )大于 3 个百分点,那么在应用程序 SQL 中会出现严重的或意外的排序问题。因为正是溢出的存在表明发生了大的排序,所以理想的情况是发现没有排序溢出或至少其百分比小于一个百分点。
如果出现过多的排序溢出,那么“应急”解决方案是增加SORTHEAP的大小。然而,这样做只是掩盖了真实的性能问题。相反,您应该确定引起排序的 SQL 并更改该 SQL、索引或群集来避免或减少排序开销。
如果SortsPerTX大于 5 (作为一种经验之谈),那么每个事务的排序数可能很大。虽然某些应用程序事务执行许多小的组合排序(它们不会溢出并且执行时间很短),但是它消耗了过多的 CPU。当SortsPerTX很大时,按我的经验,这些机器通常会受到 CPU 的限制。确定引起排序的 SQL 并改进存取方案(通过索引、群集或更改 SQL)对提高事务吞吐率是极为重要的。
对于每个表,确定 DB2 为每个事务读取的行数。您必须发出两个命令:
db2 "get snapshot for database on DBNAME"
db2 "get snapshot for tables on DBNAME"
在发出第一个命令以后,确定发生了多少个事务(通过取Commit statements attempted和Rollback statements attempted之和 - 请参阅技巧 3)。
在发出第二个命令以后,将读取的行数除以事务数(RowsPerTX)。在每个事务中,OLTP 应用程序通常应该从每个表读取 1 到 20 行。如果您发现对每个事务有成百上千的行正被读取,那么发生了扫描操作,也许需要创建索引。(有时以分布和详细的索引来运行 runstats 也可提供了一个解决的办法。)
“get snapshot for tables on DBNAME”的样本输出如下:
Snapshot timestamp = 09-25-2000 4:47:09.970811 Database name= DGIDB Database path= /fs/inst1/inst1/NODE0000/SQL00001/ Input database alias= DGIDB Number of accessed tables= 8 Table List Table Schema= INST1 Table Name= DGI_ SALES_ LOGS_TB Table Type= User Rows Written= 0 Rows Read= 98857 Overflows= 0 Page Reorgs= 0
Overflows 的数量很大就可能意味着您需要重组表。当由于更改了行的宽度从而 DB2 必须在一个不够理想的页上定位一个行时就会发生溢出。
表空间快照对理解访问什么数据以及如何访问是极其有价值的。要得到一个表空间快照,请发出以下命令:
db2 "get snapshot for tablespaces on DBNAME"
对每个表空间,回答以下问题:
平均读取时间(ms)是多少? 平均写入时间(ms)是多少? 异步(预取)相对于同步(随机)所占的物理 I/O 的百分比是多少? 每个表空间的缓冲池命中率是多少? 每分钟读取多少物理页面? 对于每个事务要读取多少物理和逻辑页面?
对于所有表空间,回答以下问题:
哪个表空间的读取和写入的时间最慢?为什么?是因为其容器在慢速的磁盘上吗?容器大小是否相等?对比异步访问和同步访问,访问属性是否和期望的一致?随机读取的表应该有随机读取的表空间,这是为了得到高的同步读取百分比、通常较高的缓冲池命中率和更低的物理 I/O 率。
对每个表空间,确保预取大小等于数据块大小乘以容器数。请发出以下命令:
db2 "list tablespaces show detail"
如果需要,可以为一个给定表空间改变预取大小。可以使用以下命令来检查容器定义:
db2 "list tablespace containers for N show detail"
在此,N 是表空间标识号。
2. 缓冲池优化
我时常发现一些 DB2 UDB 站点,虽然机器具有 2、4 或 8GB 内存,但是 DB2 数据库却只有一个缓冲池(IBMDEFAULTBP),其大小只有 16MB!
如果在您的站点上也是这种情况,请为 SYSCATSPACE 目录表空间创建一个缓冲池、为TEMPSPACE表空间创建一个缓冲池以及另外创建至少两个缓冲池:BP_RAND和BP_SEQ。随机访问的表空间应该分配给用于随机访问的缓冲池(BP_RAND)。顺序访问(使用异步预取 I/O)的表空间应该分配给用于顺序访问的缓冲池(BP_SEQ)。根据某些事务的性能目标,您可以创建附加的缓冲池;例如,您可以使一个缓冲池足够大以存储整个“热”(或者说访问非常频繁的)表。当涉及到大的表时,某些 DB2 用户将重要表的索引放入一个索引(BP_IX)缓冲池取得了很大成功。
太小的缓冲池会产生过多的、不必要的物理 I/O。太大的缓冲池使系统处在操作系统页面调度的风险中并消耗不必要的 CPU 周期来管理过度分配的内存。正好合适的缓冲池大小就在“太小”和“太大”之间的某个平衡点上。适当的大小存在于回报将要开始减少的点上。如果您没有使用工具来自动进行回报减少分析,那么您应该在不断增加缓冲池大小上科学地测试缓冲池性能(命中率、I/O 时间和物理 I/O 读取率),直到达到最佳的缓冲池大小。因为业务一直在变动和增长,所以应该定期重新评估“最佳大小”决策。
1. SQL 成本分析
一条糟糕的 SQL 语句会彻底破坏您的一整天。我不止一次地看到一个相对简单的 SQL 语句搞糟了一个调整得很好的数据库和机器。对于很多这些语句,天底下(或在文件中)没有 DB2 UDB 配置参数能够纠正因错误的 SQL 语句导致的高成本的情况。
更糟糕的是,DBA 常常受到种种束缚:不能更改 SQL(可能是因为它是应用程序供应商提供的,例如SAP、PeopleSoft或Siebel)。这给 DBA 只留下三条路可走:
1. 更改或添加索引
2. 更改群集
3. 更改目录统计信息
另外,如今健壮的应用程序由成千上万条不同的 SQL 语句组成。这些语句执行的频率随应用程序的功能和日常的业务需要的不同而不同。SQL 语句的实际成本是它执行一次的成本乘以它执行的次数。
每个 DBA 所面临的重大的任务是,识别具有最高“实际成本”的语句的挑战,并且减少这些语句的成本。
通过本机 DB2 Explain 实用程序、一些第三方供应商提供的工具或 DB2 UDB SQL Event Monitor 数据,您可以计算出执行一次 SQL 语句所用的资源成本。但是语句执行频率只能通过仔细和耗时地分析 DB2 UDB SQL Event Monitor 的数据来了解。
在研究 SQL 语句问题时,DBA 使用的标准流程是:
1. 创建一个 SQL Event Monitor,写入文件:
$> db2 "create event monitor SQLCOST for statements write to ..."
2. 激活事件监视器(确保有充足的可用磁盘空间):
$> db2 "set event monitor SQLCOST state = 1"
3. 让应用程序运行。
4. 取消激活事件监视器:
$> db2 "set event monitor SQLCOST state = 0"
5. 使用 DB2 提供的 db2evmon 工具来格式化 SQL Event Monitor 原始数据(根据 SQL 吞吐率可能需要数百兆字节的可用磁盘空间):
$> db2evmon -db DBNAME -evm SQLCOST > sqltrace.txt
6. 浏览整个已格式化的文件,寻找显著大的成本数(一个耗时的过程):
$> more sqltrace.txt
7. 对已格式化的文件进行更完整的分析,该文件试图标识唯一的语句(独立于文字值)、每个唯一语句的频率(它出现的次数)和其总 CPU、排序以及其它资源成本的总计。如此彻底的分析在 30 分钟的应用程序 SQL 活动样本上可能要花一周或更多的时间。
要减少确定高成本 SQL 语句所花的时间,您可以考虑许多可用的信息来源:
从技巧 4,务必要计算在每个事务中从每个表中读取的行数。如果产生的数字看上去很大,那么 DBA 可以在 SQL Event Monitor 格式化输出中搜索有关的表名称(这将缩小搜索范围而且节省一些时间),这样也许能够找出有问题的语句。 从技巧 3,务必计算每个表空间的异步读取百分比和物理 I/O 读取率。如果一个表空间的异步读取百分比很高并远远超过平均的物理 I/O 读取率,那么在此表空间中的一个或更多的表正在被扫描。查询目录并找出哪些表被分配到可疑的表空间(每个表空间分配一个表提供最佳性能检测),然后在 SQL Event Monitor 格式化输出中搜索这些表。这些也可能有助于缩小对高成本 SQL 语句的搜索范围。 尝试观察应用程序执行的每条 SQL 语句的 DB2 Explain 信息。然而,我发现高频率、低成本语句经常争用机器容量和能力来提供期望的性能。 如果分析时间很短而且最大性能是关键的,那么请考虑使用供应商提供的工具(它们能够快速自动化识别资源密集的 SQL 语句的过程)。Database-GUYS Inc.的 SQL-GUY 工具提供精确、实时且均衡的 SQL 语句的成本等级分析。
继续调节
最佳性能不仅需要排除高成本 SQL 语句,而且需要确保相应的物理基础结构是适当的。当所有的调节旋钮都设置得恰到好处、内存被有效地分配到池和堆而且 I/O 均匀地分配到各个磁盘时,才可得到最佳性能。虽然量度和调整需要时间,但是执行这 10 个建议的 DBA 将非常成功地满足内部和外部的 DB2 客户。因为电子商务的变化和增长,即使是管理得最好的数据库也需要定期的微调。DBA 的工作永远都做不完!
对工作负载使用足够的代理程序。 不允许 DB2 不必要地关闭和打开文件。 不允许长期的锁等待。 确保数据库的 TEMPSPACE 表空间的并行 I/O 能力。 保守地管理 DB2 排序内存并不要以大的 SORTHEAP 来掩盖排序问题。 分析表的访问活动并确定具有特别高的每个事务读取行数或溢出数的表。 分析每个表空间的性能特性,并寻求改善读取时间最慢、等待时间最长、物理 I/O 读取率最高、命中率最差的表空间性能以及与所期望的不一致的访问属性。 创建多个缓冲池,有目的地将表空间分配到缓冲池以便于共享访问属性。 检查 DB2 UDB SQL Event Monitor 信息以找到哪个 SQL 语句消耗计算资源最多并采取正确的措施。 一旦排除了高成本 SQL,马上重新评估配置和物理设计设置。
myfriend2010 发表于:2007.08.14 17:42 ::分类: (db2 ) ::阅读:(615次) ::评论 (0)
===========================================================
将oracle的 CONNECT BY 移植到 DB2
===========================================================
将oracle的 CONNECT BY 移植到 DB2
本文通过例子逐步描述如何将 CONNECT BY 语法和相关的伪列映射到 DB2® Universal Database™(DB2 UDB) for Linux®、UNIX® 和 Windows® 中的公共表表达式
动机
当把应用程序从 Oracle 移植或迁移到 DB2 UDB for Linux、UNIX 和 Windows 时,递归查询成为一块巨大的绊脚石。能理解和使用 Oracle 型递归的开发人员,却常常无法自然而然地理解 DB2 中的递归,反过来也是一样。
乍一看来,这似乎是因为 DB2 是按照 SQL 标准中的定义并使用公共表表达式(CTE)和 UNION ALL 来实现递归的,而 Oracle 则使用 CONNECT BY 子句和一组所谓的伪列(pseudo column)及系统过程来定义递归。然而,两者之间的差别不仅在于语法方面。在底层,DB2 处理递归时采用的方法是逐层递归(广度优先),而 Oracle 采用的是深度优先的方法。后一种方法自然地产生与组织结构图(org chart)相匹配的输出。
在本文中,我使用一个实用的例子,这个例子将 CONNECT BY 和相关的伪列与 DB2 递归逐步进行匹配。
安装
为了执行一些查询,您必须下载和解压本文后面 下载 小节中提供的CONNECT_BY.zip 文件。
如果您使用的是 32 位 Windows、32 位 Intel 上的 Linux 或 64 位 AIX® 系统,那么只需将 CONNECT_BY.zip 文件中适当子目录中的可执行文件 connect_by(在 Windows 上是 connect_by.dll)复制到 sqllib/function 目录。
如果使用的是其他操作系统或硬件平台,并且系统中安装了 C 编译器,那么可以将 Connect_By/FunctionSource 目录中的文件复制到 sqllib/samples/c 目录中。进入到那个目录后,运行 bldrtn connect_by。该命令将编译 C 源代码。bldrtn 还将把产生的可执行文件复制到 sqllib/function,这样便可以运行本文中的查询了。
为了方便,当连接到一个测试数据库时,运行 CONNECT_BY.zip 中的以下文件将重新产生本文中的所有 DB2 SQL:
db2 -tvf connect_by_functions.sql
db2 -tvf connect_by_sample.sql
设置例子
首先,我们将定义和填充一个雇员表。这个表有四个列,一个是作为主键的雇员 ID,一个是将雇员与其经理关联起来的经理 ID,此外还有姓名和薪水:
1 CREATE TABLE emp(empid INTEGER NOT NULL PRIMARY KEY,
2 name VARCHAR(10),
3 salary DECIMAL(9, 2),
4 mgrid INTEGER);
5 INSERT INTO emp
6 VALUES ( 1, 'Jones', 30000, 10),
7 ( 2, 'Hall', 35000, 10),
8 ( 3, 'Kim', 40000, 10),
9 ( 4, 'Lindsay', 38000, 10),
10 ( 5, 'McKeough', 42000, 11),
11 ( 6, 'Barnes', 41000, 11),
12 ( 7, 'O''Neil',36000, 12),
13 ( 8, 'Smith', 34000, 12),
14 ( 9, 'Shoeman', 33000, 12),
15 (10, 'Monroe', 50000, 15),
16 (11, 'Zander', 52000, 16),
17 (12, 'Henry', 51000, 16),
18 (13, 'Aaron', 54000, 15),
19 (14, 'Scott', 53000, 16),
20 (15, 'Mills', 70000, 17),
21 (16, 'Goyal', 80000, 17),
22 (17, 'Urbassek', 95000, NULL);
注意被插入的这些列,显然雇员‘Urbassek’是最高级的经理,‘Goyal’和‘Mills’是他的属下。而 ‘Scott’又是‘Goyal’的属下,但是他没有自己的属下。‘Monroe’则是‘Hall’、‘Kim’和‘Lindsay’的上司,同时也是‘Mills’的属下。
一个合情合理的问题是:“谁是‘Goyal’直接或间接的属下?”
一个简单的递归查询
为了回答谁是‘Goyal’的属下这个问题,Oracle 开发人员可能会编写以下查询:
1 SELECT name
2 FROM emp
3 START WITH name = 'Goyal'
4 CONNECT BY PRIOR empid = mgrid
START WITH 表示递归的种子,而 CONNECT BY 描述递归步骤,也就是如何从第 n 步发展到第 (n + 1) 步。由于在归结 name 时需要区分第 n 步和第 (n + 1) 步,因此使用 PRIOR 来表明 empid 属于第 n 步,而 mgrid 属于第 (n + 1) 步。在第 1 步,empid 为 16,mgrid 也必须是 16,因此第 2 步产生‘Scott’、‘Henry’和‘Zander’。他们的 empid 将作为第 3 步的 PRIOR,依此类推。
Oracle 语法非常简洁。SQL 标准和 DB2 语法不使用任何递归专用的关键词,而是使用常规的 SQL 来描述完全相同的关系。您会看到,这样做显得更啰嗦,但是同样也比较简单:
1 WITH n(empid, name) AS
2 (SELECT empid, name
3 FROM emp
4 WHERE name = 'Goyal'
5 UNION ALL
6 SELECT nplus1.empid, nplus1.name
7 FROM emp as nplus1, n
8 WHERE n.empid = nplus1.mgrid)
9 SELECT name FROM n;
WITH 子句允许在一条语句中定义一个有名称的查询,在同一条语句中,稍后将引用到这个查询。用技术术语来说,这叫做 公共表表达式(common table expression,CTE)。 CTE 现在在大多数基于 SQL 的 DBMS 中都受到支持,包括 Oracle 9i 和 SQL Server 2005,当然也包括 DB2。
这个 CTE 的特殊之处在于,它在自己的定义中被引用。这就是常规 CTE 与 递归 CTE 的区别。这里我将 CTE 命名为 n,以便与递归步骤关联起来。递归 CTE 由两部分组成,这两部分通过 UNION ALL 连接:
一部分是递归的种子(即第 1 步)。这就是在 Oracle 中用 START WITH 描述的那一部分。在递归 CTE 中,它只是一个普通的提供一组行的查询。在这个例子中,我们查询 emp 表,并用 ‘Goyal’ 进行过滤。当然我们会选择 name,另外还有 empid,因为在递归步骤中需要它。
另一部分是递归从第 n 步发展到第 (n + 1) 步。这里我们引用第 n 步(CTE n),并使用与 CONNECT BY 中相同的谓词将它与第 (n + 1) 步相连接。但是,这里不使用 PRIOR,而是使用常规的相关名称来区分第 n 步和第 (n + 1) 步。
这里有必要看一下这个查询的输出:
NAME
----------
SQL0347W The recursive common table expression "SRIELAU.N"
may contain an infinite loop. SQLSTATE=01605
Goyal
Zander
Henry
Scott
McKeough
Barnes
O'Neil
Smith
Shoeman
9 record(s) selected with 1 warning messages printed.
DB2 不执行任何自动的循环检查。正因为如此,当它断定可能存在循环时,就会返回这条警告。介意这条警告的 DB2 开发人员通常添加一个 level 列,令其在每次递归中加 1,并且不能大于一个固定的值。 DB2 承认这种模式,因而取消这条警告。出于映射 CONNECT BY 的目的,从现在开始我们将忽略警告,因为在后面将增加循环检查。
而且,令人感兴趣的是,DB2 返回结果时所依照的顺序暴露了递归如何逐层地而不是采用遍历树的方法进行处理。
在讨论伪列和更复杂的例子之前,我想简要地解释一下 Oracle 中递归的 WHERE 谓词应该放在哪里。我们将修改这个例子,使它返回 ‘Goyal’ 管辖的所有收入超过 40,000 的雇员,包括他们的薪水。
1 SELECT name, salary
2 FROM emp
3 WHERE salary > 40000
4 START WITH name = 'Goyal'
5 CONNECT BY PRIOR empid = mgrid
令人感兴趣的是,WHERE 子句在递归说明之前。对于 DB2 开发人员,在上述查询中,该谓词似乎属于开始时考虑的一组行。然而,事实并非如此。相反,WHERE 负责过滤最终的结果,在对应的 DB2 查询中,它是属于整个查询的:
1 WITH n(empid, name, salary) AS
2 (SELECT empid, name, salary
3 FROM emp
4 WHERE name = 'Goyal'
5 UNION ALL
6 SELECT nplus1.empid, nplus1.name, nplus1.salary
7 FROM emp as nplus1, n
8 WHERE n.empid = nplus1.mgrid)
9 SELECT name FROM n WHERE salary > 40000;
NAME SALARY
---------- -----------
Goyal 80000.00
Zander 52000.00
Henry 51000.00
Scott 53000.00
McKeough 42000.00
Barnes 41000.00
6 record(s) selected
这里要清楚的是,WHERE 子句不同于 ON 子句。在后一个例子中我会重新提到这个问题。但是首先我们还是来讨论伪列。
LEVEL 伪列
最常见的伪列是 LEVEL。这个列的作用是表明产生行的递归步骤 n 属于第几步。在这个例子中,它表示‘Goyal’与雇员之间相差的管理等级加 1(因为 LEVEL 一开始为 1)。下面是原先的 Oracle 例子添加了 LEVEL 列之后的样子:
1 SELECT LEVEL, name
2 FROM emp
3 START WITH name = 'Goyal'
4 CONNECT BY PRIOR empid = mgrid
SQL 标准不必为该特性添加语法,因为它可以使用常规的 SQL 来表达:
1 WITH n(level, empid, name) AS
2 (SELECT 1, empid, name
3 FROM emp
4 WHERE name = 'Goyal'
5 UNION ALL
6 SELECT n.level + 1, nplus1.empid, nplus1.name
7 FROM emp as nplus1, n
8 WHERE n.empid = nplus1.mgrid)
9 SELECT level, name FROM n;
LEVEL NAME
----------- ----------
1 Goyal
2 Zander
2 Henry
2 Scott
3 McKeough
3 Barnes
3 O'Neil
3 Smith
3 Shoeman
9 record(s) selected
我在这里只是引入了一个 level 列,这个列的初值为 1,每次加 1。当然,任何语义都是可能的,但是这里刚好提供了和 LEVEL 相同的语义。要由开发人员来选择传递什么信息,以及如何传递信息,下一个例子将展示这一点。
 
CONNECT_BY_ROOT 表达式
CONNECT_BY_ROOT 作用在一个列上,并返回当前行最早的(root)祖先的值。为了展示它做什么事情以及如何翻译它,我修改了上面的例子,让例子使用‘Goyal’的直接下属作为 root:
1 SELECT CONNECT_BY_ROOT name AS root, name
2 FROM emp
3 START WITH name IN ('Zander', 'Henry', 'Scott')
4 CONNECT BY PRIOR empid = mgrid
为映射到 DB2,只需添加一个 root 列。
1 WITH n(empid, root, name) AS
2 (SELECT empid, name, name
3 FROM emp
4 WHERE name IN ('Zander', 'Henry', 'Scott')
5 UNION ALL
6 SELECT nplus1.empid, n.root,
7 nplus1.name
8 FROM emp as nplus1, n
9 WHERE n.empid = nplus1.mgrid)
10 SELECT root, name FROM n;
ROOT NAME
---------- ----------
Zander Zander
Henry Henry
Scott Scott
Zander McKeough
Zander Barnes
Henry O'Neil
Henry Smith
Henry Shoeman
8 record(s) selected
接下来,我将演示如何展示整个管理链,而不仅仅是根。
SYS_CONNECT_BY_PATH() 过程
运行查询时一个常见的问题是:“这个元素与递归的开始有怎样的关系?”,或者换句话说,“这一行的祖先是什么?”在 Oracle 中,可以使用 SYS_CONNECT_BY_PATH() 来连接来自每个递归步骤的值,从而形成一个祖先路径。看看下面这个著名的例子,它展示了‘Goyal’每个下属的“从属”链:
1 SELECT SYS_CONNECT_BY_PATH(name, ':') AS chain
2 FROM emp
3 START WITH name = 'Goyal'
4 CONNECT BY PRIOR empid = mgrid
在这个例子中,每个值之间用一个 ‘:’ 号隔开。而在 DB2 中要回答这个问题,可以使用与 LEVEL 相同的技术。惟一的差别是,这里使用的是 并置(concatenation),而不是 相加(addition)。
1 WITH n(empid, chain) AS
2 (SELECT empid, CAST(name AS VARCHAR(30))
3 FROM emp
4 WHERE name = 'Goyal'
5 UNION ALL
6 SELECT nplus1.empid,
7 n.chain || ':' || nplus1.name
8 FROM emp as nplus1, n
9 WHERE n.empid = nplus1.mgrid)
10 SELECT chain FROM n;
CHAIN
------------------------------
Goyal
Goyal:Zander
Goyal:Henry
Goyal:Scott
Goyal:Zander:McKeough
Goyal:Zander:Barnes
Goyal:Henry:O'Neil
Goyal:Henry:Smith
Goyal:Henry:Shoeman
9 record(s) selected
您可以自由地选择如何构造这个链。例如,可以反转并置,使‘Goyal’位于链尾。这里还应注意被执行的 CAST。对于字符串数据类型,DB2 需要通过它来知道这个链可以增长到多长。递归 CTE 的规则规定,数据类型的长度应该由种子或 UNION ALL 查询的前半部分来定义。
至此,从 CONNECT BY 到 UNION ALL 的映射已轻松完成。现在您对递归 CTE 已经感到得心应手了,接下来是继续攻克更大难题的时候了。如果只是要求按照后面选择的路径中元素的顺序对结果排序,那么只需在最后的 SELECT 中的路径上使用一个 ORDER BY:
1 WITH n(empid, chain) AS
2 (SELECT empid, CAST(name AS VARCHAR(30))
3 FROM emp
4 WHERE name = 'Goyal'
5 UNION ALL
6 SELECT nplus1.empid,
7 n.chain || ':' || nplus1.name
8 FROM emp as nplus1, n
9 WHERE n.empid = nplus1.mgrid)
10 SELECT chain FROM n
11 ORDER BY chain;
CHAIN
------------------------------
Goyal
Goyal:Henry
Goyal:Henry:O'Neil
Goyal:Henry:Shoeman
Goyal:Henry:Smith
Goyal:Scott
Goyal:Zander
Goyal:Zander:Barnes
Goyal:Zander:McKeough
9 record(s) selected
这是一种常见的 组织结构图。但是如果要求按其他不是字符串类型的列排序,结果会怎样呢?
 
ORDER SIBLINGS BY 表达式
在 Oracle 中,ORDER SIBLINGS BY 定义返回时同一父亲下各个兄弟之间的顺序。为了使用 CONNECT BY 递归地按照薪水对所有雇员排序,查询的形式如下:
1 SELECT name, level, salary
2 FROM emp
3 START WITH name = 'Goyal'
4 CONNECT BY PRIOR empid = mgrid
5 ORDER SIBLINGS BY salary
SQL 标准有用于这个需求的特定语法。然而,DB2 UDB for LUW 还没有实现 SQL 标准的这一部分。为了在 DB2 中映射这个特性,就需要发挥创造力。可以再次建立一个路径,然后对字符串排序,但是这样看上去有点儿不优雅,因为需要将数值转换成字符串,从而增加了路径的长度。而且,随后的映射将表明,提供一个更通用的解决方案比较有益。
这里,我引入了一个 用户定义函数(UDF)。UDF 是 DB2 功能的一个扩展。在这个例子中,这个 UDF(和后面的那些 UDF)是用 C 实现的,如果您遵循了前面的 安装 小节中的说明,那么 DB2 中就有它的可执行文件。
1 CREATE FUNCTION CONNECT_BY_POS
2 (POS VARCHAR(256) FOR BIT DATA,
3 N INTEGER,
4 POSPLUS1 BIGINT)
5 RETURNS VARCHAR(256) FOR BIT DATA
6 SPECIFIC CONNECT_BY_POS
7 EXTERNAL NAME 'connect_by!connect_by_pos'
8 NOT FENCED RETURNS NULL ON NULL INPUT
9 DETERMINISTIC NO SQL NO EXTERNAL ACTION
10 LANGUAGE C PARAMETER STYLE SQL ALLOW PARALLEL;
这个函数有两个作用:
该函数以行 posplus1 的全局位置的 BIGINT 值为参数并进行转换,同时使父行的 pos 模式成为下一行的模式。父行的层次 n 用于推动递归。原则上,该函数只是建立一个二进制编码的路径。这里提供的实现在内部是使用整数的。所以,这里为二进制串任意选择的长度 256 允许 64 层嵌套,通常这是可以扩展的。
作为附加的功能,该函数还测试新行的全局位置是否已经出现在父路径中。如果的确如此,那么就会产生一个运行时错误。如果没有显式地指定,Oracle 不允许循环。所以这个功能使得这个 DB2 查询是可兼容的。
下面这个与之前 CONNECT BY 版本对应的例子很好地展示了对这个 UDF 的使用:
1 WITH source(empid, name, salary, mgrid, rownum) AS
2 (SELECT empid, name, salary, mgrid,
3 ROW_NUMBER() OVER(ORDER BY salary)
4 FROM emp),
5 n(empid, name, salary, level, pos) AS
6 (SELECT empid, name, salary, 1,
7 CONNECT_BY_POS('', 0, rownum)
8 FROM source
9 WHERE name = 'Goyal'
10 UNION ALL
11 SELECT nplus1.empid, nplus1.name,
12 nplus1.salary, level + 1,
13 CONNECT_BY_POS(n.pos, level, rownum)
14 FROM source AS nplus1, n
15 WHERE n.empid = nplus1.mgrid)
16 SELECT name, level, salary
17 FROM n
18 ORDER BY pos;
NAME LEVEL SALARY
---------- ----------- -----------
Goyal 1 80000.00
Henry 2 51000.00
Shoeman 3 33000.00
Smith 3 34000.00
O'Neil 336000.00
Zander 2 52000.00
Barnes 3 41000.00
McKeough 3 42000.00
Scott 2 53000.00
9 record(s) selected
这期间发生了什么呢?通过添加另一个 CTE source,我们可以根据 ORDER SIBLINGS BY 请求的顺序对所有行发出一个全局顺序。之后,递归 CTE n 引用 source 来获得 rownum。查询的其他部分在前面已经解释过了。实际上,CONNECT_BY_POS() 产生一个二进制串 PATH,而不像 SYS_CONNECT_BY_PATH() 那样产生常规字符串。最后,该查询按照提供层次结构 pos 中的位置的路径排序。
这时,我想回到 CONNECT BY 查询中的 ON 子句。任何连接,甚至更复杂的查询,都可以用同样的方法通过将递归源的组成放入一个 CTE 中来表达。
 
NOCYCLE 关键字
至此我已经介绍了记录递归路径和在运行时检测递归的功能,实际上还可以映射 Oracle 的 CONNECT BY 查询语法中的 NOCYCLE 关键字。简言之,NOCYCLE 防止递归进入循环。对于第 (n + 1) 步,任何在祖先中已经存在的候选行都将被忽略。在 Oracle 中,使用方法如下:
1 SELECT name, level, salary
2 FROM emp
3 START WITH name = 'Goyal'
4 CONNECT BY NOCYCLE PRIOR empid = mgrid
给定祖先路径,该语义的映射很简单。只需再用一个 UDF 就足够了。如果检测到循环,该 UDF 将返回 0。如果没有检测到循环,则返回 1。注册了该 UDF 之后,我还将在管理链中引入一个循环。‘Urbassek’现在应该是‘O'Neil’的下属。
1 CREATE function CONNECT_BY_NOCYCLE
2 (N VARCHAR(256) FOR BIT DATA,
3 LEVEL INTEGER,
4 NPLUS1 BIGINT)
5 RETURNS SMALLINT
6 SPECIFIC CONNECT_BY_NOCYCLE
7 EXTERNAL NAME 'connect_by!connect_by_nocycle'
8 NOT FENCED RETURNS NULL ON NULL INPUT
9 DETERMINISTIC NO SQL NO EXTERNAL ACTION
10 LANGUAGE C PARAMETER STYLE SQL ALLOW PARALLEL;
11 UPDATE emp SET mgrid = 7 WHERE name = 'Urbassek';
12 WITH source(empid, name, salary, mgrid, rownum) AS
13 (SELECT empid, name, salary, mgrid,
14 ROW_NUMBER() OVER(ORDER BY salary)
15 FROM emp),
16 n(empid, name, salary, level, pos) AS
17 (SELECT empid, name, salary, 1,
18 CONNECT_BY_POS('', 0, rownum)
19 FROM source
20 WHERE name = 'Goyal'
21 UNION ALL
22 SELECT nplus1.empid, nplus1.name,
23 nplus1.salary, level + 1,
24 CONNECT_BY_POS(n.pos, level, rownum)
25 FROM source AS nplus1, n
26 WHERE n.empid = nplus1.mgrid
27 AND CONNECT_BY_NOCYCLE(n.pos, level, rownum) = 0
27 SELECT name, level, salary
28 FROM n
29 ORDER BY pos;
NAME LEVEL SALARY
---------- ----------- -----------
Goyal 1 80000.00
Henry 2 51000.00
Shoeman 3 33000.00
Smith 3 34000.00
O'Neil 336000.00
Urbassek 4 95000.00
Mills 5 70000.00
Monroe 6 50000.00
Jones 7 30000.00
Hall 7 35000.00
Lindsay 7 38000.00
Kim 7 40000.00
Aaron 6 54000.00
Zander 2 52000.00
Barnes 3 41000.00
McKeough 3 42000.00
Scott 2 53000.00
17 record(s) selected
您可以看到,‘Urbassek’已经被添加到输出中,此外输出还包括‘Mills’的所有属下。但是 ‘Goyal’没有再次添加进来。这样当然很好,但是如何发现循环的所在呢?
CONNECT_BY_ISCYCLE
为了“标出”递归中的循环,Oracle 提供了另一个伪列,即 CONNECT_BY_ISCYCLE。如果当前行是循环的一部分,则这个列返回 1,否则返回 0。
1 SELECT name, level,
2 CONNECT_BY_ISCYCLE AS cycle
3 FROM emp
4 START WITH name = 'Goyal'
5 CONNECT BY NOCYCLE PRIOR empid = mgrid
为了将该特性映射到 DB2,我将再次引入一个 UDF。CONNECT_BY_ISCYCLE() 用于检测循环,就像 CONNECT_BY_NOCYCLE() 做的那样。但是,当 CONNECT_BY_ISCYCLE() 检测到一个循环时,它还将给定的路径与另一个路径进行比较。如果两个路径在循环中重叠,则返回 1,否则返回 0。下面是这个 UDF 的声明:
1 CREATE FUNCTION CONNECT_BY_ISCYCLE
2 (POS VARCHAR(256) FOR BIT DATA,
3 LEVELPOS INTEGER,
4 NPLUS1 BIGINT,
5 POSANCESTOR VARCHAR(256) FOR BIT DATA,
6 LEVELANCESTOR INTEGER)
7 RETURNS SMALLINT
8 SPECIFIC CONNECT_BY_ISCYCLE
9 EXTERNAL NAME 'connect_by!connect_by_iscycle'
10 NOT FENCED RETURNS NULL ON NULL INPUT
11 DETERMINISTIC NO SQL NO EXTERNAL ACTION
12 LANGUAGE C PARAMETER STYLE SQL ALLOW PARALLEL;
为达到目的,这个新查询必须:
返回递归中的所有行。
加入每个行的子行,以便进行比较。
驱动每个子行的递归步骤,以检测那一步是否会导致循环。
最后需要一个三路(three-way)连接:递归输出上的自连接,和对数字编号的源的引用,类似于在原先递归中所做的那样。这样做有一个优点:它足以发现将引入递归的任何子行。这里没有必要返回所有子行,实际上这样做反而有害,因为我们不想返回重复的行。注意,通过一点儿小小的变动,可以计算出一个给定行参与了多少个循环。这个谜就让有兴趣的读者自己去解开。
1 WITH source(empid, name, salary, mgrid, rownum) AS
2 (SELECT empid, name, salary, mgrid,
3 ROW_NUMBER() OVER(ORDER BY salary)
4 FROM emp),
5 n(empid, name, mgrid, level, pos) AS
6 (SELECT empid, name, mgrid, 1,
7 CONNECT_BY_POS('', 0, rownum)
8 FROM source
9 WHERE name = 'Goyal'
10 UNION ALL
11 SELECT nplus1.empid,
12 nplus1.name,
13 nplus1.mgrid,
14 level + 1,
15 CONNECT_BY_POS(n.pos, level, rownum)
16 FROM source AS nplus1, n
17 WHERE n.empid = nplus1.mgrid
18 AND CONNECT_BY_NOCYCLE(n.pos, level, rownum) = 0),
19 cycles(name, level, pos, iscycle) AS
20 (SELECT name, level, pos,
21 COALESCE((SELECT 1 AS iscycle
22 FROM n
23 LEFT OUTER JOIN source
24 ON n.mgrid = source.empid
25 WHERE CONNECT_BY_ISCYCLE(n.pos,
26 n.level,
27 source.rownum,
28 ancestor.pos,
29 ancestor.level) = 1
30 FETCH FIRST ROW ONLY), 0) AS iscycle
31 FROM n AS ancestor)
32 SELECT name, level, iscycle
33 FROM cycles
34 ORDER BY pos;
NAME LEVEL ISCYCLE
---------- ----------- -----------
Goyal 1 1
Henry 2 1
Shoeman 3 0
Smith 3 0
O'Neil 3 1
Urbassek 4 1
Mills 5 1
Monroe 6 0
Jones 7 0
Hall 7 0
Lindsay 7 0
Kim 7 0
Aaron 6 0
Zander 2 0
Barnes 3 0
McKeough 3 0
Scott 2 0
17 record(s) selected
这只是一小部分的工作,但至少现在已经获得一定成果了。像所有美好的故事一样,现在该添加一个好莱坞式的结局,让一切看上去是那么美妙。
CONNECT_BY_ISLEAF
与 CONNECT_BY_ISCYCLE 相比,CONNECT_BY_ISLEAF 更轻量一些。这个伪列只是当一个给定行在递归中是叶子的时候返回 1。换句话说:该行不会产生任何其他的行。在这个例子中,叶子指不是经理的雇员。
1 SELECT name, level,
2 CONNECT_BY_ISLEAF AS isleaf
3 FROM emp
4 START WITH name = 'Goyal'
5 CONNECT BY PRIOR empid = mgrid
实际上,这里只需要剔除之前的大部分相加。为增加可读性,我们重新开始,‘Urbassek’同样还是他自己的上司。还应注意,我去掉了前面的 NOCYCLE 选项,以便把注意力放在现在关注的问题上。毕竟,没有必要停留在过去,尤其是在过去的知识已经掌握的时候。现在,这个查询几乎没有多余的部分。
1 UPDATE emp SET mgrid = NULL WHERE name = 'Urbassek';
2 WITH n(empid, name) AS
3 (SELECT empid, name
4 FROM emp
5 WHERE name = 'Goyal'
6 UNION ALL
7 SELECT nplus1.empid, nplus1.name
8 FROM emp as nplus1, n
9 WHERE n.empid = nplus1.mgrid)
10 SELECT name,
11 COALESCE((SELECT 0 FROM emp
12 WHERE n.empid = emp.mgrid
13 FETCH FIRST ROW ONLY), 1) AS isleaf
11 FROM n;
NAME ISLEAF
---------- -----------
Goyal 0
Zander 0
Henry 0
Scott 1
McKeough 1
Barnes 1
O'Neil 1
Smith 1
Shoeman 1
9 record(s) selected
这的确不难。除非 Oracle 引入了我不知道的其他伪列或关键字,否则 Oracle 所有的递归特性现在都被映射到 DB2 UDB for Linux、UNIX 和 Windows。
结束语
在本文中,我提供了从 Oracle 型 CONNECT BY 递归查询语法到 DB2 中遵从标准的使用 UNION ALL 的 递归公共表表达式 的通用映射。所有映射都运行得很好,并且我展示了 DB2 的递归特性至少是可以表达的。
虽然 Oracle 语法要简练一些,因为它为各种常见的语义提供了关键字,但是这也意味着它的表达能力更弱,因为如果不改变 DBMS,就很难添加新的语义。
作为试图将应用程序从 Oracle 移植到 DB2 的 ISV 或终端用户,现在您不用太担心这一点了。您现在只需知道如何从 Oracle 翻译到 DB2。本文的主要目的就是向您展示这一点。当您对 SQL 标准语法感到得心应手的时候,我相信您将从 DB2 的表达能力中发现价值,虽然这意味着要多写几行代码。
后边增加一点自己的经验
CREATE TABLE "DB2ADMIN"."FIT_TC"
("CUST_ID" DECIMAL(17, 0),
"TCNAME" VARCHAR(20),
"PACKNAME" VARCHAR(20),
"FITADD" VARCHAR(100),
"ADDFEE" INTEGER,
"FITLOS" VARCHAR(100),
"LOSFEE" INTEGER
)
select * from "DB2ADMIN"."FIT_TC";
1 '49元包180' '必选包1' '34元包2元' '-1' '' '-1'
1 '49元包180' '可选包3' '' '-1' '' '-1'
1 '49元包180' '可选包2' '' '-1' '' '-1'
1 '49元包180' '可选包1' '35元包80元' 10 '' '-1'
1 '酷灵通' '必选包1' '' '-1' '' '-1'
1 '酷灵通' '可选包1' '20元包100元' '-1' '' '-1'
1 '酷灵通' '必选包1' '' '-1' '' '-1'
with
tt as (
select row_number() over (partition by TCNAME order by TCNAME) as parent,
row_number() over (partition by TCNAME order by TCNAME) as child, TCNAME,"PACKNAME"||"FITADD" as dw from "DB2ADMIN"."FIT_TC" where FITADD <>''
),
t2 (parent, child,TCNAME, dw) as (
select parent, child,TCNAME, cast(dw as varchar(200)) from tt
where parent=1 and child=1
union all
select t2.child, t2.child+1, t2.TCNAME,cast(rtrim(t2.dw) || ',' || rtrim(tt.dw) as varchar(200))
from t2, tt where t2.child=tt.parent-1 and t2.TCNAME=tt.TCNAME)
select dw, child,TCNAME from t2
where t2.child=(select max(child) from tt where t2.TCNAME=tt.TCNAME)
;
'可选包120元包100元' 1 '酷灵通'
'必选包134元包2元,可选包135元包80元' 2 '49元包180'
myfriend2010 发表于:2007.08.13 14:46 ::分类: (db2 ) ::阅读:(1211次) ::评论 (0)
===========================================================
DB2查看存储过程里SQL语句的执行情况
===========================================================
DB2查看存储过程里SQL语句的执行情况
动态SQL可以用snapshot查看,存储过程里SQL语句的执行情况用event monitor查看。
但是event monitor没有记录SQL语句,而是记录了package id和Section id。
根据package id和Section id再查询系统表就可以得到原始的SQL语句。
例子如下:
(1)创建存储过程
create procedure sales_status
(in quota integer)
dynamic result sets 2
language sql
begin
declare SQLSTATE char(5);
declare rs cursor with return for
select sales_person, sum(sales) as total_sales
from sales
group by sales_person
having sum(sales) > quota;
open rs;
insert into tt1 values (1),(2),(3),(4),(5);
end
@
(2)创建event monitor,并捕获statement信息
db2 create event monitor ev2 for statements write to file 'D: mp'
db2 set event monitor ev2 state 1
db2 "call sales_status(10)"
db2 FLUSH EVENT MONITOR ev2
db2evmon -db sample -evm ev2 > 1.out
(3)查看输出文件
在call sales_status(10)语句后面,可以找到
8) Statement Event ...
Appl Handle: 7
Appl Id: *LOCAL.DB2.070809034142
Appl Seq number: 00053
Record is the result of a flush: FALSE
-------------------------------------------
Type : Static
Operation: Execute
Section : 2
Creator : DB2ADMIN
Package : P2323139
Consistency Token : oAfgMJIX
Package Version ID :
Cursor :
Cursor was blocking: FALSE
-------------------------------------------
Start Time: 2007-08-09 12:33:22.394140
Stop Time: 2007-08-09 12:33:22.394599
Exec Time: 0.000459 seconds
Number of Agents created: 1
User CPU: 0.000000 seconds
System CPU: 0.000000 seconds
Fetch Count: 0
Sorts: 0
Total sort time: 0
Sort overflows: 0
Rows read: 1
Rows written: 5
...
10) Statement Event ...
Appl Handle: 7
Appl Id: *LOCAL.DB2.070809034142
Appl Seq number: 00053
Record is the result of a flush: FALSE
-------------------------------------------
Type : Static
Operation: Close
Section : 1
Creator : DB2ADMIN
Package : P2323139
Consistency Token : oAfgMJIX
Package Version ID :
Cursor : RS
Cursor was blocking: TRUE
-------------------------------------------
Start Time: 2007-08-09 12:33:22.390159
Stop Time: 2007-08-09 12:33:22.398984
Exec Time: 0.008825 seconds
Number of Agents created: 1
User CPU: 0.000000 seconds
System CPU: 0.000000 seconds
Fetch Count: 3
Sorts: 1
Total sort time: 0
Sort overflows: 0
Rows read: 45
Rows written: 0
...
看到Package=P2323139, Section=1的SQL有 Rows read: 45
看到Package=P2323139, Section=2的SQL有 Rows read: 1, Rows written: 5
(4)查询系统表,就可以看到原始的SQL语句了
select s.STMTNO, s.SECTNO, s.TEXT
from SYSCAT.STATEMENTS s
where s.PKGNAME='P2323139' ;
STMTNO SECTNO TEXT ----------- ------ -------
8 1 DECLARE RS cursor with return for select SALES_PERSON, SUM(SALES) as TOTAL_SALES from SALES group by SALES_PERSON having SUM(SALES) > :HV00008 :HI00008
17 2 insert into TT1 values (1),(2),(3),(4),(5)
myfriend2010 发表于:2007.08.11 12:58 ::分类: (db2 ) ::阅读:(1295次) ::评论 (0)
===========================================================
DB2 的命令行处理器和脚本编写-转
===========================================================
何时使用 DB2 命令行处理器
IBM DB2 命令行处理器听起来没什么特别之处,但实际上它是 DB2 的接口,它最佳地体现了 DB2 的威力,以及 DB2 的简单性和通用性。命令行并不可爱(实际上,Windows 上的 DB2 曾得到一个“强大但是不可爱”的名声。那是 DB2 在 NT 上初次发布的时候,当时还没有 Control Center 可用)。命令行使我们想起了 UNIX 上的 Telnet,还有 1981 年开始使用的 DOS 命令。但是,如果您的 SQL 命令够强大—— 或者您想通过输入一个快速命令来验证 DB2 的安装情况——那么命令行是理想的,而且通常比通过像 PowerBuilder 或者 Access 这样的前端提交请求要来得快。CLP 是通往每一个 DB2 编程接口的直接路径。它使得任何可以程式化地调用的东西能够通过接口来调用——或者在一个简单的脚本(就像我们曾在 DOS 中编写过的 .BAT 文件)中调用。像 MVS 上的 SPUFI、VM 上的 ISQL 以及 VSE 上的 SQLDBSU 这些类似的工具都十分耐用,这使得我们深信 CLP 必定可以使用很长一段时间。
本文将向您展示如何使用命令行处理器(简称 CLP)来为您带来好处。如果对某些工作原理还不够明了的话,可以参考手册(DB2 Command Reference),这个手册用一整章介绍 CLP 的使用。
验证安装情况和判定问题所在
当我第一次在 OS/2 上安装 DB2 时(在此一年前 DB2 已经可以在 NT 上使用了),我已经在很多其他的操作系统(DOS,VM,VSE,MVS?,AS/400?)上使用过 SQL Database 管理器了。成功地安装完之后,我开始阅读 about 信息,这时我被“cataloging nodes and databases(编目节点和数据库)”这件事给弄糊涂了。catalog 这个词与过去惹人喜爱的 SYSCAT 和 SYSIBM 目录相比有着动词化的意味。有时候,我会对着 DB2 大声埋怨:“我不想编目任何东西,我只是想通过运行一个 SELECT 语句来确保我正确地安装了 DB2。”几个小时之后,我冷静下来,了解到只有创建了一个数据库之后 DB2 才会有数据库目录;您不需要在本地机器上将节点和数据库编目——只有在一个连接到服务器的客户机上时才需要编目。创建样本数据库非常容易——运行 db2sampl 就可以了。在验证安装情况时,命令行处理器 正是我所需要的工具,这时可以运行:
DB2 SELECT COUNT(*) FROM SYSCAT.TABLES
在 UNIX 和 OS/2 上,您只需使用一个常见的操作系统提示符,并在任何 DB2 命令或者 SQL 语句前面加上"DB2" 。在 Windows 上,事情要麻烦一些,这在后面会解释,不过您可以通过输入 DB2CMD 来创建一个适合 DB2 命令、SQL 和 操作系统命令(例如 dir 和 ren)的提示符。您甚至可以混合使用 SQL、DB2 命令和操作系统参数,例如用 |more 来滚动屏幕,用大于号(>)来向文件输送内容:
DB2 select * from employee>c:tmpemp.out |more
注意:对于那些对 DB2 和操作系统都有意义的符号,比如 Windows 上的大于号(>),操作系统会最先给予解释。SELECT * FROM EMPLOYEE WHERE SALARY > 9999 语句会将错误消息输送到一个名为 9999 的文件。要划清这些特殊符号的界限;您应该输入:
SELECT * FROM EMPLOYEE WHERE SALARY ">" 9999
虽然您的用户可能永远不会使用 CLP 来访问他们的数据,对于 DBA 或者应用程序的编程人员来说, CLP 在工具箱中是最基本的工具:它就像是在所有场合都适用的燕尾服。对于关键应用来说,往往数据库是关键之处,如果某个地方出错的话,问题的判定会比较困难。在大型主机/微型计算机领域中,问题可能出在应用程序中,也可能出在软件系统中,但是问题总可以界定在一台计算机以内。而在客户机-服务器领域中,问题可能隐藏在客户机系统软件中(操作系统,数据库客户机,或者通信协议),可能隐藏在客户机应用程序代码中,可能隐藏在服务器应用程序代码中(如果您正在使用触发器,用户定义的函数,或者存储过程),还可能隐藏在服务器上的其他地方。3-层应用包括 Web 服务器、浏览器和第三层的硬件。CLP 在这里有什么用呢?答案就是,它可以将应用程序从这一架构中分割出来。如果您发现一个问题,那么可以将故障请求翻译成简单的 SQL,然后从以下机器上的 CLP 运行该 SQL:
服务器
客户机
Web 服务器
根据哪里没问题,哪里有故障,您就可以判定是 DB2 本身有故障(很可能在通过 CLP 提交 SQL的服务器上出故障的形式与客户机应用程序出故障的形式是一样的),还是问题出在通信上(请求在 客户机出了故障,而在服务器上没有问题),或者问题是出在 Web 服务器上(问题只出在最远的地方)。
帮助
CLP 也是一个到 DB2 帮助的接口。如果您收到一条消息,而又不知道应该采取怎样的适当步骤,那么在 CLP 中输入:
C:SQLLIB>db2 ? sql0100 |more
FETCH、UPDATE 或 DELETE 语句的输出中应该有 SQL0100W No 这样一行;否则查询的结果就是一个空表。
解释:下面的情况中有一种情况为真:
No 这一行符合在 UPDATE 或 DELETE 语句中指定的搜索条件。
SELECT 语句的结果是一个空表。
当游标定位到了结果表的最后一行记录时,会执行一条 FETCH 语句。
在 INSERT 语句中使用的 SELECT 的结果为空。
这里没有检索、更新或者删除数据。
用户响应:不需要动作。处理可以继续。
sqlcode: +100
sqlstate: 02000
您可以看看在 Messages 手册中的相同的帮助,包括为避开问题而建议采用并且可以采用的动作。CLP 还将提供用于 DB2 命令的语法(作为例子,可以试试 DB2 ? backup)。
脚本编写
您可以使用 CLP 运行脚本,任何可以以常规操作处理的方式运行的实用程序(例如每夜运行的 LOAD、RUNSTATS 或者 BACKUP 命令),都可以是一个 CLP 脚本。CLP 的一些选项可以指定输入文件(-f),一个用于消息的输出文件(-z),是否能够回送关于什么要在屏幕上运行的信息(-v),是否能够设置一个语句终止符(-t),如果设置了这个选项,脚本就可以包含多个 DB2 命令 和 SQL 语句。通常我会这样运行脚本:DB2 -tvf filename.ddl -t,后面加上默认的终止符(;),-v 选项允许回送文件的内容到屏幕(这样就可以检查我告诉了 DB2 要做些什么),-f 选项告诉 CLP 使用一个输入文件。通过 DB2 ? options 可以得到关于所有选项的帮助:
C:SQLLIB>db2 ? options
db2 [option ...] [db2-command | sql-statement |
[? [phrase | message | sqlstate | class-code]]]
option: -a, -c, -e{c|s}, -finfile, -lhistfile, -n, -o, -p, -rreport, -s, -t,
-td;, -v, -w, -x, -zoutputfile.
选项 描述 默认设置
-a 显示 SQLCA OFF
-c 自动提交 ON
-e 显示 SQLCODE/SQLSTATE OFF
-f 从输入文件读内容 OFF
-l 历史文件中的日志记录命令 OFF
-n 删除换行字符 OFF
-o 显示输出 ON
-p 显示 db2 交互性命令 ON
-r 将输出报告保存到文件 OFF
-s 出现命令错误时停止执行 OFF
-t 设置语句终止符 OFF
-v 回送当前命令 OFF
-w 显示 FETCH/SELECT 警告消息 ON
-x 省略列标题的打印 OFF
-z 将所有输出保存到输出文件 OFF
在 DB2 Control Center 中的脚本中心那里提供了更加高级的脚本编写,包括时间安排(scheduling),并且可以使用日志来查看发生过什么事情。在原型(prototyping)模式下,CLP 只是一种启动程序的快速方式。注意上述输出中的 -x 选项:我们添加了这个能力,以便可以在 DB2 v7 的 fixpak 1 中不输出列标题。如果客户要求输出列标题,他们可能是关心列标题,因为他们希望输出好看一些(或者要将输出作为另一个程序的输入)。对于我来说,这意味着人们现在 将 CLP 不仅仅用于原型。
编写 DDL 脚本
如果对于每个产品和开发数据库您都遵循这个简单的规则,那么您将对我感激不尽:您可以将所有用于创建或更改数据库对象的 DDL 保存在一个文件中。更令人振奋的是,可以用一个编辑器将 DDL 输入到一个文件中,然后通过提交这个文件给 CLP 来运行这个文件。如果您不采纳上述建议,那么用于在一个数据库中重新创建视图、检查约束、SQL 过程以及触发器的语句的文本也可以这样获取:
select text from syscat.views
select text,tabname from syscat.checks
select text from syscat.procedures
select text from syscat.triggers
您也可以通过使用 -e 选项(或者对于特定的表使用 -t 选项和 -e 选项)运行 db2look 来收集将大部分的这些信息。DB2 Command Reference 为 db2look 编写了文档。不过,预先将这样的信息保存在一个用于提交 DDL 的文件中,比在一个依赖于另一个数据库的模式的新项目中途匆忙地重新创建它要更显得专业些。
原型
您不必将所有的 DML(SELECT,INSERT,UPDATE,DELETE)保存在一个文件中。毕竟,这些 DML 将会处在您所编写的程序中,并且可以通过使用像监视器和 DB2 Query Patroller 这样的 DB2 工具动态地捕获。不过,在将 SQL 输入到一个应用程序之前,您可以先使用 CLP 对其进行原型试验,看看自己是否对结果满意(并且可以检查语法)。使用 -a 选项来查看 SQL Communications Area (SQLCA)。例如,如果语句没有对任何东西进行更新,或许在语法上这条语句是对的,但是没有任何记录行符合更新条件是由于采用了限制性非常强的 where 子句造成的。在这种情况下,您会得到一个值为 100 的 SQLCODE:
C:sqllib>db2 -a update employee set salary=5 where salary "<" -5
SQLCA Information
sqlcaid : SQLCA sqlcabc: 136 sqlcode: 100 sqlerrml: 0
sqlerrmc:
sqlerrp : SQLRIEXU
sqlerrd : (1) -31743 (2) 1 (3) 0
(4) 0 (5) 0 (6) 0
sqlwarn : (1) (2) (3) (4) (5) (6)
(7) (8) (9) (10) (11)
sqlstate: 02000
何时使用 DB2 Command Center
DB2 Command Center 是一个图形化的命令行(对于那些偏爱形而上学逻辑的读者来说,这是一种似是而非的说法,而不是简单的自相矛盾)。任何命令或者 SQL 语句,甚至是操作系统命令,都可以通过 Command Center 提交。虽然 CLP 直接调用 DB2 编程接口,但是 Command Center 要经由 DB2 的 Call Level Interface (即 CLI,这基本上是 ODBC 的一个超集)。这意味着当有故障发生时,您可能会得到一条 CLI 错误消息,而不是一个 SQLCODE。这还意味着如果您怀疑某个地方有 CLI bug,您可以试着通过 CLP 提交 SQL 到 Command Center。如果在 CLP 部分是成功的,而在 Command Center 部分是失败的,那么问题显然就出在 CLI 那一部分。在 DB2 中,这一点很重要,因为对 DB2 的所有 ODBC、Java、JDBC 和 SQLJ 访问都要经由 CLI。由于这个原因,Command Center 是用 Java 编写的。比起 CLP,Command Center 有以下优点:
可以在操作系统命令提示符的边界外部水平地和垂直地滚动:这包括针对您提交的命令和 SELECT 语句的结果的独立选项卡(或页面)。
对剪切和粘贴的完全剪贴板支持。
可以访问 Script Center (在 Control Center 中)和 Visual Explain (以便图形化地显示对 SQL 语句的访问计划——这是查看哪些索引得到使用的最佳方式)。可以高亮显示 SQL,通过点击 Access Plan 可以可视化地解释一条 SQL 语句。
能够更容易地通过用鼠标拓展或者收缩可见区域来显示(或隐藏)多个列。
提供了一个下拉式的菜单,用于检索和编辑先前提交的命令(而不是依赖于操作系统的命令,比如 Windows 和 OS/2 操作系统中的向上箭头和向下箭头)。
在会话中提交的命令和结果的更好的历史记录——这有利于将交互式的体验转变成脚本(或者取得所有 CREATE TABLE 语句并将其存入一个文件中)。
支持所有的 CLP 选项(例如显示 SQLCA)。
因为接口各异,其中有些微妙之处需要知道。接下来的语句在 Command Center 中和在 CLP 中将得到迥然不同的结果:
create user temporary tablespace usetemp
pagesize 4k managed by system using ('C:usetemp');
declare global temporary table t1 (col1 int) not logged;
select count(*) from session.t1;
这与 DB2 对用于用户声明的临时表的会话所有权的处理方式有关。对于在 Command Center 中启动的每个 Java 进程,所有权并不是一成不变的。上面的 select count(*) 语句在 CLP 中将获得成功,但是在 Command Center 中却不能找到 session.t1。
CLP 设计
DB2 Command Reference 在第 2 章中解释了 CLP 设计。CLP 设计由两个过程组成:
一个前端进程(或者是在 Windows 和 OS/2 上的线程),用于处理与操作系统命令提示符的通信。
一个后端进程,用于处理与数据库的通信。这确保了在您连接到 DB2 之后,如果用 Control-C 或 Control-Break 中止来自一个大型选择(例如 SELECT * FROM SYSCAT.TABLES)的输出,那么输出会顺利地被中止,而不会断开到 DB2 的连接。
命令窗口与 Windows 上的 CLP 的比较
那么,为什么 DB2 要求您用 Windows 上的 DB2CMD.EXE(或者用 DB2 Command Window,或者用 DB2 Command Line Processor,又或者用开始菜单)启动一个 CLP 呢?在 UNIX 和 OS/2 上,前端进程和后端进程之间的链接非常简单:如果父进程死亡,则其所有子进程都将被操作系统终止。在 Windows 上,父线程在死亡时并不会终止其子线程。这里我们不去冒险产生 Windows 上的大量 phantom 线程,而是决定用一个 cookie 来为 Windows 上的 CLP 链接前端线程和后端线程。这要求 CLP 要通过 DB2CMD.EXE 来启动。这样做确保了如果杀死了父线程,那么子线程也不会保留下来,从而避免了资源的浪费。不必担心叫做"DB2 Command Processor"的特定选项。它会创建像这样的一个特殊的提示符:
db2 =>
这样,您就不必在所有发送到 DB2 的指令之前都加上 DB2。另一方面,现在您必须在操作系统命令之前加上一个惊叹号(!),就像在 Command Center 中一样。
何时不使用命令行处理器
对于用于检查语法和您希望用户看到的结果的原型 SQL 来说,CLP 很有用。但是,由于 CLP 是如此的多用,能够提供到每条 DB2 SQL 语句、命令以及编程接口的访问途径,所以通常来讲,比起动态 SQL(例如那些通过 ODBC 提供的动态 SQL)来 CLP 会产生更大的开销。为了对性能进行原型试验,可以使用 db2batch,这在 DB2 Command Reference 中有文档说明。
一个需要避免的典型例子(或者说不值得拷贝的例子)
下面是一个简单的例子,其中充斥着许多坏的编程习惯,这个例子展示了为什么 CLP 对于应用程序逻辑来说不是很好。对于简单的脚本编写,下面的例子可以更加强大,甚至可以处理一些出错的情况,如果它是用 PERL 编写的话。不过,对于我来说,编写和做一些有用的工作是十分有趣的。先决条件:
已经创建了样本数据库。
从 DIR 命令得到的输出与我测试时所在的系统(带有 ServicePak 5 的 NT 4.0,以及 Windows 2000)相匹配。
您正处在 Windows 上的一个 DB2 Command Window 中。
这个例子做些什么
是不是曾经碰到过用完了磁盘空间的情况。下面的例子捕获在 C: 上的一个递归的目录清单的输出,为每个大小为 1 MB 或大于 1 MB 的文件导入一行,并列出 C: 盘中 10 个最大的文件。不要删除 PAGEFILE.SYS!只能删除那些明确知道是垃圾的文件(例如 C:TEMP 中大型的 .PDF 文件)。 这个例子中有什么好的地方?
它可以帮助我清理我的硬盘。
它可以在两种系统上工作(我成功地完成了系统测试并发布了它!)
这个例子有什么不好的地方?
在开发者园地即将发布的一个 500 页的自述文件(readme)中,您将看到对这个例子的缺点的文档说明。
仔细研究这个例子:
(我是这样运行的:db2 -tvf dirpub)
!dir c:*.* /s>dir.out;
connect to sample;
create table dirlist (size_in_mb int not null, name char(21) not null
CONSTRAINT CHECKBYTES CHECK (name not like ' bytes%'));
import from c:dir.out of asc method l (28 30, 40 60)
commitcount 1000 replace into dirlist;
select * from dirlist order by size_in_mb desc
fetch first 10 rows only;
第 1 行将 C: 上所有文件的列表发送到 dir.out。
第 2 行连接到样本数据库。
第 3 行创建一个带有两列的表:一列是以 MB 为单位的每个文件的大小,一列是每个文件的文件名中的前 21 个字符。既然在 Windows 告诉您关于目录的信息时会显示短语"bytes",那么我们使用一个检查约束来消除这些不需要的行。
第 4 行将文件 dir.out 中的行导入表 dirlist 中。我们假设以 MB 为单位的文件大小是从第 28 列到第 30 列的一个整数,并将从第 40 列到第 60 列的内容拿来作为文件名。我们每 1000 行提交一次,并且替换 dirlist 的内容,以防多次运行这种提交。
第 5 行获得 10 个最大的文件的文件名。
所以,用 5 行代码,我们就可以清理一个硬盘分区(或者至少查看出哪些文件占用了所有的空间)。处理出错情况,允许搜索其他驱动器,以及删除输出中的系统文件,这些功能能够轻松地将这个小小的程序扩展成数百行,我不 想编写这么多的代码。毕竟,CLP 的精神就是“快而脏(quick and dirty)”,即花费的精力中有 20% 满足了 80% 的需求。如果您小心地应用这个 80/20 法则,令用户感到满意,您就总能接到更多的项目。
myfriend2010 发表于:2007.08.09 16:26 ::分类: (db2 ) ::阅读:(883次) ::评论 (0)
===========================================================
DB2函数大全 --转贴
===========================================================
DB2函数大全
函数名 函数解释 函数举例
AVG()  返回一组数值的平均值.  SELECTAVG(SALARY)FROMBSEMPMS;
CORR(),CORRELATION()  返回一对数值的关系系数.  SELECTCORRELATION(SALARY,BONUS)FROMBSEMPMS;
COUNT()  返回一组行或值的个数.  SELECTCOUNT(*)FROMBSEMPMS;
COVAR(),COVARIANCE()  返回一对数值的协方差.  SELECTCOVAR(SALARY,BONUS)FROMBSEMPMS;
MAX()  返回一组数值中的最大值.  SELECTMAX(SALARY)FROMBSEMPMS;
MIN()  返回一组数值中的最小值.  SELECTMIN(SALARY)FROMBSEMPMS;
STDDEV()  返回一组数值的标准偏差.  SELECTSTDDEV(SALARY)FROMBSEMPMS;
SUM()  返回一组数据的和.  SELECTSUM(SALARY)FROMBSEMPMS;
VAR(),VARIANCE()  返回一组数值的方差.  SELECTVARIANCE(SALARY)FROMBSEMPMS;
ABS(),ABSVAL()  返回参数的绝对值.  SELECTABS(-3.4)FROMBSEMPMS;
ACOS()  返回参数的反余弦值.  SELECTACOS(0.9)FROMBSEMPMS;
ASCII()  返回整数参数最左边的字符的ASCII码.  SELECTASCII('R')FROMBSEMPMS;
ASIN()  返回用弧度表示的角度的参数的反正弦函数.  SELECTASIN(0.9)FROMBSEMPMS;
ATAN()  返回参数的反正切值,该参数用弧度表示的角度的参数.  SELECTATAN(0.9)FROMBSEMPMS;
ATAN2()  返回用弧度表示的角度的X和Y坐标的反正切值.  SELECTATAN2(0.5,0.9)FROMBSEMPMS;
BIGINT()  返回整型常量中的数字或字符串的64位整数表示.  SELECTBIGINT(EMP_NO)FROMBSEMPMS;
CEILING() OR CEIL()  返回比参数大或等于参数的最小的整数值.  SELECTCEILING(3.56)FROMBSEMPMS;  SELECTCEIL(4.67)FROMBSEMPMS;
CHAR()  返回日期时间型,字符串,整数,十进制或双精度浮点数的字符串表示.  SELECTCHAR(SALARY,',')FROMBSEMPMS;
CHR()  返回具有由参数指定的ASCII码的字符.  SELECTCHAR(167)FROMBSEMPMS;
CONCAT()  返回两个字符串的连接.  SELECTCONCAT(EMP_NO,EMP_NAM)FROMBSEMPMS;
YEAR()  返回数值的年部分.  SELECTYEAR('2003/01/02')FROMBSEMPMS;
VARCHAR()  返回字符串,日期型,图形串的可变长度的字符串表示.  SELECTVARCHAR(EMP_NAM,50)FROMBSEMPMS;
UCASE() OR UPPER()  返回字符串的大写.  SELECT UCASE(EMP_NAM)FROMBSEMPMS;  SELECTUPPER(EMP_NO)FROMBSEMPMS;
TRUNCATE() OR TRUNC()  从表达式小数点右边的位置开始截断并返回该数值.  SELECTTRUNCATE(345.6789,2)FROMBSEMPMS;
TIME()  返回一个数值中的时间.  SELECTTIME('2001-03-19.12.30.123456')FROMBSEMPMS;
SUBSTR(EXP1,EXP2)  返回EXP1串自EXP2处开始的子串.  SELECT SUBSTR('CDNJFDJFJD',5)FROM BSEMPMS;  SELECT SUBSTR('CDNJFDJFJD',5,2)FROM BSEMPMS;
SQRT()  返回该参数的平方根.  SELECTSQRT(36)FROMBSEMPMS;
SPACE()  返回由参数指定的长度,包含空格在内的字符串.  SELECTSPACE(10)FROMBSEMPMS;
SECOND()  返回一个数值的秒部分.  SELECTSECOND('18:34:32')FROMBSEMPMS;
RTRIM()  删除字符串尾部的空格.  SELECTRTRIM('COMMENT')FROMBSEMPMS;
ROUND(EXP1,EXP2)  返回EXP1小数点右边的第EXP2位置处开始的四舍五入值.  SELECTROUND(2345.6789,2)FROMBSEMPMS
REPLACE(EXP1,EXP2,EXP3)  用EXP3替代EXP1中所有的EXP2  SELECTCHAR(REPLACE('ROMANDD','NDD','CCB'),10)FROMBSEMPMS;
REPEAT(EXP1,EXP2)  返回EXP1重复EXP2次后的字符串.  SELECTCHAR(REPEAT('REPEAT',3),21)FROMBSEMPMS;
REAL()  返回一个数值的单精度浮点数表示.  SELECTREAL(10)FROMBSEMPMS;
RAND()  返回0和1之间的随机浮点数.  SELECTRAND()FROMBSEMPMS;
POWER(EXP1,EXP2)  返回EXP1的EXP2次幂.  SELECTPOWER(2,5)FROMBSEMPMS;
POSSTR(EXP1,EXP2)  返回EXP2在EXP1中的位置.  SELECT('ABCDEFGH','D')FROMBSEMPMS;
NULLIF(EXP1,EXP2)  如果EXP1=EXP2,则为NULL,否则为EXP1
NODENUMBER()  返回行的分区号.  SELECTNODENUMBER(EMP_NO)FROMBSEMPMS;
MONTH()  返回一个数值的月部分.  SELECTMONTH('2003/10/20')FROMBSEMPMS;
MOD(EXP1,EXP2)  返回EXP1除以EXP2的余数.  SELECTMOD(20,8)FROMBSEMPMS;
MINUTE()  返回一个数值的分钟部分.  SELECTMINUTE('18:34:23')FROMBSEMPMS;
LTRIM()  删除字符串前面的空格.  SELECTLTRIM('CDDD')FROMBSEMPMS;
HOUR()  返回一个数值的小时部分.  SELECTHOUR('18:34:23')FROMBSEMPMS;
DOUBLE()  如果参数是一个数字表达式,返回与其相对应的浮点数,如果参数是字符串表达式,则返回该数的字符串表达式.  SELECTDOUBLE('5678')FROMBSEMPMS;
EXP()  返回参数的指数函数.  SELECTEXP(2)FROMBSEMPMS;
FLOAT()  返回一个数的浮点表示.  SELECTFLOAT(789)FROMBSEMPMS;
FLOOR()  返回小于或等于参数的最大整数.  SLECTFLOOR(88.93)FROMBSEMPMS;
HEX()  返回一个表示为字符串的值的16进制表示.  SELECTHEX(16)FROMBSEMPMS;
myfriend2010 发表于:2007.08.02 15:26 ::分类: (db2 ) ::阅读:(1521次) ::评论 (0)
===========================================================
ORACLE和DB2實現相同功能的做法--转
===========================================================
**********************************************************
ORACLE和DB2實現相同功能的做法,歡迎拍磚...
1
﹗(以下主要以Oracle
8I和DB2 7.X為例)。
1.如何取一表前n筆記錄的Oracle和DB2的寫法
Oracle 可以這樣實現﹕
Select * from user.bsempms where rownum<=n;
DB2 可以這樣實現﹕
Select * from db2admin.bsempms fetch first n rows only;
另外也可以用 row_number() over() 去實現的;
2.如何取得當前日期的Oracle和DB2的寫法
Oracle 可以這樣實現﹕
Select sysdate from dual;
DB2 可以這樣實現﹕
Select current timestamp from sysibm.sysdummy1;
3.如何連接字段的Oracle和DB2的寫法
Oracle 可以這樣實現﹕
Select emp_no||emp_nam from bsempms;
Select concat(emp_no,emp_nam) from bsempms;
DB2 可以這樣實現﹕
Select emp_no||emp_nam from db2admin.bsempms;
select emp_no concat emp_nam from db2admin.bsempms;
4.應該是取當前時間的
Oracle 可以這樣實現﹕
Select sysdate from dual;
DB2 可以這樣實現﹕
Select current timestamp from sysibm.sysdummy1;
5.內連接INNER JOIN的Oracle和DB2的寫法
Oracle可以這樣實現﹕
Select a.* from bsempms a,bsdptms b where a.dpt_no=b.dpt_no;
DB2 可以這樣實現﹕
Select * from db2admin.bsempms inner join db2admin.bsdptms
on db2admin.bsempms.dpt_no=db2admin.bsdptms.dpt_no;
6.外連接的Oracle和DB2的寫法(右外連接,左外連接,完全外連接,組合外連接)
Oracle可以這樣實現﹕
Select a.* from bsempms a,bsdptms b where a.dpt_no=b.dpt_no(+);
Select a.* from bsempms a,bsdptms b wherea.dpt_no(+)=b.dpt_no;
DB2 可以這樣實現﹕
Select * from db2admin.bsempms right outer join db2admin.bsdptms
on db2admin.bsempms.dpt_no=db2admin.bsdptms.dpt_no;
Select * from db2admin.bsempms left outer join db2admin.bsdptms
on db2admin.bsempms.dpt_no=db2admin.bsdptms.dpt_no;
Select * from db2admin.bsempms full outer join db2admin.bsdptms
on db2admin.bsempms.dpt_no=db2admin.bsdptms.dpt_no;
7.如何執行腳本SQL文件的Oracle和DB2的寫法
Oracle 可以這樣實現﹕
SQL>@$PATH/filename.sql;
DB2 可以這樣實現﹕
db2 -tvf $PATH/filename 文件中每行以 ; ?尾
2
1.如何查看數据庫的版本的Oracle和DB2的寫法
Oracle 可以這樣實現﹕
SQL> connectsystem/manager124@test;
已連線.
SQL> select * from v$version;
BANNER
----------------------------------------------------------------
Oracle9i Enterprise Edition Release 9.2.0.1.0 - Production
PL/SQL Release 9.2.0.1.0 - Production
CORE 9.2.0.1.0 Production
TNS for 32-bit Windows: Version 9.2.0.1.0 - Production
NLSRTL Version 9.2.0.1.0 - Production
DB2 可以這樣實現﹕
在命令窗口執行 db2level
D:SQLLIBBIN>db2level
DB210851 Instance "DB2" uses DB2 code release "SQL07020" with level identifier
"03010105" and informational tokens "DB2 v7.1.0.40","n010415" and "WR21254".
2.如何快速清空一個大表的Oracle和DB2的寫法
Oracle 可以這樣實現﹕
SQL>truncate table table_name;
DB2 可以這樣實現﹕
alter table table_name active not logged initially with empty table;
3.如何查看表空間的使用狀況的Oracle和DB2的寫法
Oracle 可以這樣實現﹕
SELECT tablespace_name, max_m, count_blocks free_blk_cnt, sum_free_m,to_char(100*sum_free_m/sum_m, '99.99') || '%' AS
pct_free
FROM ( SELECT tablespace_name,sum(bytes)/1024/1024 AS sum_m FROM dba_data_files GROUP BY tablespace_name),
( SELECT tablespace_name AS fs_ts_name, max(bytes)/1024/1024 AS max_m, count(blocks) AS count_blocks,
sum(bytes/1024/1024) AS sum_free_m FROM dba_free_space GROUP BY tablespace_name )
WHERE tablespace_name = fs_ts_name
DB2 可以這樣實現﹕
list tablespace containers for 你的表空間號 show detail;
4.如何從一時間點取出日期的各部分的常用的Oracle和DB2的寫法
Oracle 可以這樣實現﹕
1>.取時間點的年份的寫法:
SELECT TO_CHAR(SYSDATE,'YYYY') FROM DUAL;
2>.取時間點的月份的寫法:
SELECT TO_CHAR(SYSDATE,'MM') FROM DUAL;
3>.取時間點的日的寫法:
SELECT TO_CHAR(SYSDATE,'DD') FROM DUAL;
4>.取時間點的時的寫法:
SELECT TO_CHAR(SYSDATE,'HH24') FROM DUAL;
5>.取時間點的分的寫法:
SELECT TO_CHAR(SYSDATE,'MI') FROM DUAL;
6>.取時間點的秒的寫法:
SELECT TO_CHAR(SYSDATE,'SS') FROM DUAL;
7>.取時間點的毫秒的寫法(9I以上)
select SUBSTR(systimestamp,20,6) from dual;
8>.取時間點的日期的寫法:
SELECT TRUNC(SYSDATE) FROM DUAL;
9>.取時間點的時間的寫法:
SELECT TO_CHAR(SYSDATE,'HH24:MI:SS') FROM DUAL;
10>.日期,時間形態變為字符形態
SELECT TO_CHAR(SYSDATE) FROM DUAL;
11>.將字符串轉換成日期或時間形態:
SELECT TO_DATE('2003/08/01') FROM DUAL;
12>.返回參數的星期几的寫法:
SELECT TO_CHAR(SYSDATE,'D') FROM DUAL;
13>.返回參數一年中的第几天的寫法:
SELECT TO_CHAR(SYSDATE,'DDD') FROM DUAL;
14>.返回午夜和參數中指定的時間值之間的秒數的寫法:
SELECT TO_CHAR(SYSDATE,'SSSSS') FROM DUAL;
15>.返回參數中一年的第几周的寫法:
SELECT TO_CHAR(SYSDATE,'WW') FROM DUAL;
DB2 可以這樣實現﹕
1>.取時間點的年份的寫法:
SELECT YEAR(current timestamp) FROM SYSIBM.SYSDUMMY1;
2>.取時間點的月份的寫法:
SELECT MONTH(current timestamp) FROM SYSIBM.SYSDUMMY1;
3>.取時間點的日的寫法:
SELECT DAY(current timestamp) FROM SYSIBM.SYSDUMMY1;
4>.取時間點的時的寫法:
SELECT HOUR(current timestamp) FROM SYSIBM.SYSDUMMY1;
5>.取時間點的分的寫法:
SELECT MINUTE(current timestamp) FROM SYSIBM.SYSDUMMY1;
6>.取時間點的秒的寫法:
SELECT SECOND(current timestamp) FROM SYSIBM.SYSDUMMY1;
7>.取時間點的毫秒的寫法:
SELECT MICROSECOND(current timestamp) FROM SYSIBM.SYSDUMMY1;
8>.取時間點的日期的寫法:
SELECT DATE(current timestamp) FROM SYSIBM.SYSDUMMY1;
9>.取時間點的時間的寫法:
SELECT TIME(current timestamp) FROM SYSIBM.SYSDUMMY1;
10>.日期,時間形態變為字符形態:
SELECT char(current date) FROM SYSIBM.SYSDUMMY1;
SELECT char(current time) FROM SYSIBM.SYSDUMMY1;
SELECT char(current date+12 hours) FROM SYSIBM.SYSDUMMY1;
11>.將字符串轉換成日期或時間形態:
SELECT TIMESTAMP('2002-10-20-12.00.00.000000') FROM SYSIBM.SYSDUMMY1;
SELECT TIMESTAMP('2002-10-20 12:00:00') FROM SYSIBM.SYSDUMMY1;
SELECT DATE('2002-10-20') FROM SYSIBM.SYSDUMMY1;
SELECT DATE('10/20/2002') FROM SYSIBM.SYSDUMMY1;
SELECT TIME('12:00:00') FROM SYSIBM.SYSDUMMY1;
SELECT TIME ('12.00.00') FROM SYSIBM.SYSDUMMY1;
12>.返回參數的星期几的寫法:
SELECT DAYNAME(current timestamp) FROM SYSIBM.SYSDUMMY1;
SELECT DAYOFWEEK(current timestamp) FROM SYSIBM.SYSDUMMY1;
SELECT DAYOFWEEK_ISO(current timestamp) FROM SYSIBM.SYSDUMMY1;
13>.返回參數一年中的第几天的寫法:
SELECT DAYOFYEAR(current timestamp) FROM SYSIBM.SYSDUMMY1;
14>.返回午夜和參數中指定的時間值之間的秒數的寫法:
SELECT MIDNIGHT_SECONDS(current timestamp) FORM SYSIBM.SYSDUMMY1;
15>.返回參數中一年的第几周的寫法:
SELECT WEEK(current timestamp) FORM SYSIBM.SYSDUMMY1
3
1.如何查有多少個數据庫實例的Oracle和DB2的寫法
Oracle 可以這樣實現﹕
SQL>SELECT * FROM V$INSTANCE;
DB2 可以這樣實現﹕
在命令窗口執行 db2ilist
2.如何查詢數据庫有多少表的Oracle和DB2的寫法
Oracle 可以這樣實現﹕
SQL>select * from all_tables;
DB2 可以這樣實現﹕
在命令中心執行
select * from syscat.tables;
3.如何知道表鎖的情況的Oracle和DB2的寫法
Oracle 可以這樣實現﹕
SQL>SELECT S.SID SESSION_ID, S.USERNAME, DECODE(LMODE, 0, 'None', 1, 'Null', 2, 'Row-S (SS)', 3, 'Row-X (SX)', 4, 'Share', 5, 'S/Row-X (SSX)', 6, 'Exclusive', TO_CHAR(LMODE)) MODE_HELD, DECODE(REQUEST, 0, 'None', 1, 'Null', 2, 'Row-S (SS)', 3, 'Row-X (SX)', 4, 'Share', 5, 'S/Row-X (SSX)', 6, 'Exclusive', TO_CHAR(REQUEST)) MODE_REQUESTED, O.OWNER||'.'||O.OBJECT_NAME||' ('||O.OBJECT_TYPE||')', S.TYPE LOCK_TYPE, L.ID1 LOCK_ID1, L.ID2 LOCK_ID2 FROM V$LOCK L, SYS.DBA_OBJECTS O, V$SESSION S WHERE L.SID = S.SID AND L.ID1 = O.OBJECT_ID
DB2 可以這樣實現﹕
在你执行你的存储过程之前,执行命令打开锁的监视开光
db2 update monisor switches using lock on ;
然后执行你的存储过程,在执行存储过程期间的时候使用命令
db2 get snapshot for locks on yourdatdabasename ;
就可以看见了你锁情况了
4.如何對鎖住的表進行解鎖的Oracle和DB2的寫法
Oracle 可以這樣實現﹕
SQL>alter system kill session 'sid,service#';
DB2 可以這樣實現﹕
db2 force application all ;
db2 terminate ;
5.測試SQL語句執行所用的時間的Oracle和DB2的寫法
Oracle 可以這樣實現﹕
SQL>set timing on ;
SQL>select * from tablename;
DB2 可以這樣實現﹕
db2batch -d 库名 -f 含有SQL语句的文件名 ;
6. 如何配置Sequence的Oracle和DB2的寫法
Oracle 可以這樣實現﹕
建sequence seq_custid
create sequence seq_custid start 1 incrememt by 1;
建表时:
create table cust
{ cust_id smallint not null,
...}
insert 时:
insert into table cust
values( seq_cust.nextval, ...)
DB2 可以這樣實現﹕
identity字段属性 用法:
create table时
cust_id smallint not null generated always as indentity (start with
1 increment by 1)
insert 时:
insert into table cust (cust_id, ... )
values ( default, ...)
4
1.如何實現分頁顯示的Oracle和DB2的寫法
Oracle 可以這樣實現﹕
SQL>select rownum,* from BSEMPMS where rownum >=5 and rownum <=100;
DB2 可以這樣實現﹕
select * from (select ROW_NUMBER() over() as a, db2admin.bsempms.* from
db2admin.bsempms) as temp where a>=5 and a<=100 ;
2.利用別的表創建表的Oracle和DB2的寫法
Oracle 可以這樣實現﹕
SQL>create table a as select * from b ;
DB2 可以這樣實現﹕
create table a like b ;
3.如何更改用戶密碼的Oracle和DB2的寫法
Oracle 可以這樣實現﹕
SQL>alter user user123 identified by password_new;
DB2 可以這樣實現﹕
connect to dbname user db2admin using oldpassw new newpassw confirm newpassw ;
4.如何增加用戶的Oracle和DB2的寫法
Oracle 可以這樣實現﹕
SQL>create user user123 identified by password_new;
DB2 可以這樣實現﹕
添加用户:
“开始/设置/控制面板/用户”添加一个用户名(例:db2admin)
分配权限:
grant dbadm on database to user 用户名
5.兩個結果集互減的函數的Oracle和DB2的寫法
Oracle 可以這樣實現﹕
SQL>SELECT * FROM BSEMPMS_OLD MINUS SELECT * FROM BSEMPMS_NEW;
DB2 可以這樣實現﹕
SELECT * FROM BSEMPMS_OLD EXCEPT SELECT * FROM BSEMPMS_NEW;
SELECT * FROM BSEMPMS_OLD EXCEPT ALL SELECT * FROM BSEMPMS_NEW;
6.兩個結果集互加的函數的Oracle和DB2的寫法
Oracle 可以這樣實現﹕
SQL>SELECT * FROM BSEMPMS_OLD INTERSECT SELECT * FROM BSEMPMS_NEW;
SQL>SELECT * FROM BSEMPMS_OLD UNION SELECT * FROM BSEMPMS_NEW;
SQL>SELECT * FROM BSEMPMS_OLD UNION ALL SELECT * FROM BSEMPMS_NEW;
DB2 可以這樣實現﹕
SELECT * FROM DB2ADMIN.BSEMPMS
UNION
SELECT * FROM DB2ADMIN.BSEMPMS ;
SELECT * FROM DB2ADMIN.BSEMPMS
UNION ALL
SELECT * FROM DB2ADMIN.BSEMPMS ;
7.如何找数据库表的主键字段的名称的Oracle和DB2的寫法
Oracle 可以這樣實現﹕
SQL>SELECT * FROM user_constraints WHERE CONSTRAINT_TYPE='P' and table_name='TABLE_NAME';
DB2 可以這樣實現﹕
select colnames from syscat.indexes where tabname='TABLE_NAME' ;