# Database Deepdive
## 1. Database Connection Pool - Why and How
[圖片引用於此](http://peggg327.blogspot.com/2014/11/connection-pool.html)


### 什麼是 connection pool?
> a database connection cache implementation which can be configured to suit specific requirements
>
介於 db & client 中間的連線快取機制
### 為什麼要用?
因為建立資料庫連線是一件很貴又很花時間的事。
> By just simply implementing a database connection container, which allows us to reuse a number of existing connections, we can effectively save the cost of performing a huge number of expensive database trips, hence boosting the overall performance of our database-driven applications.
>
Persistent connection vs connection pooling
Object pool pattern
> 物件池(object pool pattern)是一種設計模式。一個物件池包含一組已經初始化過且可以使用的物件,而可以在有需求時創建和銷毀物件。池的用戶可以從池子中取得對象,對其進行操作處理,並在不需要時歸還給池子而非直接銷毀它。這是一種特殊的工廠物件。
>
> 若初始化、實例化的代價高,且有需求需要經常實例化,但每次實例化的數量較少的情況下,使用對象池可以獲得顯著的效能提升。從池子中取得對象的時間是可預測的,但新建一個實例所需的時間是不確定。
### 怎麼用?
直接看 Google 怎麼建 MySQL connection pool https://cloud.google.com/sql/docs/mysql/manage-connections
設定:
* Create pool
* Open / close connections
* Connection count
* ~~Exponential backoff~~ (The mysql module automatically uses exponential delays between failed connection attempts.)
* Connection timeout
* Connection timeout
* ~~Connection duration~~ (The 'mysql' Node.js library currently doesn't offer any functionality to control the duration of a connection.)
### CreatePool觀念:
[簡明教程:Pool 连接池](https://www.jmjc.tech/less/113)
用 createConnection 创建 Mysql 连接,每执行一次 connection.query 都是一个全新的连接,会造成一个资源的极大浪费,降低性能。
连接池是另外的一种执行方法,它一次性的创建了多个连接,然后根据客户端的查询,自动的 分发、复用、管理 这些连接。
```
const mysql = require('mysql')
// 链接池:创建多个链接、复用与分发链接
const pool = mysql.createPool({
host: '127.0.0.1',
port: '3306',
user: 'root',
password: ''
})
// 封装
query = function(sql,callback){
pool.getConnection(function(err,connection){
connection.query(sql,function(err,results){
callback(err, results) // 结果回调
connection.release() // 释放连接资源 | 跟 connection.destroy() 不同,它是销毁
})
}
})
}
// 随机分配一个连接
pool.query(sql, function (err, result) {
// ...
}
```
connectionLimit: 是針對client端的連線限制數量。创建连接池的方法是createPool(option),option里多了一个参数connectionLimit指的是一次性在连接池里创建多少个连接对象,默认10个。如果你想共享一个连接对象,可以使用pool.getConnection。
根據[github上 mysql模組](https://github.com/mysqljs/mysql#pool-options)的解釋:
> This is a shortcut for the pool.getConnection() -> connection.query() -> connection.release() code flow.
> Using pool.getConnection() is useful to share connection state for subsequent queries. This is because two calls to pool.query() may use two different connections and run in parallel.
### 何時用pool.query及何時用pool.getConnection
[參考tread](https://github.com/mysqljs/mysql/issues/1668)
>`getConnection` if you need transactions or some state between queries.
Reference:
[MySQL Doc - Connection Pooling with Connector/J](https://dev.mysql.com/doc/connector-j/8.0/en/connector-j-usagenotes-j2ee-concepts-connection-pooling.html)
[Wikipedia - Object pool pattern](https://en.wikipedia.org/wiki/Object_pool_pattern)
[MySQL - Persistent connection vs connection pooling
](https://stackoverflow.com/questions/9736188/mysql-persistent-connection-vs-connection-pooling)
[如何理解node链接mysql时使用连接池的connectionLimit(链接限制数)](https://cnodejs.org/topic/5787d38e3b501f7054983003)
[Github JDBC 入門](https://github.com/JustinSDK/JavaSE6Tutorial/blob/master/docs/CH20.md)
[Node连接mysql数据库方法](https://segmentfault.com/a/1190000007981124)
[簡明教程:Pool 连接池](https://www.jmjc.tech/less/113)
[連接池介紹](http://peggg327.blogspot.com/2014/11/connection-pool.html)
---
## 2. Database Normalization - Optimization Guidance
> 是指將原先關聯表格的所有資訊,在「分解」之後,仍能由數個新關
聯表格中經過「合併」得到相同的資訊。即所謂的「無損失分解」
(Lossless decomposition) 的觀念。
### 為何要正規化?
重複的資料佔資料庫儲存空間
要去除的問題:
* 資料冗餘 data redundancy
* 不一致的相依性 inconsistent dependency
沒有正規化易發生的異常們:
* 新增異常 (Insert Anomaly)
* 修改異常 (Update Anomaly)
* 刪除異常 (Delete Anomaly)
### 正規化方法
每一個階段都是以欄位的「相依性」, 做為分割資料表的依據之一。
NF = Normal Form

BCNF被視為大部分應用程式所需的最高階正規形式。
可以看這兩個表哪個比較有感(講的是一樣的東西):


### 正規化型式們
1. First Normal Form: 是指在資料表中的所有記錄之屬性內含值都是基元值 (Atomic Value),亦即無重覆項目群。沒有做1NF的話就必須要預留很大的空間給這某些欄位, 造成儲存空間的浪費。
- How? 將重複的資料項分別儲存到不同的記錄中, 並加上適當的主鍵。
- Before: sizes 欄位中有超過一個值

- After: sizes 拆開放

3. Second Normal Form: 每一非鍵屬性必須「完全相依」於主鍵;即不可「部分功能相依」(partial dependency)於主鍵。
- How? 如果有哪些資料只和一個鍵的一部份有關的話,就得把它們獨立出來變成另一個資料表。如果一個資料表的鍵只有單個欄位的話,它就一定符合第二正規化。
- stylish tables 都只有一個 PK,符合 2NF
5. Third Normal Form: 各欄位與「主鍵」之間沒有「遞移相依」(transitive dependency)的關係。
- How? :將「遞移相依」 的欄位「分割」出去,再另外組成「新的資料表」,並且利用外鍵(F.K.) 來連接二個資料表。
- Before: variant 表中 color_name 僅相依於 color_code, color_code 相依於 variantid (PK)

- After: 新增 color_object 表切出顏色對照,並將 variant 表中添加 FK color_id 做為對照
 
product 表把 sizes 交給 variant 表負責,精簡很多

7. BCNF: 是由Boyce和Codd於1974年所提出來的3NF的改良式。如果資料表的「主鍵」是由「多個欄位」組成的, 則必須再執行BoyceCodd 正規化。去除功能相依 (functional dependency)
- stylish tables 都只有一個 PK,符合 BCNF
* stylish 最後優化:拆出重複的 product_info
- Before:

- After:


* EER diagram (product related)

#### 過早優化是萬惡的根源
qps 可能降低
資料維護不易
### Reference
[Normalization of Database (有印度腔影片可看)](https://www.studytonight.com/dbms/database-normalization.php)
[維基:數據庫正規化](https://zh.wikipedia.org/wiki/%E6%95%B0%E6%8D%AE%E5%BA%93%E8%A7%84%E8%8C%83%E5%8C%96)
[資料庫正規劃:水果訂單範例](https://hackmd.io/@TSMI_E7ORNeP8YBbWm-lFA/rykcj8kmM?type=view)
[Cust.edu slides:學生課程老師範例](http://cc.cust.edu.tw/~ccchen/doc/db_04.pdf)
### Appendix
<!-- BCNF
- How?

- Reference: [正規化概述 slides](http://cs.sttlrc.kuas.edu.tw/pluginfile.php/6271/mod_resource/content/0/Ch06_%E6%AD%A3%E8%A6%8F%E5%8C%96%E6%A6%82%E8%BF%B0.pdf) -->
#### 2NF eg.
- Before: 訂單編號&商品名稱為主鍵

- After:

#### Fourth Normal Form: 去除多值相依
3NF 之後接下來有點玄。。。
Eg. 飯店提供的披薩種類與配貨地區無關,也即飯店為所有的供貨地區提供它能製作的所有披薩類型。那麼,這個表不滿足第四規格化。因為這個表在{Restaurant}屬性(它不是超鍵)上提供了兩個非平凡的多值依賴:
{Restaurant} -> {Pizza Variety}
{Restaurant} -> {Delivery Area}
- Before:

- After:

#### Fifth Normal Form: 去除連接依賴 (Join Dependency)
- How:

- Before:

- After:

- Reference: [第五正規劃](https://www.youtube.com/watch?v=mbj3HSK28Kk)