Home » Posts tagged "db" (Page 19)

PostgreSQL 9.5 的 GROUPING SETS 以及 CUBE 與 ROLLUP

Zite 上看到的「Postgres finally has CUBE / ROLLUP / GROUPING SETS !」。

直接看 PostgreSQL 的文件「7.2.4. GROUPING SETS, CUBE, and ROLLUP」就可以知道用法:

=> SELECT * FROM items_sold;
 brand | size | sales
-------+------+-------
 Foo   | L    |  10
 Foo   | M    |  20
 Bar   | M    |  15
 Bar   | L    |  5
(4 rows)

=> SELECT brand, size, sum(sales) FROM items_sold GROUP BY GROUPING SETS ((brand), (size), ());
 brand | size | sum
-------+------+-----
 Foo   |      |  30
 Bar   |      |  20
       | L    |  15
       | M    |  35
       |      |  50
(5 rows)

結果就是分次 GROUP BY 的聯集。而 CUBEROLLUP 則是提供列舉的方式。

ROLLUP 的部份:

ROLLUP ( e1, e2, e3, ... )

表示階層式的列舉:

GROUPING SETS (
    ( e1, e2, e3, ... ),
    ...
    ( e1, e2 )
    ( e1 )
    ( )
)

CUBE

CUBE ( a, b, c )

則是表示 power set (所有的組合):

GROUPING SETS (
    ( a, b, c ),
    ( a, b    ),
    ( a,    c ),
    ( a       ),
    (    b, c ),
    (    b    ),
    (       c ),
    (         ),
)

也有更複雜的 CUBE ( (a,b), (c,d) )GROUP BY a, CUBE(b,c), GROUPING SETS ((d), (e)) 可以用,參考文件裡的範例即可 :p

PostgreSQL 9.5 的 UPSERT

在「Upsert Lands in PostgreSQL 9.5 – a First Look」這邊提到了 PostgreSQL 9.5 支援的 UPSERT 操作。

UPSERT 的定義是:

(computing, database) An operation that inserts rows into a database table if they do not already exist, or updates them if they do.

如果不存在就 INSERT,如果存在就 UPDATE,然後取一部分的字變成 UPSERT。由於要偵測「存在」,只能用在有 primary key 或是有 unique 條件時的表格上。

作者給的範例講解了 PostgreSQL 9.5 上的語法:

INSERT INTO products (
    upc,
    title,
    description,
    link)
VALUES (
    123456789,
    ‘Figment #1 of 5’,
    ‘THE NEXT DISNEY ADVENTURE IS HERE - STARRING ONE OF DISNEY'S MOST POPULAR CHARACTERS! ’,
    ‘http://www.amazon.com/dp/B00KGJVRNE?tag=mypred-20'
    )
ON CONFLICT DO UPDATE SET description=excluded.description;

這邊用的是 ON CONLIFCT DO UPDATE SET,在 MySQL 則是用 ON DUPLICATE UPDATE

關於要不要使用 MySQL 這件事情...

前陣子 ant 將在 5xRuby 演講的投影片放出來:「技術演講:淺入淺出 MySQL & PostgreSQL」,另外在 kaif.io 上也有討論:「淺入淺出 MySQL & PostgreSQL // Speaker Deck」。

而國外剛好也有好幾篇文章都在討論 MySQL (InnoDB),其中「how innodb lost its advantage」這篇講到對 InnoDB 的壓縮感到悲觀...

另外 Pinterest 的「Learn to stop using shiny new things and love MySQL」這篇的時間點感覺上就是在回應上面某些想法。

下面是我的整理 (以及想法)。

MySQLPostgreSQL 都是很成熟的 RDBMS。

如果你對其中一種有經驗,那麼就用你熟悉的 RDBMS。如果你對兩者都有經驗,那麼你就憑自己的判斷選擇。

如果都沒有經驗呢?看你身邊的人用什麼就選什麼。

我在 5xRuby 時回答的比較輕鬆,但這是很實際的回答:你既然都不會用這些進階功能,那麼兩套其實對你都差不多。選一個可以問的到答案的就好。

反正真的夠大的時候,拿錢出來總是有方案可以解決問題。初期把力氣花在怎麼搞定產品吧,如果你不熟悉,這通常都不是你在這個時間應該花時間去研究的問題。

InnoDB 對 Primary Key 的選擇

