暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

关于日期类型列对应的直方图统计信息里的endpoint_value值的推算

原创 Jenny 2021-10-23
1188

对于日期类型的字段收集直方图后,在直方图统计视图中显示的endpoint_value为长串数字,怎么将这些数字与实际的日期值对应起来呢?

我们举例说明一下:

表TEST_D的列D1的统计信息如下:

SQL> select column_name,high_value,low_value from user_tab_col_statistics where table_name='TEST_D' and column_name='D1';

 COLUMN_NAME        HIGH_VALUE           LOW_VALUE

----------------- ------------------ --------------------

D1                   78790914010101      78790103010101

这个视图中的high_value与low_value为raw类型的值,我们可以使用dbms_stats.convert_raw_value将其转换为日期类型。

SQL> set serveroutput on;

SQL> declare

  2    highvalue date;

  3    lowvalue date;

  4  begin

  5    dbms_stats.convert_raw_value('78790914010101',highvalue);

  6    dbms_stats.convert_raw_value('78790103010101',lowvalue);

  7    dbms_output.put_line('highvalue:'||to_char(highvalue,'yyyy-mm-dd hh24:mi:ss'));

  8    dbms_output.put_line('lowvalue:'||to_char(lowvalue,'yyyy-mm-dd hh24:mi:ss'));

  9  end;

 10  /

highvalue:2021-09-20 00:00:00

lowvalue:2021-01-03 00:00:00

 

PL/SQL procedure successfully completed.

 

这个列的直方图统计信息如下:

SQL> select column_name,endpoint_value,endpoint_number from user_histograms where table_name='TEST_D' and column_name='D1';

 

COLUMN_NAME    ENDPOINT_VALUE    ENDPOINT_NUMBER

--------------------  --------------------------    ------------------

D1                          2459218               1

D1                          2459252               2

D1                          2459255               3

D1                          2459354               4

D1                          2459385               5

D1                          2459425               6

D1                          2459445               7

D1                          2459478               8


我们发现endpoint_value是一长串数字,这串数字是怎么来的,是从公元前471311日到这个日期的所经过的天数,闰年的算法比较复杂,我们可以利用差值来推算每个桶的endpoint_value

首先根据lag分析函数算出每个endpoint_value与前一个桶的endpoint_value的差值div。

SQL> select endpoint_value,

  2   endpoint_value - lag(endpoint_value, 1) over(order by endpoint_number) as div,

  3                 endpoint_number

  4            from user_histograms

  5           where table_name = 'TEST_D'

  6             and column_name = 'D1';

 

ENDPOINT_VALUE        DIV     ENDPOINT_NUMBER

------------------------    ---------        ---------------

       2459218                          1

       2459252         34               2

       2459255          3               3

       2459354         99               4

       2459385         31               5

       2459425         40               6

       2459445         20               7

       2459478         33               8

 

8 rows selected.

我们使用sum分析函数计算出当前桶距离第一个桶的差值sumdiv,再使用列统计视图中low_value对应的日期值加上sumdiv,这样就可以推算出每个endpoint_value。

SQL> select to_date('2021-01-03 00:00:00','yyyy-mm-dd hh24:mi:ss') + sum(nvl(div, 0)) over(order by endpoint_number) as endpoint_value,

  2  endpoint_number

  3    from (select endpoint_value,

  4             endpoint_value - lag(endpoint_value, 1) over(order by endpoint_number) as div,

  5                 endpoint_number

  6            from user_histograms

  7           where table_name = 'TEST_D'

  8             and column_name = 'D1') a

  9  ;

 

ENDPOINT_VALUE      ENDPOINT_NUMBER

------------------- ---------------

2021-01-03 00:00:00               1

2021-02-06 00:00:00               2

2021-02-09 00:00:00               3

2021-05-19 00:00:00               4

2021-06-19 00:00:00               5

2021-07-29 00:00:00               6

2021-08-18 00:00:00               7

2021-09-20 00:00:00               8


我们可以看到最大桶的endpoint_value与列统计视图的high_value对应的日期值是吻合的。

经勇哥提醒,此数字为儒略日,oracle其实有函数根据这个值计算出实际日期。

SQL> select to_date(2459218,'J') from dual;

TO_DATE(2459218,'J'
-------------------
2021-01-03 00:00:00

但是这个转换只针对整形数字,无法对小数数字进行转换,官方文档中这样说的

对格式串‘J’的转换:Julian day; the number of days since January 1, 4712 BC. Number specified with J must be integers.

如果时间有具体时分秒,直方图中endpoint_value是带小数点,所以用窗口函数来处理还是有用的。

当我们想依据直方图计算某个日期值的选择性时可以使用此方法。

下面普及一下儒略日常识:

儒略日的起点订在公元前4713年(天文学上记为 -4712年)1月1日格林威治时间平午世界时12:00),即JD 0指定为UT时间B.C.4713年1月1日12:00到UT时间B.C.4713年1月2日12:00的24小时。每一天赋予了一个唯一的数字,顺数而下,如:1996年1月1日12:00:00的儒略日是2450084。这个日期是考虑了太阳、月亮的轨道运行周期,以及当时收税的间隔而订出来的。

最后修改时间:2021-11-04 11:18:39
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论