Baby I Love You!

2010年7月27日下午1点53分,我的儿子张小事儿诞生了,八斤半啊,医生说,“好久没抱过这么沉的新生儿了”。

祝愿我的儿子会健康壮实,成为名副其实的属老虎的狮子座男子汉。

诸位一直以来关心我们的朋友,我的儿子用小老虎一样的哈欠向各位问好且表示感谢。:)

谢谢我的弟弟,你的房子和你今天来回地跑几趟,亲弟弟我才敢这么支使你。
谢谢600的媳妇儿寿影帮忙在医院跑前跑后,没有你就没有这样顺利的过程,你是当之无愧的干妈。
谢谢eygle帮我cover这段时间本应我去做的工作,辛苦了。
谢谢coolyl让我住在离医院更近的他的房子里,减少了我来回奔波的距离。
谢谢老丈人,丈母娘,姐姐,老姑,你们的精心照顾让我完全没有后顾之忧。
谢谢爸妈和小阿姨在老家的惦记和嘱咐,虽然你们没有在身边,但是我知道你们比我们更焦急更关心。
谢谢医生,护士,六院是很好的医院。

当然,最需要感谢的是我漂亮勇敢的老婆,你是我的骄傲,我爱你。

User Experience Suggesion for Dameng Database

试用了达梦数据库6.02 for Linux版本。测试的操作系统为CentOS 5虚拟机,数据库软件从此处下载

本文并未像老杨那样做产品功能性的测试,实际上老杨已经测试的够详细了。

只是作为Oracle的重度用户,在用户体验上将DM和Oracle做些许比较,大部分集中在DM的isql和Oracle的sql*plus上,当然这些比较还很肤浅,权当一看。

1. 最重要的,最诚恳的建议,达梦应该在网上提供完全没有任何技术限制的软件下载,包括达梦企业版和安全版。达梦不需要怕别人免费用自己的数据库,而应该怕别人没有兴趣用自己的数据库。如果免费使用的人数有1万,那么希望进行技术讨论的人数就可能会有1千,而1千个踊跃讨论的用户将会带来更多的免费使用人群,这些人群中只要有1%愿意付费,就是达梦的成功。只有虚怀若谷才能海纳百川。

2. 字符界面的静默安装速度很快,但是安装过程中的英文提示有“Whether to ”字样,我明白是想表达“是否要”的意思,但是出现在安装提示中比较奇怪,建议全部去掉。比如:

Whether to Initialize the Database (Y/y,N/n) [Y/y]:y
Whether to Modify DataBase Initiation Parameter (Y/y,N/n) [N/n]:y
Whether to Modify SYSDBA Password (Y/y,N/n) [N/n]:

3. 安装文档中并没有提及在Linux环境需要创建另外的用于安装DMDBMS的用户组和用户,因此这可能会让大家都使用root用户来安装DM数据库,实际上在我的测试环境中也是使用root用户的。建议对于安装程序和文档都做相应修改,明确建议DM数据库应该安装在自己的用户下。比如用户组是dba,用户是dmusr。

4. 即使在安装过程中选择了安装示例数据库,但是在安装结束以后并没有发现有BOOKSHOP数据库。

5. 安装完毕以后需要重新login,因为 export LD_LIBRARY_PATH=/u01/dmdbms/bin这样的设置仅仅更新在.bash_profile中了,但是当前环境没有生效,此时运行isql会报错:

./isql: error while loading shared libraries: libdmapi.so: cannot open shared obj

建议不要依靠LD_LIBRARY_PATH这样的设置,或者在安装后立刻在当前环境中使 LD_LIBRARY_PATH设置生效。

6. 即使已经设置大小写不敏感,但是isql登陆时默认密码必须使用大写。这容易让初次使用者困惑。

[root@centos-vm ~]# isql sysdba/sysdba
isql V6.0.2.51-Build(2009.12.23)
login fail
SQL>exit
[root@centos-vm ~]# 
[root@centos-vm ~]# isql sysdba/SYSDBA
isql V6.0.2.51-Build(2009.12.23)
login success

