用 InnoDB 時關於 PRIMARY KEY 的建議

Percona 的「InnoDB scalability issues due to tables without primary keys」這篇文章在討論 InnoDB 在沒有 PRIMARY KEY 時的效能問題。

在討論效能問題前,應該先讀過 MySQL 官方文件裡提到 InnoDB index 架構的文章,其中就有提到 PRIMARY KEY 以及其他的 INDEX KEY 的底層架構:「InnoDB Table and Index Structures」。

InnoDB 是 clustered index 架構 (關於 clustered index 的完整說明,可以參考維基百科的「Database index」條目),也就是說,資料本身 (row data) 存放時會按照某個順序存放,這邊的順序是按照這樣的方式定義的:

  • 如果你有指定 PRIMARY KEY,那麼就會直接用 PRIMARY KEY 當作 clustered index。
  • 如果沒有指定 PRIMARY KEY,但有 UNIQUE INDEX,而且所有欄位都是 NOT NULL,那麼就用這組 UNIQUE INDEX (NOT NULL) 當作 clustered index。
  • 如果都沒有指定 PRIMARY KEY,那麼就會產生一個隱藏的欄位,是一個 6 bytes 的 auto increment 的數字,用這個欄位當 clustered index。也因為如此,在這種情況下,資料會依照建立的順序存放。

另外,InnoDB 的 secondary index 會指到 PRIMARY KEY (B+Tree 的 value 部分是放 PRIMARY KEY)。

所以,一般在規劃資料庫時建議的作法是:

  • 所有的表格都要有 PRIMARY KEY。
  • PRIMARY KEY 必須是 INT UNSIGNED (4 bytes),只有在需要 BIGINT UNSIGNED (8 bytes)的時候才用 BIGINT UNSIGNED。

對於有大量 secondary index 的表格更應該這樣做 (因為可以省下大量空間)。而對於現代的 ORM 來說,也都幾乎要求要有 PRIMARY KEY,甚至有些 ORM 要求 PRIMARY KEY 必須是 single column。

如果你都能了解後,再去看 Percona 討論沒有 PRIMARY KEY 的情況時,才能了解他們想要討論什麼事情... 裡面還包含了 InnoDB 格式的差異。

Percona 對 InnoDB 效能的建議...

2007 年的「Innodb Performance Optimization Basics」這篇是以當時的環境寫的 (MySQL 5.0)。過了六年,出了 MySQL 5.1、5.5,目前新版是 5.6。

於是就冒出這篇 2013 年版:「InnoDB performance optimization basics (updated)」。

主要是新的科技與技術讓 InnoDB 有更多選擇可以用。SSD 的發明讓 i/o 效率更好,而檔案系統的改善使得 ext4 開始被大家接受。

另外 InnoDB 自己的改善也能夠充分發揮現代硬體的能力,尤其是對多核心的延展能力。

這篇該講的都有講到,文末雖然打自家廣告推薦 Percona Server with XtraDB,不過這的確是個好東西。

MySQL 的 SQL Query...

Percona 的 blog 上跑出一篇「What kind of queries are bad for MySQL?」,分析哪些 SQL query 對 MySQL 的效能不好...

內容相當偏激,然後在 comment 引起討論... (文章作者反而就跑去休息了)

舉例來說,他認為只要有 JOIN 就算是 bad query。作者舉了這樣的 SQL query 為例:

SELECT t2.value FROM t2 JOIN t1 ON (t1.id=t2.tid) WHERE t1.orderdate=NOW()

應該要被展開成:

SELECT t2.value FROM t2 WHERE t2.orderdate=NOW()

看得出來有重度 denormalize 與 cache 症狀... XD

CloudFlare 的速度...

CloudFlare 是一種 CDN 服務,相較於其他 CDN 會被歸類到 AkamaiDynamic Site AcceleratorLimelight NetworksDynamic Site Platform,或是 EdgeCastApplication Delivery Network

這類型的 CDN 加速服務,如果用在完全沒有考慮最佳化的網站上,效果應該會很明顯。但如果拿到 WordPress 或是其他 open source 軟體上,反而會因為軟體已經做了不少處理,上了 CloudFlare 反而因為多了一層而變慢。

不過會變慢多少呢?有人跳下去測試寫報告了:「Cloudflare Showdown」,如果懶得看中間的數據,可以看最後的結論「Conclusion」。

如果用在已經最佳化過的網站上,用 CloudFlare 會慢不少,如果是 WordPress 及其他 open source 軟體,最好的情況是快一點點,但最差的情況會慢個幾倍... 作者下的結論是「不要用」。

