最近的琐事比较多,而提问题的朋友还是不少,很多消息都没有来得及回复,各种事情一堆起来,不少问题想起来已经过了好几天了,所以还是来整理一篇技术问答为好。
首先是很多朋友问我关于半自动化搭建Data Guard的脚本,我写了几篇文章来介绍思路,自己也提了不少的改进,团队内部也沟通过了,一直迟迟没有发布出来是因为我觉得目前的实现方式可能对于我的工作能够极大提高,但是很多朋友使用的环境可能没有中控的概念,所以不是很通用,所以我想做一些改变,还有一个是里面的有些逻辑我想改改,至少简化一下。但是一直是思想的潜行者,行动的矮子,这件事情拖了不少日子。真是惭愧,我力争下周末前分享出来,然后附上简单的使用说明。
最近开始实践时间管理,所以对于微信上的事情花的精力就少了很多,这样可以让我更加专注,可能隔一段时间我会看看聊天记录。不知不觉,又堆积了快一百条未读消息,目前我使用的时间管理工具是日事清,至少这个工具能够手机端,电脑端都可以同步,这个完全符合我的习惯,使用起来还不错,其实越是指定详细的计划,越是发现自己很多东西都需要学习,都需要改进。看来分得了轻重缓急,而且能够实践到位是一件很不容易的事情。我发现很多时候都会有急于求成的心态,所以任务栏上的有些东西突然加上去了,而有些计划内的东西就耽搁了,长此以往会逐步有拖延的现象,这个一定要引以为戒。
然后来解答几个技术问题。
今天在微信群中看到叶老师提问关于得到DB time的曲线图,其实要得到这样的图形,有两种思路,一种就是得到实时的数据,这个就需要指定频度来抓取状态数据,比如抓取实时DB time,根据这些状态点信息得到一个完整的曲线图,这个在Zabbix监控体系中是没有问题的,而且基于Oracle的监控可以使用Orabbix,要查看按天,按周,按月的曲线图,这个在Zatree里面是完全支持的,目前我们也这么用;而另外一种思路就是基于快照,这个得到的数据频度可能是半小时或者一小时,状态略粗一些,我下午整理了一个shell脚本,感兴趣百度网盘可以查看 https://pan.baidu.com/s/1nvCnl1J
而自我上次发了一篇关于执行计划直方图的文章一来,还是有几个朋友对这方面很关注,提了不少的建议。有些朋友问那个15个字符是什么意思,没看明白,我做个小测试来说明。
创建一个测试表。
> create table test_stats (order_id varchar2(64),user_id varchar2(64),channel_id number);
Table created.
> insert into test_stats values('0000000000001241414','test',1);
1 row created.
> insert into test_stats values('0000000000001251414','test2',2);
1 row created.
> insert into test_stats values('0000000000001251514','test3',2);
1 row created.
> commit;
Commit complete.
如果想看更多细节,可以开启10046事件。
ALTER SESSION SET EVENTS '10046 trace name context forever, level 12'
收集统计信息
exec dbms_stats.gather_table_stats(tabname => 'test_stats',ownname => 'N1',method_opt => 'FOR ALL COLUMNS SIZE AUTO');
ALTER SESSION SET EVENTS '10046 trace name context off'
收集统计信息使用了auto选项呢,可以看到,都没有生成直方图信息。
SELECT COLUMN_NAME, NUM_DISTINCT, NUM_BUCKETS, HISTOGRAM
FROM USER_TAB_COL_STATISTICS
WHERE TABLE_NAME = 'TEST_STATS' AND COLUMN_NAME IN ('ORDER_ID','USER_ID') ;
COLUMN_NAME NUM_DISTINCT NUM_BUCKETS HISTOGRAM
---------------------- ------------ ----------- ------------------------------
ORDER_ID 3 1 NONE
USER_ID 3 1 NONE
但是实际上查看数据字典可以看到还是依旧存在两个默认的bucket.
select to_char(endpoint_value) value,endpoint_number,column_name from dba_tab_histograms where table_name = 'TEST_STATS' and column_name in ('ORDER_ID','USER_ID') ORDER BY endpoint_number;
VALUE ENDPOINT_NUMBER COLUMN_NAME
---------------------------------------- --------------- --------------------
250207622735984000000000000000000000 0 ORDER_ID
604364106098959000000000000000000000 0 USER_ID
250207622735984000000000000000000000 1 ORDER_ID
604364106160614000000000000000000000 1 USER_ID
这个值是怎么算出来的。
首先对字段order_id的max值做一个dump
SQL> select to_char(substrb(dump(max("ORDER_ID"),16,0,32),1,120)) from "N1"."TEST_STATS" t ;
TO_CHAR(SUBSTRB(DUMP(MAX("ORDER_ID"),16,0,32),1,120))
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Typ=1 Len=19: 30,30,30,30,30,30,30,30,30,30,30,30,31,32,35,31,35,31,34
然后取前30位,转为十六进制,得到的是2502开始的一长串数字。
SQL> select to_number('303030303030303030303030313235','xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx') aa from dual;
AA
-------------------------------------------------------------
250207622735984164311304858405777973
而得到的这一长串数字的前15位是什么呢?
SQL> select substr('250207622735984164311304858405777973',1,15) from dual;
SUBSTR('2502076227359841643113
------------------------------
250207622735984
我们这个时候来看看直方图数据字典的信息。可以看到value是250207622735984000000000000000000000,前面的15位就是我们计算得到的这个数字。
select to_char(endpoint_value) value,endpoint_number,column_name from
dba_tab_histograms where table_name = 'TEST_STATS' and column_name in
('ORDER_ID') ORDER BY endpoint_number;
VALUE ENDPOINT_NUMBER COLUMN_NAME
---------------------------------------- --------------- --------------------
250207622735984000000000000000000000 0 ORDER_ID
250207622735984000000000000000000000 1 ORDER_ID
而如果我们重新收集统计信息,指定bucket为20
exec dbms_stats.gather_table_stats(tabname => 'test_stats',ownname => 'N1',method_opt => 'FOR COLUMNS SIZE 20 ORDER_ID');
然后再次查看,其实这个时候只生成了3个,因为我只插入了3行数据,样本太少,但是查看value值是一样的,这样也就很难有所差别,其实也算是丢失了一些精度导致。
SQL> select to_char(endpoint_value) value,endpoint_number,column_name,ENDPOINT_ACTUAL_VALUE from dba_tab_histograms where table_name = 'TEST_STATS' and column_name in ('ORDER_ID') ORDER BY endpoint_number;
VALUE ENDPOINT_NUMBER COLUMN_NAME ENDPOINT_ACTUAL_VALUE
---------------------------------------- --------------- -------------------- ----------------------------------------
250207622735984000000000000000000000 1 ORDER_ID 0000000000001241414
250207622735984000000000000000000000 2 ORDER_ID 0000000000001251414
250207622735984000000000000000000000 3 ORDER_ID 0000000000001251514