快速生成日期維度資料

2021-09-16 21:50:55 字數 4332 閱讀 6860

日期維度在資料倉儲中是乙個特殊角色。日期維度包含時間概念,而時間是最重要的,因為資料倉儲的主要功能之一就是儲存和追溯歷史資料,所以每個資料倉儲裡的資料都有乙個時間特徵。裝載日期資料有三個常用方法:預裝載、每日裝載一天、從源資料裝載日期。在三種方法中,預裝載最為常見也最容易實現。在資料倉儲生命週期中,只需要預裝載日期維度一次。

假設建立有如下日期維度表:

create table date_dim (    

date_sk int,            -- **鍵  

date date,              -- 日期

month smallint,         -- 月份

month_name varchar(9),  -- 月份名稱

quarter smallint,       -- 季度

year smallint           -- 年份

);

採用預裝載方法一次性生成21年的日期維度資料,從2023年1月1日到2023年12月31日。在資料庫中生成日期維度資料很簡單,因為資料庫一般都提供了豐富的日期時間函式,而且可以在儲存過程中迴圈插入資料。下面對比hawq中兩個生成日期資料函式的效能。

方法一:平凡低效

create or replace function fn_populate_date (start_dt date, end_dt date)    

returns void as $$    

declare    

v_date date:= start_dt;   

v_datediff int:= end_dt - start_dt;  

begin    

for i in 0 .. v_datediff loop      

insert into date_dim    

values(i,

v_date,

extract(month from v_date),

to_char(v_date,'mon'),

extract(quarter from v_date),

extract(year from v_date));   

v_date := v_date + 1;  

end loop;  

analyze date_dim;  

end; $$    

language plpgsql;

關於這個函式沒什麼好說的,就是乙個大迴圈,每次插入一條資料。以起始日期和終止日期引數的相差天數作為迴圈次數。在我的環境中執行這個函式需要將近9分鐘,原因主要在於insert語句被執行了7671次。

postgres=# select fn_populate_date(date '2000-01-01', date '2020-12-31'); 

fn_populate_date 

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

(1 row)

time: 533999.903 ms

方法二:高效迭代

create or replace function fn_populate_date (start_dt date, end_dt date)  

returns void as  

$$  

declare  

i int:=1;

v_date date:= start_dt;

v_datediff int:= end_dt - start_dt;

begin  

truncate table date_dim;

insert into date_dim(date_sk, date, month, month_name, quarter, year)

values(i,

v_date,

extract(month from v_date),

to_char(v_date,'mon'),

extract(quarter from v_date),

extract(year from v_date));

while i <= v_datediff

loop    

insert into date_dim(date_sk, date, month, month_name, quarter, year)  

select date_sk + i, date + i, 

extract(month from date+i),

to_char(date+i,'mon'),

extract(quarter from date+i),

extract(year from date+i)

from date_dim where date +i <= end_dt;

i := i*2;

end loop;

analyze date_dim;

end;  

$$  

language plpgsql;

這次執行只用了不到5秒鐘。

postgres=# select fn_populate_date(date '2000-01-01', date '2020-12-31');

fn_populate_date 

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

(1 row)

time: 4987.249 ms

在這個函式中,變數 i 儲存插入date_dim表的行數。迴圈開始前先插入 1 條資料,然後當 date +i <= end_dt 成立時執行迴圈。在每次迭代中,該函式把日期維度表當前所有行的值加上 i 後再插入日期維度表中。這樣每次迴圈插入的行數以2的冪次方遞增,insert語句只被執行了14次,其中還包括作為種子資料的第一次插入。因此這個函式的執行速度很快。

這種思想具有一定的通用性,例如在mysql中生成數字輔助表資料時,就可以用下面的過程快速生成。

delimiter //

create procedure pfastcreatenums(cnt int)

begin

declare s int default 1;

truncate table nums;

insert into nums select s;

while s<=cnt do

insert into nums select id+s from nums where id+s <=cnt;

set s=s*2;

end while;

commit;

end;

//

方法三:一次生成

insert into date_dim

select date_sk,

date,

extract(month from date),

to_char(date,'mon'),

extract(quarter from date),

extract(year from date)

from (select rn date_sk,date('2000-01-01') + rn - 1 date

from (select generate_series(1,7671) rn) t) t;

這種方法利用 generate_series 函式生成的序列一次性生成所有日期,只需要1秒多。

postgres=# insert into date_dim

postgres-# select date_sk,

postgres-# date,

postgres-# extract(month from date),

postgres-# to_char(date,'mon'),

postgres-# extract(quarter from date),

postgres-# extract(year from date)

postgres-# from (select rn date_sk,date('2000-01-01') + rn - 1 date

postgres(# from (select generate_series(1,7671) rn) t) t;

insert 0 7671

time: 1225.582 ms

Sqlserver儲存過程生成日期維度

話不多說,之前已經有一篇日誌是利用oracle的儲存過程生成日期維度表,接下來我們就用sqlserver來實現這個操作,如下面的步驟所示 1 建立日期維度表 dim time use dw go object table dbo dim time script date 12 19 2015 15 ...

MSSQL生成日期列表

title generating test data author wufeng4552 date 2009 09 28 08 52 38 if exists select from dbo.sysobjects where id object id n dbo f getdate and xtyp...

linux crontab e生成日期格式

近期公司資料庫伺服器要上雙活專案,實施顧問要收集伺服器 磁碟效能資料 io及vm的一些相關資訊,並已日期時間格式生成檔案 用crontab e增加以下內容,它的作用是每隔1個小時啟動一次iostat和vmstat,iostat的間隔為10秒,共360次,即為1個小時。以下是顧問給的指令碼,直接在終端...