7. iSQL中的describe没有desc缩写,这会让习惯于Oracle的用户很不习惯。iSQL中的输出结果完全没有排列整齐,急需修改。
[sourcecode language=”sql”]SQL>describe vversion;
describe v
version;

COLNAME TYPE LENGTH NULLABLE

1 BANNER VARCHAR2 80 Y
1 rows got
time used: 0.685(ms).[/sourcecode]

8. 在iSQL提示符下,即使是空行回车也显示行数符号,必须用;来结束,这对于习惯于在上一个SQL语句结束以后,多按几次回车空出几行使显示更清楚的操作人员来说很困扰。
[sourcecode language=”sql”]SQL>
2
3
4 ;
line 4: syntax error: ‘;'[/sourcecode]

建议修改为oracle的sqlplus样式
[sourcecode language=”sql”]D:\Temp>sqlplus /nolog

SQL*Plus: Release 11.2.0.1.0 Production on Fri Jul 23 18:15:01 2010

Copyright (c) 1982, 2010, Oracle. All rights reserved.

SQL>
SQL>
SQL>
SQL>[/sourcecode]

9. 对于英文环境必须要求设置java font的路径,否则只能显示乱码(如下图)。强烈建议在Linux下的那些java gui,比如manager,console等具备英文界面。

10. 小细节,Uninstall DMDBMS的图标用的是Windows的回收站图标。这对于安装到Linux操作系统中的数据库软件来说有些奇怪,而且这个图标跟其它的图标看上去有些不配套。

Oracle Histogram Investigation

这段时间有客户的10gR2数据库经常遭遇执行计划不稳定的现象,应该是直方图信息(Histogram)+绑定变量窥视(Bind Variable Peeking)造成的问题,藉此分享一下直方图的使用经验,但是我非常希望能听到针对本文的不同声音。测试环境Oracle 11.2.0.1 for Windows X64。

创建一个测试表。

drop table t;

create table t as
select
rownum n1,
ROUND(rownum / 100) n2,
'xxxx' n3
from
dba_objects
where
rownum <= 10000;

这样我们生成了一张表T,其中有一万行记录。
N1字段可以认为是主键,有10000个distinct值(1-10000),这是一个数据分布均匀的字段;
N2字段有101个distinct值,除了第一个值0和最后一个值101之外,其它的值都有100行记录,我们可以认为这是一个数据分布均匀的字段;
N3字段有10000个值都是xxxx,实际上这也仍然是一个分布均匀的字段。

对于这三种类型的字段,我们都不应该去收集直方图信息,因为没有意义。那么直方图信息之所以需要存在的根本意义在哪里?

一. 我们何时该做
直方图究其根本实际上就是一个数据分布的图示,这个图示是为了在生成SQL执行计划的时候给Oracle的CBO更多的信息,换句话说,就是当在where条件中的某些列可能由于列值的不同而希望CBO制定出不同的执行计划时,我们需要直方图。

反过来说,什么情况下我们不需要直方图呢?或者说直方图的存在是没有意义的呢?
1. 当此列不用于查询时,也就是这个字段永远不会出现在where条件中(注意:即使是用于表连接那也算是出现在where条件中)。
2. 当此列无论给予什么比较值,我们都希望永远是一种执行计划时。上面例子中的3个字段都属于这种情况。
对于N1或者N2出现在where条件中,我们希望永远是用该列上的索引扫描(当然需要在该列上先创建索引),对于N3出现在where条件中,我们希望永远是全表扫描。这样的执行计划的制定,只要有表级别的统计信息就足够了,直方图信息的出现不但不会对制定正确的执行计划有帮助,甚至会出现奇怪的现象导致执行计划不稳定。

