iT邦幫忙

第 11 屆 iT 邦幫忙鐵人賽

DAY 24
1
Postgresql Sequence 的操作及容量

接續昨天的討論.先來建立一個 sequence , 設定 maxvalue 為 7, 開始值為 2,
遞增值為 2,會循環.

create sequence nana.s3
as smallint
increment by 2
maxvalue 7
start with 2
cycle;

檢查相關資訊
\d nana.s3
                          Sequence "nana.s3"
+----------+-------+---------+---------+-----------+---------+-------+
|   Type   | Start | Minimum | Maximum | Increment | Cycles? | Cache |
+----------+-------+---------+---------+-----------+---------+-------+
| smallint |     2 |       1 |       7 |         2 | yes     |     1 |
+----------+-------+---------+---------+-----------+---------+-------+

取值
select array_agg(n::text || '->' || nval::text)
  from (select n, nextval('nana.s3') nval
          from generate_series(1, 10) as gs(n)) a;

+------------------------------------------------------+
|                      array_agg                       |
+------------------------------------------------------+
| {1->2,2->4,3->6,4->1,5->3,6->5,7->7,8->1,9->3,10->5} |
+------------------------------------------------------+

利用 array 以及 array_agg()聚合, 這樣避免一長串.
可以看到取了10次,是循環的.

select currval('nana.s3');
+---------+
| currval |
+---------+
|       5 |
+---------+

接著建立 increment 為 -1 的.

create sequence nana.s4
as smallint
increment by -1;

\d nana.s4
                          Sequence "nana.s4"
+----------+-------+---------+---------+-----------+---------+-------+
|   Type   | Start | Minimum | Maximum | Increment | Cycles? | Cache |
+----------+-------+---------+---------+-----------+---------+-------+
| smallint |    -1 |  -32768 |      -1 |        -1 | no      |     1 |
+----------+-------+---------+---------+-----------+---------+-------+

可以觀察到 從 -1 開始, 而且 default 的 Maximum 也是 -1.

來看取值

select array_agg(n::text || '->' || nval::text)
  from (select n, nextval('nana.s4') nval
          from generate_series(1, 5) as gs(n)) a;

+---------------------------------+
|            array_agg            |
+---------------------------------+
| {1->-1,2->-2,3->-3,4->-4,5->-5} |
+---------------------------------+

接著來建立 increment 為 -1, Maximum 為 32767的.

create sequence nana.s5
as smallint
increment by -1
maxvalue 32767;

\d nana.s5
                          Sequence "nana.s5"
+----------+-------+---------+---------+-----------+---------+-------+
|   Type   | Start | Minimum | Maximum | Increment | Cycles? | Cache |
+----------+-------+---------+---------+-----------+---------+-------+
| smallint | 32767 |  -32768 |   32767 |        -1 | no      |     1 |
+----------+-------+---------+---------+-----------+---------+-------+

由上面幾個 sequence 的情況觀察,可以知道.當未設定 Maximum 或 Minimum 時.
以 increment 之正負,來定. 0 是被排除的.
                     -   +
      型態的Min <==(-1) 0 1==> 型態的Max

除了 default 的方式以外,還可以自行設定 Max, Min 來決定取值的範圍.

試試看 Min > Max

create sequence nana.s6
as smallint
minvalue 5
maxvalue 3;

ERROR:  22023: MINVALUE (5) must be less than MAXVALUE (3)

這樣會出現錯誤.

修改一下.

create sequence nana.s6
as smallint
minvalue 3
maxvalue 5;

select array_agg(n::text || '->' || nval::text)
  from (select n, nextval('nana.s6') nval
          from generate_series(1, 3) as gs(n)) a;
+------------------+
|    array_agg     |
+------------------+
| {1->3,2->4,3->5} |
+------------------+

再取一個值.

select nextval('nana.s6');

ERROR:  2200H: nextval: reached maximum value of sequence "s6" (5)

會出現錯誤訊息.告知超過 Maxvalue (5).

當我們使用 sequence 時,需要注意是否達到上限.
sequence 是使用 smallint, integer, bigint 三種,分別是 2 bytes, 4 bytes, 
8 bytes. default 只使用正數,不含 0.至於為何要這樣設計呢?
一來是符合一般的習慣,二來是可以另有妙用,這留待後續會分享.

先來討論這三種數值,是否足夠使用.
可以觀察昨天的資料知道 是 32 KB, 2048 MB, 8388608 TB.
或者可以查文件,然後複製 bigint(int8) 的一長串數字,來計算.

假設每分鐘輸入 10K 筆資料.一年約

select 10000 * 1440 * 365::bigint;
+------------+
|  ?column?  |
+------------+
| 5256000000 |
+------------+

其實看到 使用 bigint 來計算就知道 2048M 是不夠的.
改成計算週數

select 2147483647 / (10000 * 1440 * 7::bigint);

+----------+
| ?column? |
+----------+
|       21 |
+----------+

僅21週! 使用 integer 型態的 sequence ,就要很小心.

那接著來看使用 bigint (int8), 的情況下,若每分鐘輸入 1M 筆資料,可以撐多久?
因為我不想去copy那一串數字,所以改用計算的方式.

select big / (1000000 * 1440 * 365::bigint) as "year"
  from (select  -(((2^(8*pg_column_size(1::bigint)-2))::bigint << 1)+1) as big) a;

+----------+
|   year   |
+----------+
| 17548272 |
+----------+

還蠻久的,使用 bigint 型態的情況下,只要小心檢查,適當的移轉舊資料,應該是比較安全.

今天做了一些關於sequence 的容量相關介紹,昨天有寫一個 function,但是還不夠完備.
看了今天的介紹,理解了 Minvalue, Maxvalue 是可以自行調整,而且方向可以是遞增或是
遞減,情況就顯得比較複雜了,怎樣修改 function 讓他可以正確的計算,這個先留給大家思考一陣子.
我會在本系列結束之前,將我的方法與大家分享.
明天將探討 sequence 使用在 table 的情況.


上一篇
Postgresql 的 Sequence 關聯物件
下一篇
Postgresql Sequence 與 Surrogate_key
系列文
以Postgresql為主,聊聊資料庫.31

尚未有邦友留言

立即登入留言