跟預期差不多,動態資料的加速基本上是個商業包裝而已,真正需要加速還是得自己把可以 cache 的部份切割出來。

node.js 版的 YUICompressor...

看「Fantastic front-end performance Part 1 – Concatenate, Compress & Cache – A Node.JS Holiday Season, part 4」的時候發現 node.js 版的 YUICompressor 比起 Perl 版本更早之前就 porting 完成了:「UglifyCSS」,甚至是官方版本的「yuicompressor / ports / js / cssmin.js」也都遠早於 Perl 版本...

npm 裝 uglifycss 就可以用了...

sitespeed.io 網站測速

sitespeed.io 是一個 open source 軟體,讓開發者可以測試網站的效能,然後輸出 html 報表:「Do you sitespeed?」。

執行需要 Java 1.7+ 以及 PhantomJS,我是在 FreeBSD 上跑 (Java 的部份是用 java/openjdk7),另外根據文章裡第三個 comment,在 Windows 上用 Cygwin 也可以跑。

./sitespeed.io -u http://ptt.cc/ -d 1 -o img 跑出來後會有一整個目錄的報告,包括了 summary 以及所有頁面的清單 (後面這兩個連結是跑完後用 s3cmd sync 丟上 S3 的):「ptt.cc - Summary of the sitespeed.io result」、「ptt.cc - All pages information」。

每一頁都有細項說明,像是首頁 /index.html:「Page data, collected by sitespeed.io for page - http://www.ptt.cc/index.html」。

不過我更感興趣的是 PhantomJS,不知道可以做多少事情...

AWS EBS 的改善...

AWS EBSAmazon Web Services 平台上的永久性儲存空間 (一般開起來的空間在 crash 後會消失),不過 EBS 的效能 (速度與 IOPS) 一直讓大家很頭痛,要硬撐 IOPS 的方式是透過四個 EBS volume,上面用 mdadm 跑 RAID0...

這幾個禮拜 AWS 丟出了兩個方案出來,提供不同的選擇...

首先是帶大容量 SSD 空間的 instance,參考「AWS 推出高速 I/O 的 EC2 instance」,這對於 cache 類的應用相當適合...

而昨天則是介紹了 Provisioned IOPS 與 EBS-Optimized instances:「Fast Forward - Provisioned IOPS for EBS Volumes」。

Provisioned IOPS 是保障 IOPS 的機制,每個 volume 最高可以到 1000 IOPS。除了每 GB 的價錢比較高以外,另外每個保障的 IOPS 要再收 USD$0.1/month。(本來 EBS 的 I/O 費用還是要計算)

標準的 EBS 約提供 100 IOPS,這個 Provisioned IOPS 架構讓使用者要在上面衝 IOPS 變得更容易...

EBS-Optimized instances 是把 EBS 使用的頻寬獨立出來,目前只支援 m1.large、m1.xlarge 以及 m2.4xlarge 這三種,其中 m1.large 跑到 500Mbps (理論值 62.5MB/sec),後面兩種可以上 1Gbps (125MB/sec),使得服務與 I/O 的頻寬不會互相干擾到...

PHP 5.4

PHP 5.4 前幾天正式釋出了:「PHP 5.4.0 released!」,新增與改變了很多東西。

有些蠻值得注意的地方:

  • safe mode 與 magic quote 都消失了,升級後需要重新檢查 php.ini
  • array_combine(array(), array()) 不再傳回 FALSE 了,總算是傳回 array()
  • 可以用 [] 表示 array() 了。
  • function 傳回 array 後可以直接對 array 取值,也就是 foo()[0] 變合法語法了。
  • new 完後可以直接 call function 了,也就是 (new Foo)->bar() 變合法語法了。
  • 內建 web server。

另外記憶體使用量以及效能都有巨大的改善,尤其是對物件的 method 效能改善很多,這對 framework 是好消息。

不過應該還是等 5.4.1 之後再用吧,剛出來的這幾個版本應該有不少人會踩到地雷需要修正...

Firefox 11 將會支援 SPDY Protocol

Firefox 預定在 11 (現在是 8) 支援 SPDY Protocol:「(SPDY) Implement SPDY protocol」,除了 Google Chrome 自家瀏覽器支援外,總算有個大的也要支援了...

所以現在除了 Chrome、Kindle Fire 以外,又多了 Firefox 支援...

不過 ApacheF5 什麼時候會支援呢... mod-spdy 看起來... 呃...