二. 我们可以怎样做
那么我们继续看一下收集直方图信息的方法,众所周知,是需要使用DBMS_STATS.GATHER_TABLE_STATS存储过程的,并且是由这个存储过程中的method_opt参数决定的。可以由以下几种选择。

method_opt=>’for columns size skewonly [column_name]’
什么是SKEWONLY?先看一下Oracle官方文档中的定义。

Oracle determines the columns to collect histograms based on the data distribution of the columns.

也就是要看列上的数据分布,那么按照我们前面提到的,T表中的三列数据分布都是均匀的,并不应该收集任何列上的直方图信息,实际呢?

EXEC dbms_stats.gather_table_stats(ownname=>'KAMUS',tabname=>'T',estimate_percent=>NULL,method_opt=>'for all columns size skewonly',CASCADE=>true);
SQL> select column_name,density,num_buckets,histogram from dba_tab_col_statistics where table_name='T';
COLUMN_NAME DENSITY NUM_BUCKETS HISTOGRAM
------------------------------ ---------- ----------- ---------------
N3 .00005 1 FREQUENCY
N2 .00005 101 FREQUENCY
N1 .0001 1 NONE

可以看到在N2上收集了直方图信息,收集了101个bucket,而N3上则收集了1个bucket的直方图信息(实际上也只能收集一个,因为只有一个distinct值xxxx)。收集直方图信息是耗费资源的,因此SKEWONLY不推荐使用。实际上经历了这么多版本,SKEWONLY的算法一直很奇怪,我没有找到一份文档描述Oracle到底是如何定义SKEWONLY的收集凭据的。

method_opt=>’for columns size auto [column_name]’
什么是AUTO?再看一下Oracle官方文档中的定义。

Oracle determines the columns to collect histograms based on data distribution and the workload of the columns.

也就是在SKEWONLY的基础上额外增加了workload限制,何谓workload?实际上就是我们前面提到的是否在where条件中出现。如果一个列从来没有出现在where条件中,Oracle就认为是没有workload的,那么即使此列上的数据被认为是SKEW的,也不会收集直方图信息,只有出现过至少一次,Oracle才会收集。[via Comment by Dbsnake] 该workload信息可以从数据字典COL_USAGE$中获得,在数据字典中存在的列才是有workload的。

--T表是新创建的,创建完毕以后还没有进行过任何select,因此AUTO选项不会收集任何直方图信息。
EXEC dbms_stats.gather_table_stats(ownname=>'KAMUS',tabname=>'T',estimate_percent=>NULL,method_opt=>'for all columns size auto',CASCADE=>true);
SQL> select column_name,density,num_buckets,histogram from dba_tab_col_statistics where table_name='T';
COLUMN_NAME DENSITY NUM_BUCKETS HISTOGRAM
------------------------------ ---------- ----------- ---------------
N3 1 1 NONE
N2 .00990099 1 NONE
N1 .0001 1 NONE
--执行一次select,再次收集,可以看到N2字段上的直方图信息了。
SQL> SELECT COUNT(*) FROM t WHERE n2=10;
COUNT(*)
----------
100
SQL> EXEC dbms_stats.gather_table_stats(ownname=>'KAMUS',tabname=>'T',estimate_percent=>NULL,method_opt=>'for all columns size auto',CASCADE=>true);
PL/SQL procedure successfully completed.
SQL> select column_name,density,num_buckets,histogram from dba_tab_col_statistics where table_name='T';
COLUMN_NAME DENSITY NUM_BUCKETS HISTOGRAM
------------------------------ ---------- ----------- ---------------
N3 1 1 NONE
N2 .00005 101 FREQUENCY
N1 .0001 1 NONE