前幾天 Ant 在「淺入淺出 MySQL & PostgreSQL」剛好有提到,結果 Percona 這兩天也丟出了這個題目,不過這邊討論的是空間的問題:「Illustrating Primary Key models in InnoDB and their impact on disk usage」。

一樣的作法,Primary Key 的選擇有三種:

  • INT + AUTO_INCREMENT
  • BINARY(16) (Ordered UUID)
  • CHAR(36) (Random UUID)

用的是 Jeremy Colespace-lsn-age-illustrate 畫出 LSN 的值 (InnoDB 的 Log Sequence Number,由於嚴格遞增,可以藉由這個值知道每個 page 最新被修改的時間):

I then used the powerful tool innodb_space’s function space-lsn-age-illustrate (from Jeremy Cole’s innodb_ruby project) to plot the LSN (InnoDB’s Log Sequence Number, an always-incrementing value) pages from each table that uses the different Primary Keys via ASCII colour (so hot, right? Thanks Jeremy!!).

測試是 INSERT-only 的 case,雖然不太能理解為什麼要用 CHAR(36) 存 UUID,而非與 BINARY(16),但可以看出一些 pattern。

有順序的 INT + AUTO_INCREMENT 與 BINARY(16) (Ordered UUID) 都可以看出層次 (一直往後寫),而且也看得出來 BINARY(16) 比 INT 大了不少:

而 CHAR(36) 當然是最大的,而且寫入的 i/o 也最隨機:

innodb_file_per_table 對於 CREATE TABLE 與 DROP TABLE 的速度

雖然平常應該不會常常用到 CREATE TABLEDROP TABLE,不過還是很有趣的 benchmark:「Is MySQL’s innodb_file_per_table slowing you down?」。

重點在這段:

  • With innodb_file_per_table=ON
    • Schema and table creation = 1m54.852s
    • Schema drops = 1m21.682s
  • With innodb_file_per_table=OFF
  • Schema and table creation = 0m59.968s
  • Schema drops = 0m54.870s

不過作者測試時沒有用 ENGINE=COMPRESSED (必須在 innodb_file_per_table 打開時才支援,而且這也是選擇打開 innodb_file_per_table 的重要因素),不知道壓縮開起來以後會差多少...

不過就算再怎麼慢,相較於 CREATE TABLEDROP TABLE 的效能,還是比較計較壓縮換來的 I/O 效能。(尤其是資料量超過記憶體大小時)

關於 RDBMS 的 Schema Migration...

在「NoSQL 大腸花」這份投影片裡面的 Page 12 有提到關於 RDBMS 的 Schema Migration:

以目前 open source 的兩個專案,MySQLPostgreSQL 來看,裡面提到的 lock 應該都不是問題...

首先是 MySQL 的部份,真的量大的網站都應該是往 InnoDB 投靠,而 pt-online-schema-change 在這個領域則是處理的很好。

Facebook 的 Mark Callaghan 曾經在 2010 年寫過一篇關於 InnoDB 的 online schema change 的原理:「Online Schema Change for MySQL」,主要是利用 Trigger 的機制,用七個步驟架構出沒有 downtime 的 online scheme change。

就算不考慮 pt-online-schema-change 這種工具,在 MySQL 5.6 開始,就有愈來愈多 ALTER TABLE 的行為是不會影響到 read/write 了:「Avoiding MySQL ALTER table downtime」。

而 PostgreSQL 的情況也差不多,常見的 ALTER TABLE (新增與刪除 column 與 index) 也都不會影響 read/write。

這些在 Stack Overflow 上有不少討論:「ALTER TABLE without locking the table?」。

MySQL 在 RDBMS 領域裡比起來的確是不怎樣,不過沒有這麼糟糕啊...

Amazon Aurora

Amazon RDS for Aurora 是這次 re:Invent 發表的資料庫:「Amazon Aurora - New Cost-Effective MySQL-Compatible Database Engine for Amazon RDS」。

以往的資料庫都是先選定好 storage 大小、storage 種類 (以及 IOPS),然後再選擇機器大小,而要更改的時候會有 downtime。

這次推出的 Amazon Aurora 則是拿掉前面兩個限制,由系統自動幫你處理:空間與 storage 種類 (包括 IOPS)。你只要選擇 instance 的種類就就可以了。

重點是相容於 MySQL 啊,現有使用 MySQL 的程式大多都可以直接接上去,從 10GB 長大到 64TB 都可以無痛一直升級...

由於 IOPS 的部份不需要事先 booking,機器的價錢看起來還算合理,找機會來測試看看可以惡搞到什麼程度?

Archives