因此AUTO也是有问题的,N2字段上的直方图信息仍然会收集,这是我们不需要的。注意,在Oracle10g之后的自动统计信息收集任务中,默认的是FOR ALL COLUMNS SIZE AUTO,这是很有问题的,因此即使是不禁用自动统计信息收集,也应该通过DBMS_STATS.SET_PARAM存储过程(在11gR2版本中被SET_GLOBAL_PREFS存储过程替代)来修改该默认值。通常我们经历的执行计划莫名其妙改变,很多场合都是因为Oracle10g之后的这个统计信息自动收集任务导致的。关于自动统计信息收集,可以参看:Automatic Statistics Gathering

method_opt=>’for columns size repeat [column_name]’
只有在已有直方图信息的列上再次收集直方图信息。这是我们推荐设置为默认值的方式。具体的执行方法见后文。

method_opt=>’for columns size 1 [column_name]’
size 1将删除列上的直方图信息,同样也意味着不收集。

SQL> EXEC dbms_stats.gather_table_stats(ownname=>'KAMUS',tabname=>'T',estimate_percent=>NULL,method_opt=>'for all columns size 1',CASCADE=>true);
PL/SQL procedure successfully completed.
SQL> select column_name,density,num_buckets,histogram from dba_tab_col_statistics where table_name='T';
COLUMN_NAME DENSITY NUM_BUCKETS HISTOGRAM
------------------------------ ---------- ----------- ---------------
N3 1 1 NONE
N2 .00990099 1 NONE
N1 .0001 1 NONE

method_opt=>’for all columns size 30′
size自定义大于1的数值,最大为254,如例表示要求收集30个bucket的直方图信息。

SQL> EXEC dbms_stats.gather_table_stats(ownname=>'KAMUS',tabname=>'T',estimate_percent=>NULL,method_opt=>'for all columns size 30',CASCADE=>true);
PL/SQL procedure successfully completed.
SQL> select column_name,density,num_buckets,histogram from dba_tab_col_statistics where table_name='T';
COLUMN_NAME DENSITY NUM_BUCKETS HISTOGRAM
------------------------------ ---------- ----------- ---------------
N3 .00005 1 FREQUENCY
N2 .00995002 30 HEIGHT BALANCED
N1 .0001 30 HEIGHT BALANCED

那么现在到了最重要的部分,对于一个数据库系统,我们到底应该如何收集直方图信息呢?

三. 我们应该怎样做
首先我们要明确直方图信息是有存在的必要的,但是只应该存在在那些应该要存在的列上,Oracle知道哪些列上应该存在吗?Oracle一直在致力于想知道,可惜的是现在做的仍然不够好,全部交给Oracle去做的话(SIZE SKEWONLY或者SIZE AUTO),可能得到的结果就是该收集的没收集,不该收集的收集了一堆。只有我们的DBA才最知道哪些列上应该收集直方图,这实际上已经远远不仅仅是技术问题了,而是一个业务问题,因此DBA应该去熟悉业务,DBA应该知道自己的应用的数据分布特点,应该知道哪些列会常被用在where条件中。

直方图信息收集是一个漫长而持续的过程,没有一蹴而就的方法,也不可能一劳永逸。

我们推荐的方法是:
1. 第一次收集统计信息时,设置method_opt=>FOR ALL COLUMNS SIZE 1,这意味删除所有列上的直方图。
2. 在测试阶段或者在真实生产环境中,在调优SQL的过程中,DBA将会逐渐得知每个需要直方图信息的字段,在这些字段上人工收集统计信息,method_opt=>FOR COLUMNS SIZE AUTO [COLUMN_NAME],如果你能够明确知道应该收集多少个bucket而手工指定SIZE值那更好。保留收集所有这些字段的脚本,以备数据库系统升级或者迁移时候使用。
3. 在每次数据分布有所变化的时候,更新统计信息,使用method_opt=>FOR ALL COLUMNS SIZE REPEAT,这样只会收集已经存在了直方图信息的字段。

重复2,3步骤,直到系统稳定。这是一个可控的步骤,只有可控,才可能避免不可预知的错误。

[备注1] dba_tab_col_statistics.histogram字段值的含义。
该字段可能包含三个值:NONE,FREQUENCY或者HEIGHT BALANCED。

NONE:就是没有直方图

FREQUENCY:当该列的distinct值数量<=bucket数量时,为此类型。对于此类型而言,在dba_tab_histograms视图中的会存在相当于distinct值数量的记录,该视图的ENDPOINT_VALUE字段记录了这些distinct值,而ENDPOINT_NUMBER字段则记录了到此distinct值为止总共有多少条记录,注意这是一个累加值,实际上我们可以用一条记录的ENDPOINT_NUMBER减去上一条记录的ENDPOINT_NUMBER来获知对应于本记录的ENDPOINT_VALUE值有多少条记录。我知道这听上去很拗口,可能也有些难于理解,但是请尽量去理解吧。 HEIGHT BALANCED:当该列的distinct值数量>bucket数量时,为此类型。比如我们上面的例子收集了SIZE 30的直方图信息,对于N1,N2字段来说都超过了30个distinct值,因此为HEIGHT BALANCED类型。此时dba_tab_histograms视图中的ENDPOINT_NUMBER字段就不再是表示有多少条记录了,而仅仅表示bucket编号,SIZE 30的话,就是简单的0-30(需要31个bucket才可以表示SIZE 30)。主要是在于ENDPOINT_VALUE字段,实际上是这样分的,分了30个bucket,现在T表总共是10000条记录,那么每个bucket里面大概会是333条记录。

第一个ENDPOINT_VALUE的值相当于如下SQL的返回值。
[sourcecode language=”sql” light=”true”]select max(n2) from (select n2 from t order by n2) where rownum<=333[/sourcecode]
第二个ENDPOINT_VALUE的值相当于如下SQL的返回值。
[sourcecode language=”sql” light=”true”]select max(n2) from (select n2 from t order by n2) where rownum<=3332[/sourcecode]
第三个ENDPOINT_VALUE的值相当于如下SQL的返回值。
[sourcecode language=”sql” light=”true”]select max(n2) from (select n2 from t order by n2) where rownum<=333
3[/sourcecode]

依次类推。正是这样的信息告诉了Oracle数据的分布情况,试想一下,如果连续3个bucket的ENDPOINT_VALUE值都10,那么也就是说至少有2个bucket中的记录N2字段都是10,也就是说N2=10的记录至少有666条,越多的bucket有越多相同的ENDPOINT_VALUE值,就表明数据分布越不均匀。
有一点需要额外注意的是:如果某几个bucket的ENDPOINT_VALUE值相同,那么在视图中只会记录最后一个bucket的信息。

[备注2] dba_tab_col_statistics.density字段值的含义。
官方文档中的解释“Density of the column”就跟没说一样。Density的含义是“密度”。

还是看上面的例子,当HISTOGRAM=NONE的时候,N1字段的密度是.0001,一万分之一,1万条记录在某字段上有1万个distinct值,那么该字段的密度就是一万分之一;N3字段的密度是1,1万条记录在某字段上都是相同的,只有1个distinct值,那么该字段的密度就是1。到这里应该可以比较形象的理解Density了。那么对于N2字段来说呢,密度是.00990099,很简单了,1万条记录里面有101个distinct值,10000/101/10000=.00990099。

DENSITY值是会影响CBO判断执行计划的,而回到前文的例子,我们比较一下有直方图和没有直方图时候的同一列的DENSITY值,就会发现很要命的事情,直方图很大地影响到了密度值,目前还没有更科学的方法去研究直方图是如何影响密度的,从而又会对CBO的判断产生多大影响(至少我还没有研究到),但是至少我们可以知道直方图只应该存在在必须存在的列上,因为除了不必要的收集会消耗不必要的资源,它有更多不可预知的影响会导致性能问题。

[备注3] 参阅其它的文章
Choosing An Optimal Stats Gathering Strategy
DBMS_STATS, METHOD_OPT and FOR ALL INDEXED COLUMNS