Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
資料庫索引數據結構及主鍵設計 (B+Tree)
Database index data structure and primary key design (part1)
2016
Ant
yftzeng@gmail.com
2016
2/129
自我介紹
♪ Muzik Online (www.muzikair.com) 總工程師。
♪ Paganini+ (http://www.paganiniplus.com/) 技術長。
♪ BELP (fb.com/bel...
2016
3/129
問題 1: UUID ?
Q: 資料庫 Primary key 使用 UUID 比較快?
Serial/Auto-Increment
1
2
3
4
5
...
UUID
3a5e439b-eeb4-4074-8b23-5...
4/129
2016
問題 1: UUID ?
Q: 資料庫 Primary key 使用 UUID 比較快?
偽命題
2016
5/129
問題 1 ( 修正 ): MySQL UUID ?
Q: MySQL 的 Primary key 使用 UUID 比較快?
Serial/Auto-Increment
1
2
3
4
5
...
UUID
3a5e439b...
6/129
2016
問題 1 ( 修正 ): MySQL UUID ?
Q: MySQL 的 Primary key 使用 UUID 比較快?
偽命題
7/129
2016
問題 1 ( 修正 ): MySQL UUID ?
UUID 目前公定有五種版本:
➀ Version 1 (MAC address & date-time)
➁ Version 2 (DCE Security)
➂ Ve...
8/129
2016
問題 1 ( 修正 ): MySQL UUID ?
UUID 目前公定有五種版本:
➀ Version 1 (MAC address & date-time)
➁ Version 2 (DCE Security)
➂ Ve...
9/129
2016
問題 1 ( 修正 ): MySQL UUID ?
UUID 目前公定有五種版本:
➀ Version 1 (MAC address & date-time)
➁ Version 2 (DCE Security)
➂ Ve...
10/129
2016
問題 1 ( 修正 ): MySQL UUID ?
UUID 類循序式 ( 通常後序產生的值 > 先前產生的值 ) :
➀ Version 1 (MAC address & date-time)
UUID 亂序式 ( 值...
11/129
2016
問題 1 ( 修正 ): MySQL UUID ?
UUIDv1 的範例:
2190718a-c7a3-61e2-aa34-024281ed9db5
2191f33e-c7a3-61e2-9b92-024281ed9db...
12/129
2016
問題 1 ( 修正 ): MySQL UUID ?
UUIDv4 的範例:
3a5e439b-eeb4-4074-8b23-51c2cdd35421
1bb19e6b-9c0c-475e-a7b3-f01a6b4cd49...
13/129
2016
問題 1 ( 修正 ): MySQL UUID ?
結論: UUID 可以是類循序式,也可以是亂序式。
但《循序式》與《亂序式》的重要性為何?
14/129
2016
問題 1 ( 修正 ): MySQL UUID ?
Ref: https://www.percona.com/blog/2014/12/19/store-uuid-optimized-way/
15/129
2016
問題 1 ( 修正 ): MySQL UUID ?
延伸 : GUID 與 UUID 的差異?
16/129
2016
問題 1 ( 修正 ): MySQL UUID ?
GUID 是 Microsoft 用詞,指的其實類似於 UUID ,
但實作方式不一樣。
Microsoft 對於 GUID 的實作至少有兩種:
➀ 基於 UuidCr...
2016
17/129
索引數據結構
18/129
2016
索引數據結構 : 無索引
目的:尋找【欄位一為 5 的資料】
操作: 5 , O(n)
缺點:總是需要全表掃描
資料表:
1 user1 pass1
2 user2 pass2
3 user3 pass3
4 user4...
19/129
2016
索引數據結構 : B-tree 索引
B-tree = Balanced tree (not Binary tree)
20/129
2016
索引數據結構 : B-tree 索引
目的:尋找【欄位一為 5 的資料】
操作: 4 , O(logbn)
缺點:全表掃描需要遍歷樹
資料表:
1 user1 pass1
2 user2 pass2
3 user3 pa...
21/129
2016
索引數據結構 : B+tree 索引
目的:尋找【欄位一為 5 的資料】
優點:全表掃描不需遍歷樹
資料表:
1 user1 pass1
2 user2 pass2
3 user3 pass3
4 user4 pass4...
22/129
2016
索引數據結構 : B+tree 索引
目的:尋找【欄位一為 5 的資料】
操作: 4 , O(logbn)
優點:全表掃描不需遍歷樹
資料表:
1 user1 pass1
2 user2 pass2
3 user3 pa...
2016
23/129
問題 2: B+tree
Q: 哪些資料庫索引數據結構支援 B+tree ?
MySQL
Oracle
Microsoft SQL Server
PostgreSQL
MongoDB
CouchDB
LevelDB
Ro...
24/129
2016
問題 2: B+tree
Q: 哪些資料庫索引數據結構支援 B+tree ?
MySQL
Oracle
Microsoft SQL Server
PostgreSQL
MongoDB
CouchDB
LevelDB
Ro...
2016
25/129
索引頁分裂
26/129
2016
索引頁分裂
觸發:頁剩餘空間 - 保留空間 < 新增資料
問題:頁分裂時會 Latch( 小鎖 )
page
page page
latch
page
27/129
2016
索引頁分裂 : 循序式新增資料
操作:新增 25( 假設頁只能存三筆資料 )
9 18
21 24
19 20 21 22 23 24
25
p1
p10
p12p11
9 18
21 24 25
19 20 21 22...
28/129
2016
索引頁分裂 : 亂序式新增資料
操作:新增 5( 假設頁只能存三筆資料 )
20
6 12
2 4 6 8 10 12
5
20
4 6 12
2 4 5 6 8 10 12
p1 p1
p2 p2
p4p3 p3 p4...
29/129
2016
索引頁分裂 : 亂序式新增資料
Ref: http://blogs.catapultsystems.com/rnewkirk/archive/2013/05/14/sql-fragmentation-explained/
30/129
2016
索引頁分裂 : I/O 與 Page Size
資料庫 I/O 以 Page 為單位。
儲存引擎的 Page Size :
➊ PostgreSQL 8KB
➋ MySQL/InnoDB 16KB(default)
➌ ...
31/129
2016
索引頁分裂 : 循序式新增 I/O
9 18
21 24 25
19 20 21 22 23 24
25
p1
p10
p12p11
25
p13
latch
latch
Block N+1 Block N+2 Bloc...
32/129
2016
索引頁分裂 : 循序式新增 I/O
如果 Page Size 比較大?
Block N+1 Block N+2 Block N+3 p11 p12 p13p10
I/O
Block N+1 Block N+2 p13p1...
33/129
2016
索引頁分裂 : 亂序式新增 I/O
Block N+3 Block N+4
I/O
p2 p3 p4p1 # # #p5
20
6 12
2 4 6 8 10 12
20
4 6 12
2 4 5 6 8 10 12
p...
34/129
2016
索引頁分裂 : 亂序式新增 I/O
如果 Page Size 比較大?
Block N+4p4p3p2p1
I/OI/O
Block N+3 Block N+4
I/O
p2 p3 p4p1 # # #p5
I/O
#p...
2016
35/129
索引子頁結構
36/129
2016
索引子頁結構 : Non-clustered index
以 B+tree 為例
特色:子頁不包括資料本身 ( 指針指向資料 )
補充:對應的資料表稱 Heap table
資料表:循序式
1 user1 pass1
2...
37/129
2016
索引子頁結構 : Non-clustered index
如果不是《循序式》而是《亂序式》。
資料表:亂序式
1 user1 pass1
4 user4 pass4
5 user5 pass5
2 user2 pass2...
38/129
2016
索引子頁結構 : Clustered index
以 B+tree 為例
特色:子頁包括資料本身 ( 不需指針指向資料 )
補充:對應的資料表稱 Index Organized Table(IOT)
資料表:循序式與亂序...
39/129
2016
Non-clustered index(Heap table)
循序式
➀ 有索引指針指向資料的額外開銷。
➁ Hotspot 發生在樹最右下的頁,但循序寫及合併寫機率高。
➂ Range scan 讀取時開銷大。
亂序...
40/129
2016
索引子頁結構 : Clustered index
Clustered index(IOT)
循序式
➀ 資料佔頁空間,頁存放的資料量少,頁分裂頻繁。
➁ 搜尋至頁索引時,因包括資料本身,無額外指針開銷。
➂ Hotspo...
41/129
2016
索引子頁結構 : Clustered index
Q: 循序式 / 亂序式 vs. I/O Scheduler vs. Filesystem vs. HDD / Flash / Fusion IO ?
循序式
亂序式
C...
2016
42/129
Range scan
43/129
2016
Range scan
>, <, >=, <=
BETWEEN, IN
GROUP BY with max, min, count
44/129
2016
Range scan: Heap table w/ 循序式
SELECT * FROM x WHERE y BETWEEN 1 AND 7;
1 user1 pass1
2 user2 pass2
3 user3 pas...
45/129
2016
Range scan: Heap table w/ 亂序式
SELECT * FROM x WHERE y BETWEEN 1 AND 7;
1 user1 pass1
4 user4 pass4
5 user5 pas...
46/129
2016
Range scan: Heap table w/ 亂序式
I/O
p5 p7 p3 p6
I/O I/OI/O
p1 # p2 p4...
Ref: http://etutorials.org/SQL/Postgres...
47/129
2016
Range scan: IOT w/ 循序式 & 亂序式
SELECT * FROM x WHERE y BETWEEN 1 AND 7;
13
4 7
1 2 3 4 5 6 7
1 user1 pass1
2 use...
2016
48/129
問題 3
Q: 哪些資料庫支援 Heap table ?哪些支援 IOT ?
MySQL
Oracle
Microsoft SQL Server
PostgreSQL
MongoDB
CouchDB
49/129
2016
問題 3
Heap table IOT
MySQL/MyISAM O X
MySQL/InnoDB X O
Oracle O O
Microsoft SQL Server O O
PostgreSQL O X
Mongo...
50/129
2016
問題 3
Q: 選什麼資料庫比較好?
是個偽命題,需視你的場景而定。
2016
51/129
特別篇 1: MySQL 生態系
Q: MySQL 生態系, MySQL / Percona / MariaDB /
WebScaleSQL 該怎麼選擇?
52/129
2016
特別篇 1: MySQL 生態系
MySQL
➀ 官方,有 Oracle 技術支持及專利保護。
➁ 最新的 MySQL 5.7 擁有大量新特性。
➂ 商業因素預設不會接受其他分支的特性。
Percona
➀ drop-i...
53/129
2016
特別篇 1: MySQL 生態系
MariaDB
➀ drop-in replacement for (official) MySQL 。
➁ MariaDB 10 基於 MySQL 5.6 ,但不相容 5.7 。
➂ ...
54/129
2016
特別篇 1: MySQL 生態系
MySQL 5.7 解決了 index→lock contention 問題。
2016
55/129
特別篇 2: PostgreSQL
PostgreSQL 是 Object-relational database
56/129
2016
特別篇 2: PostgreSQL (Fusion IO)
Fusion IO 可大幅排除 IO Bottlenect 的可能性。
57/129
2016
特別篇 2: PostgreSQL (Fusion IO)
Fusion IO 只特別支援 Oracle / MySQL / Percona / MariaDB ?
Ref: https://www.sandisk.co...
58/129
2016
特別篇 2: PostgreSQL (Fusion IO)
Fusion IO 可讓 MySQL 免除 double write 。
Ref: https://www.sandisk.com/business/datac...
59/129
2016
特別篇 2: PostgreSQL (Fragmentation)
PostgreSQL(HOT) 天性無法避免 fragmentation 。
Ref: http://etutorials.org/SQL/Postgr...
60/129
2016
特別篇 2: PostgreSQL (Index Bloat)
PostgreSQL(non HOT updates) 天性無法避免 index bloat 。
Ref: PostgreSQL 9.0 High Perf...
61/129
2016
特別篇 2: PostgreSQL (Index Bloat)
62/129
2016
特別篇 2: PostgreSQL (Index Bloat)
63/129
2016
特別篇 2: PostgreSQL (Merge IO)
PostgreSQL 沒有類似 MySQL 的 Change Buffer 。
Ref: http://www.slideshare.net/morgo/inno...
64/129
2016
特別篇 2: PostgreSQL (Merge IO)
MySQL Insert Buffering( 現在改名 Change Buffer) :
1. Reducing the number of disk i/o ...
65/129
2016
特別篇 2: PostgreSQL (Merge IO)
66/129
2016
特別篇 2: PostgreSQL ( 儲存引擎 )
Microsoft SQL Server / Oracle 支援 Heap table 及 IOT ,
可依各資料表的特性分別採用。
MySQL 及 MongoDB ...
2016
67/129
特別篇 3: MongoDB
68/129
2016
特別篇 3: MongoDB
Ref: http://itindex.net/detail/43573
69/129
2016
特別篇 3: MongoDB
Ref: http://sql-vs-nosql.blogspot.tw/2013/11/indexes-comparison-mongodb-vs-mssqlserver.html
70/129
2016
特別篇 3: MongoDB
Ref: http://learnmongodbthehardway.com/schema/chapter4/
B+Tree / Heap Table
71/129
2016
特別篇 3: MongoDB
Ref: Indexing and Performance Tuning (2015-11-03).pdf (p39)
72/129
2016
特別篇 3: MongoDB
Index
➀ ”統一命名為 _id”
➁ ”新增若未指定 _id” 值,會使用 ObjectId
➂ ObjectId 為 12-byte BSON 型態
➊ 4-byte 為 UNIX ...
73/129
2016
特別篇 3: MongoDB
MMAPv1 儲存引擎
➀ Memory-mapped files
Ref: http://learnmongodbthehardway.com/schema/chapter3/
74/129
2016
特別篇 3: MongoDB
MMAPv1 儲存引擎
➀ Memory-mapped files
➁ Padding
Ref: http://learnmongodbthehardway.com/schema/chapt...
75/129
2016
特別篇 3: MongoDB
MMAPv1 儲存引擎
➀ Memory-mapped files
➁ Padding
➂ Fragmentation
Ref: http://learnmongodbthehardway....
76/129
2016
特別篇 3: MongoDB
MMAPv1 儲存引擎
➀ Memory-mapped files
➁ Padding
➂ Fragmentation
➃ Collection-level locking (WiredTi...
77/129
2016
特別篇 3: MongoDB
MMAPv1 儲存引擎
➀ Memory-mapped files
➁ Padding
➂ Fragmentation
➃ Collection-level locking (WiredTi...
78/129
2016
特別篇 3: MongoDB
MMAPv1 的 Fragmentation 問題
Ref: http://www.slideshare.net/mongodb/7-managing-a-maturing-mongo-db...
79/129
2016
特別篇 3: MongoDB
MMAPv1 的 Fragmentation 問題
動作:連續新增 5 個 Document
Collection :
{Document 1}
{Document 2}
{Document...
80/129
2016
特別篇 3: MongoDB
MMAPv1 的 Fragmentation 問題
動作:更新 Document 3
情況一:新的 Document 3 大小 <= 原先大小
Collection :
{Document ...
81/129
2016
特別篇 3: MongoDB
MMAPv1 的 Fragmentation 問題
動作:更新 Document 3
情況二:新的 Document 3 大小 > 原先大小
Collection :
{Document 1...
82/129
2016
特別篇 3: MongoDB
MMAPv1 的 Fragmentation 問題
動作:新增 Document 6
Collection :
{Document 1}
{Document 2}
Free
{Documen...
83/129
2016
特別篇 3: MongoDB
MMAPv1 的 Fragmentation 問題
動作:新增 Document 6
情況一: Document 6 大小 <= 原先 Document 3 (Free) 大小
Collec...
84/129
2016
特別篇 3: MongoDB
MMAPv1 的 Fragmentation 問題
動作:新增 Document 6
情況二: Document 6 大小 > 原先 Document 3 (Free) 大小
Collect...
85/129
2016
特別篇 3: MongoDB
特色與改善
➀ Sharding/Replica 較容易
( 但 Sharding/Replica 只有 Primary 可寫 )
➁ Dynamic schema ( 不是 Schemal...
86/129
2016
特別篇 3: MongoDB
特色與改善
➃ 寫入的 Locking level 改善
2.2 版前, Process-level lock ,一個 Mongod 實例一個鎖
2.8 版前, Database-level...
87/129
2016
特別篇 3: MongoDB
特色與改善
➄ 支援 MapReduce
2.4 版前,使用 SpiderMonkey ,是 single threaded
2.4 版之後,改用 V8 engine ,改善問題
➅ Sin...
2016
88/129
特別篇 4: RDMBS or NoSQL ?
Q: 使用 RDBMS 還是 NoSQL ?
89/129
2016
特別篇 4: RDMBS or NoSQL ?
Q: 使用 RDBMS 還是 NoSQL ?
是個偽命題,需視你的場景而定。
90/129
2016
特別篇 4: RDMBS or NoSQL ?
不過 RDBMS 及 NoSQL 的分界會愈來愈小。
過去的一些 RDBMS 已開始支援 NoSQL 特性,
Microsoft SQL Server / Oracle /...
91/129
2016
特別篇 4: RDMBS or NoSQL ?
不過 RDBMS 及 NoSQL 的分界會愈來愈小。
過去的一些 RDBMS 已開始支援 NoSQL 特性,
Microsoft SQL Server / Oracle /...
2016
92/129
特別篇 5: 黑暗執行緒案例
Q: 試著分析黑暗執行緒的文章。
【 GUID Primary Key 資料庫避雷守則】
Ref: http://blog.darkthread.net/post-2016-01-29-gu...
93/129
2016
特別篇 5: 黑暗執行緒案例
以架構設計而言,我更傾向讓應用伺服器決定 GUID / UUID 的值,
理由有幾個。
➊ 未來若需要異質資料庫彼此交換資料, GUID / UUID 的衝突會
更小。例如若 SQL Ser...
94/129
2016
特別篇 5: 黑暗執行緒案例
➌ 應用伺服器脫離 SQL Server 後,就無法使用 NEWID 及
NEWSEQUENTIALID ,所以需要找 UUID 產生器。 UUID 產生器有
幾種版本, UUIDv1 是類...
95/129
2016
特別篇 5: 黑暗執行緒案例
黑暗執行緒提供的表設計建議
96/129
2016
特別篇 5: 黑暗執行緒案例
黑暗執行緒提供的表設計建議
4c.. cb.. ee..
07.. 3b.. 4c.. 5b.. 9e.. cb.. ee..
Clustered Index ( 循序式 )
Nonclus...
97/129
2016
98/129
2016
特別篇 5: 黑暗執行緒案例
假設已有五筆資料
5b.. cb..
07.. 3b.. 5b.. 9e.. cb..
3 5
1 2 3 4 5
[SeqNo] [FlowId] ...
1 07.. ...
2 9e....
99/129
2016
特別篇 5: 黑暗執行緒案例
尋找【 WHERE FlowId = “5b..” 】
IO 次數: 0
5b.. cb..
07.. 3b.. 5b.. 9e.. cb..
3 5
1 2 3 4 5
[SeqNo] [...
100/129
2016
特別篇 5: 黑暗執行緒案例
尋找【 WHERE FlowId = “5b..” 】
IO 次數: 1
5b.. cb..
07.. 3b.. 5b.. 9e.. cb..
3 5
1 2 3 4 5
[SeqNo] ...
101/129
2016
特別篇 5: 黑暗執行緒案例
尋找【 WHERE FlowId = “5b..” 】
IO 次數: 2
5b.. cb..
07.. 3b.. 5b.. 9e.. cb..
3 5
1 2 3 4 5
[SeqNo] ...
102/129
2016
特別篇 5: 黑暗執行緒案例
尋找【 WHERE FlowId = “5b..” 】
IO 次數: 3
5b.. cb..
07.. 3b.. 5b.. 9e.. cb..
3 5
1 2 3 4 5
[SeqNo] ...
103/129
2016
特別篇 5: 黑暗執行緒案例
尋找【 WHERE FlowId = “5b..” 】
IO 次數: 4 ( 完成 )
5b.. cb..
07.. 3b.. 5b.. 9e.. cb..
3 5
1 2 3 4 5
[...
104/129
2016
特別篇 5: 黑暗執行緒案例
新增【 SeqNo: 6, FlowID: 4c.. 】
IO 次數: 0
5b.. cb..
07.. 3b.. 5b.. 9e.. cb..
3 5
1 2 3 4 5
[SeqNo]...
105/129
2016
特別篇 5: 黑暗執行緒案例
新增【 SeqNo: 6, FlowID: 4c.. 】
IO 次數: 1
5b.. cb..
07.. 3b.. 5b.. 9e.. cb..
3 5
1 2 3 4 5
[SeqNo]...
106/129
2016
特別篇 5: 黑暗執行緒案例
新增【 SeqNo: 6, FlowID: 4c.. 】
IO 次數: 2
5b.. cb..
07.. 3b.. 5b.. 9e.. cb..
3 5
1 2 3 4 5
[SeqNo]...
107/129
2016
特別篇 5: 黑暗執行緒案例
新增【 SeqNo: 6, FlowID: 4c.. 】
IO 次數: 3+3
Page Split 次數: 1
3 5
1 2 3 4 5
[SeqNo] [FlowId] ...
1 ...
108/129
2016
特別篇 5: 黑暗執行緒案例
新增【 SeqNo: 6, FlowID: 4c.. 】
IO 次數: 3+3+1
Page Split 次數: 1
3 5
1 2 3 4 5
[SeqNo] [FlowId] ...
...
109/129
2016
特別篇 5: 黑暗執行緒案例
新增【 SeqNo: 6, FlowID: 4c.. 】
IO 次數: 3+3+2
Page Split 次數: 1
3 5
1 2 3 4 5
[SeqNo] [FlowId] ...
...
110/129
2016
特別篇 5: 黑暗執行緒案例
新增【 SeqNo: 6, FlowID: 4c.. 】
IO 次數: 3+3+3
Page Split 次數: 1
3 5
1 2 3 4 5 6
[SeqNo] [FlowId] .....
111/129
2016
特別篇 5: 黑暗執行緒案例
新增【 SeqNo: 6, FlowID: 4c.. 】
IO 次數: 3+3+4=10 ( 完成 )
Page Split 次數: 1
07.. 3b.. 4c.. 5b..
3 6
1...
112/129
2016
特別篇 5: 黑暗執行緒案例
如果用一般亂序式 UUID
[FlowId] ... ...
07.. ... ...
9e.. ... ...
3b.. ... ...
cb.. ... ...
5b.. ... .....
113/129
2016
特別篇 5: 黑暗執行緒案例
尋找【 WHERE FlowId = “5b..” 】
IO 次數: 0
[FlowId] ... ...
07.. ... ...
9e.. ... ...
3b.. ... ...
c...
114/129
2016
特別篇 5: 黑暗執行緒案例
尋找【 WHERE FlowId = “5b..” 】
IO 次數: 1
[FlowId] ... ...
07.. ... ...
9e.. ... ...
3b.. ... ...
c...
115/129
2016
特別篇 5: 黑暗執行緒案例
尋找【 WHERE FlowId = “5b..” 】
IO 次數: 2 ( 完成 )
[FlowId] ... ...
07.. ... ...
9e.. ... ...
3b.. .....
116/129
2016
特別篇 5: 黑暗執行緒案例
新增【 FlowID: 4c.. 】
IO 次數: 0
[FlowId] ... ...
07.. ... ...
9e.. ... ...
3b.. ... ...
cb.. ... ....
117/129
2016
特別篇 5: 黑暗執行緒案例
新增【 FlowID: 4c.. 】
IO 次數: 1
[FlowId] ... ...
07.. ... ...
9e.. ... ...
3b.. ... ...
cb.. ... ....
118/129
2016
特別篇 5: 黑暗執行緒案例
新增【 FlowID: 4c.. 】
IO 次數: 2
[FlowId] ... ...
07.. ... ...
9e.. ... ...
3b.. ... ...
cb.. ... ....
119/129
2016
特別篇 5: 黑暗執行緒案例
新增【 FlowID: 4c.. 】
IO 次數: 3+3 ( 完成 )
Page Split 次數: 1
[FlowId] ... ...
07.. ... ...
9e.. ... ....
120/129
2016
特別篇 5: 黑暗執行緒案例
如果用一般循序式 UUID
[FlowId] ... ...
1 ... ...
2 ... ...
3 ... ...
4 ... ...
5 ... ...
3 5
1 2 3 4 5...
121/129
2016
特別篇 5: 黑暗執行緒案例
尋找【 WHERE FlowId = 5 】
IO 次數: 0
[FlowId] ... ...
1 ... ...
2 ... ...
3 ... ...
4 ... ...
5 ......
122/129
2016
特別篇 5: 黑暗執行緒案例
尋找【 WHERE FlowId = 5 】
IO 次數: 1
[FlowId] ... ...
1 ... ...
2 ... ...
3 ... ...
4 ... ...
5 ......
123/129
2016
特別篇 5: 黑暗執行緒案例
尋找【 WHERE FlowId = 5 】
IO 次數: 2 ( 完成 )
[FlowId] ... ...
1 ... ...
2 ... ...
3 ... ...
4 ... .....
124/129
2016
特別篇 5: 黑暗執行緒案例
新增【 FlowID: 6 】
IO 次數: 0
[FlowId] ... ...
1 ... ...
2 ... ...
3 ... ...
4 ... ...
5 ... ...
6 ...
125/129
2016
特別篇 5: 黑暗執行緒案例
新增【 FlowID: 6 】
IO 次數: 1
[FlowId] ... ...
1 ... ...
2 ... ...
3 ... ...
4 ... ...
5 ... ...
6 ...
126/129
2016
特別篇 5: 黑暗執行緒案例
新增【 FlowID: 6 】
IO 次數: 2
[FlowId] ... ...
1 ... ...
2 ... ...
3 ... ...
4 ... ...
5 ... ...
6 ...
127/129
2016
特別篇 5: 黑暗執行緒案例
新增【 FlowID: 6 】
IO 次數: 3+1 ( 完成 )
[FlowId] ... ...
1 ... ...
2 ... ...
3 ... ...
4 ... ...
5 ....
128/129
2016
特別篇 5: 黑暗執行緒案例
小結:本場景為例
黑暗執行緒 亂序式 UUID 循序式 UUID
Point-of-query IO 4 2 2
Insert IO 10 6 4
Insert
(Page Split)
...
129/129
2016
特別篇 6: MultiColumn B-Tree Index
[Col#1] [Col#2]
1 A
3 B
3 C
4 D
3 C
CREATE INDEX ON table (Col#1, Col#2);
1 A...
Upcoming SlideShare
Loading in …5
×

資料庫索引數據結構及主鍵設計(b+tree)(part 1)

8,689 views

Published on

* UUID / GUID?
* 主鍵使用 UUID 真的比較好?
* 常見索引數據結構。
* 什麼是索引頁分裂?
* 案例探討。

題目很宅也看似簡單,但若弄通,RDBMS 到 NoSQL 再到 NewSQL 的核心概念之一就通了。對於一般人而言,也會打破過去舊有索引的概念。

Published in: Engineering
  • Be the first to comment

資料庫索引數據結構及主鍵設計(b+tree)(part 1)

  1. 1. 資料庫索引數據結構及主鍵設計 (B+Tree) Database index data structure and primary key design (part1) 2016 Ant yftzeng@gmail.com
  2. 2. 2016 2/129 自我介紹 ♪ Muzik Online (www.muzikair.com) 總工程師。 ♪ Paganini+ (http://www.paganiniplus.com/) 技術長。 ♪ BELP (fb.com/belp.general) 共同創辦人。 ♪ CHROOT (www.chroot.org) 成員。 ♪ 講師經驗 PHPConf, Modern Web Taiwan, MOPCON, WebConf, COSCUP, JSDC Taiwan, DrupalCamp Taiwan, OSDC, HITCON, ... ♪ 略懂智慧財產權、資訊安全及軟體程式設計。 ♪ 『略懂諸葛』。 ♪ 沉浸於『人性』、『法律』與『科技』的三角關係中。
  3. 3. 2016 3/129 問題 1: UUID ? Q: 資料庫 Primary key 使用 UUID 比較快? Serial/Auto-Increment 1 2 3 4 5 ... UUID 3a5e439b-eeb4-4074-8b23-51c2cdd35421 1bb19e6b-9c0c-475e-a7b3-f01a6b4cd496 af4c8b80-4bf5-4bf3-a4e3-a71bed920f10 e62acb5b-a393-4707-9aa5-90f79352eb4b 2e199d72-4e49-4ace-a504-419da63878f5 ...
  4. 4. 4/129 2016 問題 1: UUID ? Q: 資料庫 Primary key 使用 UUID 比較快? 偽命題
  5. 5. 2016 5/129 問題 1 ( 修正 ): MySQL UUID ? Q: MySQL 的 Primary key 使用 UUID 比較快? Serial/Auto-Increment 1 2 3 4 5 ... UUID 3a5e439b-eeb4-4074-8b23-51c2cdd35421 1bb19e6b-9c0c-475e-a7b3-f01a6b4cd496 af4c8b80-4bf5-4bf3-a4e3-a71bed920f10 e62acb5b-a393-4707-9aa5-90f79352eb4b 2e199d72-4e49-4ace-a504-419da63878f5 ...
  6. 6. 6/129 2016 問題 1 ( 修正 ): MySQL UUID ? Q: MySQL 的 Primary key 使用 UUID 比較快? 偽命題
  7. 7. 7/129 2016 問題 1 ( 修正 ): MySQL UUID ? UUID 目前公定有五種版本: ➀ Version 1 (MAC address & date-time) ➁ Version 2 (DCE Security) ➂ Version 3 (MD5 hash & namespace) ➃ Version 4 (Random) ➄ Version 5 (SHA-1 hash & namespace) Ref: https://en.wikipedia.org/wiki/Universally_unique_identifier
  8. 8. 8/129 2016 問題 1 ( 修正 ): MySQL UUID ? UUID 目前公定有五種版本: ➀ Version 1 (MAC address & date-time) ➁ Version 2 (DCE Security) ➂ Version 3 (MD5 hash & namespace) ➃ Version 4 (Random) ➄ Version 5 (SHA-1 hash & namespace) Ref: https://en.wikipedia.org/wiki/Universally_unique_identifier Version 2 未在 UUID 規格中定義,少見
  9. 9. 9/129 2016 問題 1 ( 修正 ): MySQL UUID ? UUID 目前公定有五種版本: ➀ Version 1 (MAC address & date-time) ➁ Version 2 (DCE Security) ➂ Version 3 (MD5 hash & namespace) ➃ Version 4 (Random) ➄ Version 5 (SHA-1 hash & namespace) Ref: https://en.wikipedia.org/wiki/Universally_unique_identifier
  10. 10. 10/129 2016 問題 1 ( 修正 ): MySQL UUID ? UUID 類循序式 ( 通常後序產生的值 > 先前產生的值 ) : ➀ Version 1 (MAC address & date-time) UUID 亂序式 ( 值的大小沒有前後關係 ) : ➂ Version 3 (MD5 hash & namespace) ➃ Version 4 (Random) ➄ Version 5 (SHA-1 hash & namespace)
  11. 11. 11/129 2016 問題 1 ( 修正 ): MySQL UUID ? UUIDv1 的範例: 2190718a-c7a3-61e2-aa34-024281ed9db5 2191f33e-c7a3-61e2-9b92-024281ed9db5 2192cc0a-c7a3-61e2-be4c-024281ed9db5 21939950-c7a3-61e2-9aad-024281ed9db5 21945ff2-c7a3-61e2-90fc-024281ed9db5 219525f4-c7a3-61e2-99df-024281ed9db5 Time
  12. 12. 12/129 2016 問題 1 ( 修正 ): MySQL UUID ? UUIDv4 的範例: 3a5e439b-eeb4-4074-8b23-51c2cdd35421 1bb19e6b-9c0c-475e-a7b3-f01a6b4cd496 af4c8b80-4bf5-4bf3-a4e3-a71bed920f10 e62acb5b-a393-4707-9aa5-90f79352eb4b 2e199d72-4e49-4ace-a504-419da63878f5 8cf2e49f-8ae9-43f2-a84d-78cb323114a3 Time
  13. 13. 13/129 2016 問題 1 ( 修正 ): MySQL UUID ? 結論: UUID 可以是類循序式,也可以是亂序式。 但《循序式》與《亂序式》的重要性為何?
  14. 14. 14/129 2016 問題 1 ( 修正 ): MySQL UUID ? Ref: https://www.percona.com/blog/2014/12/19/store-uuid-optimized-way/
  15. 15. 15/129 2016 問題 1 ( 修正 ): MySQL UUID ? 延伸 : GUID 與 UUID 的差異?
  16. 16. 16/129 2016 問題 1 ( 修正 ): MySQL UUID ? GUID 是 Microsoft 用詞,指的其實類似於 UUID , 但實作方式不一樣。 Microsoft 對於 GUID 的實作至少有兩種: ➀ 基於 UuidCreate 的 NEWID(SQL) ; ➁ 基於 UuidCreateSequential 的 NEWSEQUENTIALID(SQL) 。 其中 NEWID 是亂序式,而 NEWSEQUENTIALID 是循序式。
  17. 17. 2016 17/129 索引數據結構
  18. 18. 18/129 2016 索引數據結構 : 無索引 目的:尋找【欄位一為 5 的資料】 操作: 5 , O(n) 缺點:總是需要全表掃描 資料表: 1 user1 pass1 2 user2 pass2 3 user3 pass3 4 user4 pass4 5 user5 pass5
  19. 19. 19/129 2016 索引數據結構 : B-tree 索引 B-tree = Balanced tree (not Binary tree)
  20. 20. 20/129 2016 索引數據結構 : B-tree 索引 目的:尋找【欄位一為 5 的資料】 操作: 4 , O(logbn) 缺點:全表掃描需要遍歷樹 資料表: 1 user1 pass1 2 user2 pass2 3 user3 pass3 4 user4 pass4 5 user5 pass5 8 3 6 1 2 4 5 7
  21. 21. 21/129 2016 索引數據結構 : B+tree 索引 目的:尋找【欄位一為 5 的資料】 優點:全表掃描不需遍歷樹 資料表: 1 user1 pass1 2 user2 pass2 3 user3 pass3 4 user4 pass4 5 user5 pass5 13 4 7 1 2 3 4 5 6 7
  22. 22. 22/129 2016 索引數據結構 : B+tree 索引 目的:尋找【欄位一為 5 的資料】 操作: 4 , O(logbn) 優點:全表掃描不需遍歷樹 資料表: 1 user1 pass1 2 user2 pass2 3 user3 pass3 4 user4 pass4 5 user5 pass5 13 4 7 1 2 3 4 5 6 7 13 b
  23. 23. 2016 23/129 問題 2: B+tree Q: 哪些資料庫索引數據結構支援 B+tree ? MySQL Oracle Microsoft SQL Server PostgreSQL MongoDB CouchDB LevelDB RocksDB HBase Cassandra Riak NessDB BoltDB TokuDB Aerospike Couchbase
  24. 24. 24/129 2016 問題 2: B+tree Q: 哪些資料庫索引數據結構支援 B+tree ? MySQL Oracle Microsoft SQL Server PostgreSQL MongoDB CouchDB LevelDB RocksDB HBase Cassandra Riak NessDB BoltDB TokuDB Aerospike Couchbase
  25. 25. 2016 25/129 索引頁分裂
  26. 26. 26/129 2016 索引頁分裂 觸發:頁剩餘空間 - 保留空間 < 新增資料 問題:頁分裂時會 Latch( 小鎖 ) page page page latch page
  27. 27. 27/129 2016 索引頁分裂 : 循序式新增資料 操作:新增 25( 假設頁只能存三筆資料 ) 9 18 21 24 19 20 21 22 23 24 25 p1 p10 p12p11 9 18 21 24 25 19 20 21 22 23 24 p1 p10 p12p11 25 p13 latch latch hotspot
  28. 28. 28/129 2016 索引頁分裂 : 亂序式新增資料 操作:新增 5( 假設頁只能存三筆資料 ) 20 6 12 2 4 6 8 10 12 5 20 4 6 12 2 4 5 6 8 10 12 p1 p1 p2 p2 p4p3 p3 p4p5 latch fragmentation fragmentation
  29. 29. 29/129 2016 索引頁分裂 : 亂序式新增資料 Ref: http://blogs.catapultsystems.com/rnewkirk/archive/2013/05/14/sql-fragmentation-explained/
  30. 30. 30/129 2016 索引頁分裂 : I/O 與 Page Size 資料庫 I/O 以 Page 為單位。 儲存引擎的 Page Size : ➊ PostgreSQL 8KB ➋ MySQL/InnoDB 16KB(default) ➌ MongoDB/MMAPv1 dynamic (powered by 2) ➍ MongoDB/WiredTiger 32KB(default) ➎ Percona/TokuDB 64KB(default)
  31. 31. 31/129 2016 索引頁分裂 : 循序式新增 I/O 9 18 21 24 25 19 20 21 22 23 24 25 p1 p10 p12p11 25 p13 latch latch Block N+1 Block N+2 Block N+3 p11 p12 p13p10 I/O hotspot? hotspot
  32. 32. 32/129 2016 索引頁分裂 : 循序式新增 I/O 如果 Page Size 比較大? Block N+1 Block N+2 Block N+3 p11 p12 p13p10 I/O Block N+1 Block N+2 p13p12p11p10 I/OI/O
  33. 33. 33/129 2016 索引頁分裂 : 亂序式新增 I/O Block N+3 Block N+4 I/O p2 p3 p4p1 # # #p5 20 6 12 2 4 6 8 10 12 20 4 6 12 2 4 5 6 8 10 12 p1 p1 p2 p2 p4p3 p3 p4p5 latch I/O 5
  34. 34. 34/129 2016 索引頁分裂 : 亂序式新增 I/O 如果 Page Size 比較大? Block N+4p4p3p2p1 I/OI/O Block N+3 Block N+4 I/O p2 p3 p4p1 # # #p5 I/O #p5 I/O
  35. 35. 2016 35/129 索引子頁結構
  36. 36. 36/129 2016 索引子頁結構 : Non-clustered index 以 B+tree 為例 特色:子頁不包括資料本身 ( 指針指向資料 ) 補充:對應的資料表稱 Heap table 資料表:循序式 1 user1 pass1 2 user2 pass2 3 user3 pass3 4 user4 pass4 5 user5 pass5 13 4 7 1 2 3 4 5 6 7
  37. 37. 37/129 2016 索引子頁結構 : Non-clustered index 如果不是《循序式》而是《亂序式》。 資料表:亂序式 1 user1 pass1 4 user4 pass4 5 user5 pass5 2 user2 pass2 3 user3 pass3 13 4 7 1 2 3 4 5 6 7
  38. 38. 38/129 2016 索引子頁結構 : Clustered index 以 B+tree 為例 特色:子頁包括資料本身 ( 不需指針指向資料 ) 補充:對應的資料表稱 Index Organized Table(IOT) 資料表:循序式與亂序式都一樣 13 4 7 1 2 3 4 5 6 7 1 user1 pass1 2 user2 pass2 3 user3 pass3 4 user4 pass4 5 user5 pass5
  39. 39. 39/129 2016 Non-clustered index(Heap table) 循序式 ➀ 有索引指針指向資料的額外開銷。 ➁ Hotspot 發生在樹最右下的頁,但循序寫及合併寫機率高。 ➂ Range scan 讀取時開銷大。 亂序式 ➀ 有索引指針指向資料的額外開銷。 ➁ Range scan 讀取時開銷可能比循序式更大。 ➂ 大量新增資料,幾乎是隨機寫,也難以合併寫。 索引子頁結構 : Non-clustered index
  40. 40. 40/129 2016 索引子頁結構 : Clustered index Clustered index(IOT) 循序式 ➀ 資料佔頁空間,頁存放的資料量少,頁分裂頻繁。 ➁ 搜尋至頁索引時,因包括資料本身,無額外指針開銷。 ➂ Hotspot 發生在樹最右下的頁,但循序寫及合併寫機率高。 亂序式 ➀ 資料佔頁空間,頁存放的資料量少,頁分裂頻繁。 ➁ 搜尋至頁索引時,因包括資料本身,無額外指針開銷。 ➂ 為了維持循序,發生大量的頁分裂。
  41. 41. 41/129 2016 索引子頁結構 : Clustered index Q: 循序式 / 亂序式 vs. I/O Scheduler vs. Filesystem vs. HDD / Flash / Fusion IO ? 循序式 亂序式 CFQ Deadline NOOP HDD Flash Fusion IO Ext4 XFS ZFS BtrFS
  42. 42. 2016 42/129 Range scan
  43. 43. 43/129 2016 Range scan >, <, >=, <= BETWEEN, IN GROUP BY with max, min, count
  44. 44. 44/129 2016 Range scan: Heap table w/ 循序式 SELECT * FROM x WHERE y BETWEEN 1 AND 7; 1 user1 pass1 2 user2 pass2 3 user3 pass3 4 user4 pass4 5 user5 pass5 6 user6 pass6 7 user7 pass7 13 4 7 1 2 3 4 5 6 7 Block N+3 ... p1 p3 I/O p2 p1 p2 p3 p4 I/O Block N+M
  45. 45. 45/129 2016 Range scan: Heap table w/ 亂序式 SELECT * FROM x WHERE y BETWEEN 1 AND 7; 1 user1 pass1 4 user4 pass4 5 user5 pass5 2 user2 pass2 3 user3 pass3 7 user7 pass7 6 user6 pass6 13 4 7 1 2 3 4 5 6 7 I/O p5 p7 p3 p6 I/O I/OI/O p1 # p2 p4... p4 p7 p5 p1 p3 p2 p6
  46. 46. 46/129 2016 Range scan: Heap table w/ 亂序式 I/O p5 p7 p3 p6 I/O I/OI/O p1 # p2 p4... Ref: http://etutorials.org/SQL/Postgresql/Part+I+General+PostgreSQL+Use/Chapter+4.+Performance/Gathering+Performance+Information/
  47. 47. 47/129 2016 Range scan: IOT w/ 循序式 & 亂序式 SELECT * FROM x WHERE y BETWEEN 1 AND 7; 13 4 7 1 2 3 4 5 6 7 1 user1 pass1 2 user2 pass2 3 user3 pass3 4 user4 pass4 5 user5 pass5 6 user6 pass6 7 user7 pass7 p1 p3 p2 Block N+3 ... I/O p1 p2 p3 p4 I/O Block N+M
  48. 48. 2016 48/129 問題 3 Q: 哪些資料庫支援 Heap table ?哪些支援 IOT ? MySQL Oracle Microsoft SQL Server PostgreSQL MongoDB CouchDB
  49. 49. 49/129 2016 問題 3 Heap table IOT MySQL/MyISAM O X MySQL/InnoDB X O Oracle O O Microsoft SQL Server O O PostgreSQL O X MongoDB/MMAPv1 O X MongoDB/WiredTiger O X CouchDB X O
  50. 50. 50/129 2016 問題 3 Q: 選什麼資料庫比較好? 是個偽命題,需視你的場景而定。
  51. 51. 2016 51/129 特別篇 1: MySQL 生態系 Q: MySQL 生態系, MySQL / Percona / MariaDB / WebScaleSQL 該怎麼選擇?
  52. 52. 52/129 2016 特別篇 1: MySQL 生態系 MySQL ➀ 官方,有 Oracle 技術支持及專利保護。 ➁ 最新的 MySQL 5.7 擁有大量新特性。 ➂ 商業因素預設不會接受其他分支的特性。 Percona ➀ drop-in compatible with (official) MySQL 。 ➁ 針對 MySQL 額外新增許多特性。 ➂ 額外支援 XtraDB / TokuDB 等引擎。 ➃ 商業特性可接受其他所有分支的特性。
  53. 53. 53/129 2016 特別篇 1: MySQL 生態系 MariaDB ➀ drop-in replacement for (official) MySQL 。 ➁ MariaDB 10 基於 MySQL 5.6 ,但不相容 5.7 。 ➂ 額外支援 XtraDB / TokuDB / Cassandra / CONNECT 等引擎。 ➃ 至今仍沒有穩定的自我開發儲存引擎。 XtraDB / TokuDB 都屬 Percona 公司。 WebScaleSQL ➀ 基於 5.6 ,但可收納 5.7 特性。 ➁ 專針對特大型 Web 公司需求而生,小心駕馭。
  54. 54. 54/129 2016 特別篇 1: MySQL 生態系 MySQL 5.7 解決了 index→lock contention 問題。
  55. 55. 2016 55/129 特別篇 2: PostgreSQL PostgreSQL 是 Object-relational database
  56. 56. 56/129 2016 特別篇 2: PostgreSQL (Fusion IO) Fusion IO 可大幅排除 IO Bottlenect 的可能性。
  57. 57. 57/129 2016 特別篇 2: PostgreSQL (Fusion IO) Fusion IO 只特別支援 Oracle / MySQL / Percona / MariaDB ? Ref: https://www.sandisk.com/business/datacenter/resources/overviews/accelerate-mysql-open-source-databases
  58. 58. 58/129 2016 特別篇 2: PostgreSQL (Fusion IO) Fusion IO 可讓 MySQL 免除 double write 。 Ref: https://www.sandisk.com/business/datacenter/resources/overviews/accelerate-mysql-open-source-databases
  59. 59. 59/129 2016 特別篇 2: PostgreSQL (Fragmentation) PostgreSQL(HOT) 天性無法避免 fragmentation 。 Ref: http://etutorials.org/SQL/Postgresql/Part+I+General+PostgreSQL+Use/Chapter+4.+Performance/Gathering+Performance+Information/
  60. 60. 60/129 2016 特別篇 2: PostgreSQL (Index Bloat) PostgreSQL(non HOT updates) 天性無法避免 index bloat 。 Ref: PostgreSQL 9.0 High Performance [PACKT] (2010) (p171)
  61. 61. 61/129 2016 特別篇 2: PostgreSQL (Index Bloat)
  62. 62. 62/129 2016 特別篇 2: PostgreSQL (Index Bloat)
  63. 63. 63/129 2016 特別篇 2: PostgreSQL (Merge IO) PostgreSQL 沒有類似 MySQL 的 Change Buffer 。 Ref: http://www.slideshare.net/morgo/inno-db-presentation (p9)
  64. 64. 64/129 2016 特別篇 2: PostgreSQL (Merge IO) MySQL Insert Buffering( 現在改名 Change Buffer) : 1. Reducing the number of disk i/o operations by merging i/o requests to the same block. 2. Some random i/o operations can be sequential. Ref: http://www.percona.com/files/presentations/percona-live/london-2011/PLUK2011-linux-and-hw-optimizations-for-mysql.pdf (p17)
  65. 65. 65/129 2016 特別篇 2: PostgreSQL (Merge IO)
  66. 66. 66/129 2016 特別篇 2: PostgreSQL ( 儲存引擎 ) Microsoft SQL Server / Oracle 支援 Heap table 及 IOT , 可依各資料表的特性分別採用。 MySQL 及 MongoDB 支援可抽換儲存引擎,也可依資料表的 特性分別採用。 但 PostgreSQL 只有一個儲存引擎,也只支援 Heap table 。
  67. 67. 2016 67/129 特別篇 3: MongoDB
  68. 68. 68/129 2016 特別篇 3: MongoDB Ref: http://itindex.net/detail/43573
  69. 69. 69/129 2016 特別篇 3: MongoDB Ref: http://sql-vs-nosql.blogspot.tw/2013/11/indexes-comparison-mongodb-vs-mssqlserver.html
  70. 70. 70/129 2016 特別篇 3: MongoDB Ref: http://learnmongodbthehardway.com/schema/chapter4/ B+Tree / Heap Table
  71. 71. 71/129 2016 特別篇 3: MongoDB Ref: Indexing and Performance Tuning (2015-11-03).pdf (p39)
  72. 72. 72/129 2016 特別篇 3: MongoDB Index ➀ ”統一命名為 _id” ➁ ”新增若未指定 _id” 值,會使用 ObjectId ➂ ObjectId 為 12-byte BSON 型態 ➊ 4-byte 為 UNIX 紀元時間 ➋ 3-byte 為機器識別碼 ➌ 2-byte 為 Process ID ➍ 3-byte 為隨機值 Ref: https://docs.mongodb.org/manual/reference/object-id/ “_id” : ObjectId(“563479cc8a8a4246bd27d784”) “_id” : ObjectId(“563479d48a8a4246bd27d785”) “_id” : ObjectId(“563479df8a8a4246bd27d786”) 循序式 UUID
  73. 73. 73/129 2016 特別篇 3: MongoDB MMAPv1 儲存引擎 ➀ Memory-mapped files Ref: http://learnmongodbthehardway.com/schema/chapter3/
  74. 74. 74/129 2016 特別篇 3: MongoDB MMAPv1 儲存引擎 ➀ Memory-mapped files ➁ Padding Ref: http://learnmongodbthehardway.com/schema/chapter3/
  75. 75. 75/129 2016 特別篇 3: MongoDB MMAPv1 儲存引擎 ➀ Memory-mapped files ➁ Padding ➂ Fragmentation Ref: http://learnmongodbthehardway.com/schema/chapter3/
  76. 76. 76/129 2016 特別篇 3: MongoDB MMAPv1 儲存引擎 ➀ Memory-mapped files ➁ Padding ➂ Fragmentation ➃ Collection-level locking (WiredTiger 為 Document-level) Ref: http://sql-vs-nosql.blogspot.tw/2013/11/indexes-comparison-mongodb-vs-mssqlserver.html
  77. 77. 77/129 2016 特別篇 3: MongoDB MMAPv1 儲存引擎 ➀ Memory-mapped files ➁ Padding ➂ Fragmentation ➃ Collection-level locking (WiredTiger 為 Document-level) ➄ MongoDB 3.2 以前為預設引擎, 3.2 後換 WiredTiger Ref: https://docs.mongodb.org/manual/core/wiredtiger/
  78. 78. 78/129 2016 特別篇 3: MongoDB MMAPv1 的 Fragmentation 問題 Ref: http://www.slideshare.net/mongodb/7-managing-a-maturing-mongo-db-ecosystem-charity-majors (p35) 左邊是大量 Fragmentation ; 右邊是修復 Fragmentation 後
  79. 79. 79/129 2016 特別篇 3: MongoDB MMAPv1 的 Fragmentation 問題 動作:連續新增 5 個 Document Collection : {Document 1} {Document 2} {Document 3} {Document 4} {Document 5}
  80. 80. 80/129 2016 特別篇 3: MongoDB MMAPv1 的 Fragmentation 問題 動作:更新 Document 3 情況一:新的 Document 3 大小 <= 原先大小 Collection : {Document 1} {Document 2} {Document 3} {Document 4} {Document 5} {Document 1} {Document 2} {Document 3‘} {Document 4} {Document 5}
  81. 81. 81/129 2016 特別篇 3: MongoDB MMAPv1 的 Fragmentation 問題 動作:更新 Document 3 情況二:新的 Document 3 大小 > 原先大小 Collection : {Document 1} {Document 2} {Document 3} {Document 4} {Document 5} {Document 1} {Document 2} Free {Document 4} {Document 5} {Document 3‘}
  82. 82. 82/129 2016 特別篇 3: MongoDB MMAPv1 的 Fragmentation 問題 動作:新增 Document 6 Collection : {Document 1} {Document 2} Free {Document 4} {Document 5} {Document 3‘}
  83. 83. 83/129 2016 特別篇 3: MongoDB MMAPv1 的 Fragmentation 問題 動作:新增 Document 6 情況一: Document 6 大小 <= 原先 Document 3 (Free) 大小 Collection : {Document 1} {Document 2} {Document 6} {Document 4} {Document 5} {Document 3‘} {Document 1} {Document 2} Free {Document 4} {Document 5} {Document 3‘}
  84. 84. 84/129 2016 特別篇 3: MongoDB MMAPv1 的 Fragmentation 問題 動作:新增 Document 6 情況二: Document 6 大小 > 原先 Document 3 (Free) 大小 Collection : {Document 1} {Document 2} Free {Document 4} {Document 5} {Document 3‘} {Document 6} {Document 1} {Document 2} Free {Document 4} {Document 5} {Document 3‘}
  85. 85. 85/129 2016 特別篇 3: MongoDB 特色與改善 ➀ Sharding/Replica 較容易 ( 但 Sharding/Replica 只有 Primary 可寫 ) ➁ Dynamic schema ( 不是 Schemaless) ➂ 儲存引擎可抽換 ➊ MMAPv1 ➋ WiredTiger ➌ inMemory ➍ Devnull ➎ (RocksDB)
  86. 86. 86/129 2016 特別篇 3: MongoDB 特色與改善 ➃ 寫入的 Locking level 改善 2.2 版前, Process-level lock ,一個 Mongod 實例一個鎖 2.8 版前, Database-level lock ,一個 DB 一個鎖 2.8 版之後, WiredTiger 提供 Document-level lock 3.0 版之後, MMAPv1 改為 Collection-level lock Ref: http://sql-vs-nosql.blogspot.tw/2013/11/indexes-comparison-mongodb-vs-mssqlserver.html
  87. 87. 87/129 2016 特別篇 3: MongoDB 特色與改善 ➄ 支援 MapReduce 2.4 版前,使用 SpiderMonkey ,是 single threaded 2.4 版之後,改用 V8 engine ,改善問題 ➅ Single thread model ,大多時候只用到一顆 CPU (WiredTiger 已支援 Multiple CPUs)
  88. 88. 2016 88/129 特別篇 4: RDMBS or NoSQL ? Q: 使用 RDBMS 還是 NoSQL ?
  89. 89. 89/129 2016 特別篇 4: RDMBS or NoSQL ? Q: 使用 RDBMS 還是 NoSQL ? 是個偽命題,需視你的場景而定。
  90. 90. 90/129 2016 特別篇 4: RDMBS or NoSQL ? 不過 RDBMS 及 NoSQL 的分界會愈來愈小。 過去的一些 RDBMS 已開始支援 NoSQL 特性, Microsoft SQL Server / Oracle / MySQL / PostgreSQL 都確定支援 JSON(B) 操作。 Percona / MariaDB 可抽換為 TokuDB 引擎, MariaDB 更可抽換為 Cassandra 引擎。 NoSQL 等也開始支援強一致性。
  91. 91. 91/129 2016 特別篇 4: RDMBS or NoSQL ? 不過 RDBMS 及 NoSQL 的分界會愈來愈小。 過去的一些 RDBMS 已開始支援 NoSQL 特性, Microsoft SQL Server / Oracle / MySQL / PostgreSQL 都確定支援 JSON(B) 操作。 Percona / MariaDB 可抽換為 TokuDB 引擎, MariaDB 更可抽換為 Cassandra 引擎。 NoSQL 等也開始支援強一致性。 NewSQL
  92. 92. 2016 92/129 特別篇 5: 黑暗執行緒案例 Q: 試著分析黑暗執行緒的文章。 【 GUID Primary Key 資料庫避雷守則】 Ref: http://blog.darkthread.net/post-2016-01-29-guid-as-pk-on-db.aspx
  93. 93. 93/129 2016 特別篇 5: 黑暗執行緒案例 以架構設計而言,我更傾向讓應用伺服器決定 GUID / UUID 的值, 理由有幾個。 ➊ 未來若需要異質資料庫彼此交換資料, GUID / UUID 的衝突會 更小。例如若 SQL Server 要與 MySQL 交換, MySQL 沒有 NEWID / NEWSEQUENTIALID 函式,所以勢必要用另一種算法來計算 UUID , 而算法不同就可能破壞原本 GUID / UUID 不會重複的機率。 ➋ 資料庫在整體架構中,是最難以擴展的,所以我傾向讓資料庫做愈少 事情愈好。 GUID / UUID 是需要計算的,即使開銷很低,但若量大還是 很可觀,所以我還是會把計算的成本移至應用伺服器處理。
  94. 94. 94/129 2016 特別篇 5: 黑暗執行緒案例 ➌ 應用伺服器脫離 SQL Server 後,就無法使用 NEWID 及 NEWSEQUENTIALID ,所以需要找 UUID 產生器。 UUID 產生器有 幾種版本, UUIDv1 是類循序性, UUIDv4 是亂序性,可以依業務 場景選擇所需。而且 UUIDv1 的類循序性不像 NEWSEQUENTIALID 這麼容易猜測。 ➍ 大規模架構中,全循序性 Insert 不一定是好事。想像一下,順序性 Insert 時,所有資料會集中在樹最右下角的 Leaf Page Insert ,當 Page 滿後,就必須 Page Split ,此時就一定有 Latch 。 Latch 會減 緩 Insert 的速度。再加上實際在硬碟寫入的 Block 也會變成是 Hotspot 。 所以有時候,適當非循序性所造成的 Fragmentation 有時反而會更快。 最後有可能會變成全順序性 Insert 不一定最快,全隨機性 Insert 也不 一定最好,反而中間找平衡才是最佳的。而這時把 UUID 的計算移到應 用伺服器,剛好可以滿足這點。
  95. 95. 95/129 2016 特別篇 5: 黑暗執行緒案例 黑暗執行緒提供的表設計建議
  96. 96. 96/129 2016 特別篇 5: 黑暗執行緒案例 黑暗執行緒提供的表設計建議 4c.. cb.. ee.. 07.. 3b.. 4c.. 5b.. 9e.. cb.. ee.. Clustered Index ( 循序式 ) Nonclustered Index ( 亂序式 ) 3 6 7 1 2 3 4 5 6 7
  97. 97. 97/129 2016
  98. 98. 98/129 2016 特別篇 5: 黑暗執行緒案例 假設已有五筆資料 5b.. cb.. 07.. 3b.. 5b.. 9e.. cb.. 3 5 1 2 3 4 5 [SeqNo] [FlowId] ... 1 07.. ... 2 9e.. ... 3 3b.. ... 4 cb.. ... 5 5b.. ... 1 3 5 2 4 Nonclustered Index ( 亂序式 ) Clustered Index ( 循序式 )
  99. 99. 99/129 2016 特別篇 5: 黑暗執行緒案例 尋找【 WHERE FlowId = “5b..” 】 IO 次數: 0 5b.. cb.. 07.. 3b.. 5b.. 9e.. cb.. 3 5 1 2 3 4 5 [SeqNo] [FlowId] ... 1 07.. ... 2 9e.. ... 3 3b.. ... 4 cb.. ... 5 5b.. ... 1 3 5 2 4 Nonclustered Index ( 亂序式 ) Clustered Index ( 循序式 )
  100. 100. 100/129 2016 特別篇 5: 黑暗執行緒案例 尋找【 WHERE FlowId = “5b..” 】 IO 次數: 1 5b.. cb.. 07.. 3b.. 5b.. 9e.. cb.. 3 5 1 2 3 4 5 [SeqNo] [FlowId] ... 1 07.. ... 2 9e.. ... 3 3b.. ... 4 cb.. ... 5 5b.. ... 1 3 5 2 4 Nonclustered Index ( 亂序式 ) Clustered Index ( 循序式 )
  101. 101. 101/129 2016 特別篇 5: 黑暗執行緒案例 尋找【 WHERE FlowId = “5b..” 】 IO 次數: 2 5b.. cb.. 07.. 3b.. 5b.. 9e.. cb.. 3 5 1 2 3 4 5 [SeqNo] [FlowId] ... 1 07.. ... 2 9e.. ... 3 3b.. ... 4 cb.. ... 5 5b.. ... 1 3 5 2 4 Nonclustered Index ( 亂序式 ) Clustered Index ( 循序式 )
  102. 102. 102/129 2016 特別篇 5: 黑暗執行緒案例 尋找【 WHERE FlowId = “5b..” 】 IO 次數: 3 5b.. cb.. 07.. 3b.. 5b.. 9e.. cb.. 3 5 1 2 3 4 5 [SeqNo] [FlowId] ... 1 07.. ... 2 9e.. ... 3 3b.. ... 4 cb.. ... 5 5b.. ... 1 3 5 2 4 Nonclustered Index ( 亂序式 ) Clustered Index ( 循序式 )
  103. 103. 103/129 2016 特別篇 5: 黑暗執行緒案例 尋找【 WHERE FlowId = “5b..” 】 IO 次數: 4 ( 完成 ) 5b.. cb.. 07.. 3b.. 5b.. 9e.. cb.. 3 5 1 2 3 4 5 [SeqNo] [FlowId] ... 1 07.. ... 2 9e.. ... 3 3b.. ... 4 cb.. ... 5 5b.. ... 1 3 5 2 4 Nonclustered Index ( 亂序式 ) Clustered Index ( 循序式 )
  104. 104. 104/129 2016 特別篇 5: 黑暗執行緒案例 新增【 SeqNo: 6, FlowID: 4c.. 】 IO 次數: 0 5b.. cb.. 07.. 3b.. 5b.. 9e.. cb.. 3 5 1 2 3 4 5 [SeqNo] [FlowId] ... 1 07.. ... 2 9e.. ... 3 3b.. ... 4 cb.. ... 5 5b.. ... 6 4c.. ... 1 3 5 2 4 Nonclustered Index ( 亂序式 ) Clustered Index ( 循序式 )
  105. 105. 105/129 2016 特別篇 5: 黑暗執行緒案例 新增【 SeqNo: 6, FlowID: 4c.. 】 IO 次數: 1 5b.. cb.. 07.. 3b.. 5b.. 9e.. cb.. 3 5 1 2 3 4 5 [SeqNo] [FlowId] ... 1 07.. ... 2 9e.. ... 3 3b.. ... 4 cb.. ... 5 5b.. ... 6 4c.. ... 1 3 5 2 4 Nonclustered Index ( 亂序式 ) Clustered Index ( 循序式 )
  106. 106. 106/129 2016 特別篇 5: 黑暗執行緒案例 新增【 SeqNo: 6, FlowID: 4c.. 】 IO 次數: 2 5b.. cb.. 07.. 3b.. 5b.. 9e.. cb.. 3 5 1 2 3 4 5 [SeqNo] [FlowId] ... 1 07.. ... 2 9e.. ... 3 3b.. ... 4 cb.. ... 5 5b.. ... 6 4c.. ... 1 3 5 2 4 Nonclustered Index ( 亂序式 ) Clustered Index ( 循序式 )
  107. 107. 107/129 2016 特別篇 5: 黑暗執行緒案例 新增【 SeqNo: 6, FlowID: 4c.. 】 IO 次數: 3+3 Page Split 次數: 1 3 5 1 2 3 4 5 [SeqNo] [FlowId] ... 1 07.. ... 2 9e.. ... 3 3b.. ... 4 cb.. ... 5 5b.. ... 6 4c.. ... Nonclustered Index ( 亂序式 ) Clustered Index ( 循序式 ) 07.. 3b.. 4c.. 5b.. 1 3 6 5 42 3b.. 5b.. cb.. 9e.. cb..
  108. 108. 108/129 2016 特別篇 5: 黑暗執行緒案例 新增【 SeqNo: 6, FlowID: 4c.. 】 IO 次數: 3+3+1 Page Split 次數: 1 3 5 1 2 3 4 5 [SeqNo] [FlowId] ... 1 07.. ... 2 9e.. ... 3 3b.. ... 4 cb.. ... 5 5b.. ... 6 4c.. ... Nonclustered Index ( 亂序式 ) Clustered Index ( 循序式 ) 07.. 3b.. 4c.. 5b.. 1 3 6 5 42 3b.. 5b.. cb.. 9e.. cb..
  109. 109. 109/129 2016 特別篇 5: 黑暗執行緒案例 新增【 SeqNo: 6, FlowID: 4c.. 】 IO 次數: 3+3+2 Page Split 次數: 1 3 5 1 2 3 4 5 [SeqNo] [FlowId] ... 1 07.. ... 2 9e.. ... 3 3b.. ... 4 cb.. ... 5 5b.. ... 6 4c.. ... Nonclustered Index ( 亂序式 ) Clustered Index ( 循序式 ) 07.. 3b.. 4c.. 5b.. 1 3 6 5 42 3b.. 5b.. cb.. 9e.. cb..
  110. 110. 110/129 2016 特別篇 5: 黑暗執行緒案例 新增【 SeqNo: 6, FlowID: 4c.. 】 IO 次數: 3+3+3 Page Split 次數: 1 3 5 1 2 3 4 5 6 [SeqNo] [FlowId] ... 1 07.. ... 2 9e.. ... 3 3b.. ... 4 cb.. ... 5 5b.. ... 6 4c.. ... Nonclustered Index ( 亂序式 ) Clustered Index ( 循序式 ) 07.. 3b.. 4c.. 5b.. 1 3 6 5 42 3b.. 5b.. cb.. 9e.. cb..
  111. 111. 111/129 2016 特別篇 5: 黑暗執行緒案例 新增【 SeqNo: 6, FlowID: 4c.. 】 IO 次數: 3+3+4=10 ( 完成 ) Page Split 次數: 1 07.. 3b.. 4c.. 5b.. 3 6 1 2 3 4 5 6 [SeqNo] [FlowId] ... 1 07.. ... 2 9e.. ... 3 3b.. ... 4 cb.. ... 5 5b.. ... 6 4c.. ... 1 3 6 5 42 Nonclustered Index ( 亂序式 ) Clustered Index ( 循序式 ) 3b.. 5b.. cb.. 9e.. cb..
  112. 112. 112/129 2016 特別篇 5: 黑暗執行緒案例 如果用一般亂序式 UUID [FlowId] ... ... 07.. ... ... 9e.. ... ... 3b.. ... ... cb.. ... ... 5b.. ... ... 5b.. cb.. 07.. 3b.. 5b.. 9e.. cb.. Clustered Index ( 亂序式 )
  113. 113. 113/129 2016 特別篇 5: 黑暗執行緒案例 尋找【 WHERE FlowId = “5b..” 】 IO 次數: 0 [FlowId] ... ... 07.. ... ... 9e.. ... ... 3b.. ... ... cb.. ... ... 5b.. ... ... 5b.. cb.. 07.. 3b.. 5b.. 9e.. cb.. Clustered Index ( 亂序式 )
  114. 114. 114/129 2016 特別篇 5: 黑暗執行緒案例 尋找【 WHERE FlowId = “5b..” 】 IO 次數: 1 [FlowId] ... ... 07.. ... ... 9e.. ... ... 3b.. ... ... cb.. ... ... 5b.. ... ... 5b.. cb.. 07.. 3b.. 5b.. 9e.. cb.. Clustered Index ( 亂序式 )
  115. 115. 115/129 2016 特別篇 5: 黑暗執行緒案例 尋找【 WHERE FlowId = “5b..” 】 IO 次數: 2 ( 完成 ) [FlowId] ... ... 07.. ... ... 9e.. ... ... 3b.. ... ... cb.. ... ... 5b.. ... ... 5b.. cb.. 07.. 3b.. 5b.. 9e.. cb.. Clustered Index ( 亂序式 )
  116. 116. 116/129 2016 特別篇 5: 黑暗執行緒案例 新增【 FlowID: 4c.. 】 IO 次數: 0 [FlowId] ... ... 07.. ... ... 9e.. ... ... 3b.. ... ... cb.. ... ... 5b.. ... ... 4c.. ... ... 5b.. cb.. 07.. 3b.. 5b.. 9e.. cb.. Clustered Index ( 亂序式 )
  117. 117. 117/129 2016 特別篇 5: 黑暗執行緒案例 新增【 FlowID: 4c.. 】 IO 次數: 1 [FlowId] ... ... 07.. ... ... 9e.. ... ... 3b.. ... ... cb.. ... ... 5b.. ... ... 4c.. ... ... 5b.. cb.. 07.. 3b.. 5b.. 9e.. cb.. Clustered Index ( 亂序式 )
  118. 118. 118/129 2016 特別篇 5: 黑暗執行緒案例 新增【 FlowID: 4c.. 】 IO 次數: 2 [FlowId] ... ... 07.. ... ... 9e.. ... ... 3b.. ... ... cb.. ... ... 5b.. ... ... 4c.. ... ... 5b.. cb.. 07.. 3b.. 5b.. 9e.. cb.. Clustered Index ( 亂序式 )
  119. 119. 119/129 2016 特別篇 5: 黑暗執行緒案例 新增【 FlowID: 4c.. 】 IO 次數: 3+3 ( 完成 ) Page Split 次數: 1 [FlowId] ... ... 07.. ... ... 9e.. ... ... 3b.. ... ... cb.. ... ... 5b.. ... ... 4c.. ... ... 3b.. 5b.. cb.. 07.. 3b.. 4c.. 5b.. Clustered Index ( 亂序式 ) 9e.. cb..
  120. 120. 120/129 2016 特別篇 5: 黑暗執行緒案例 如果用一般循序式 UUID [FlowId] ... ... 1 ... ... 2 ... ... 3 ... ... 4 ... ... 5 ... ... 3 5 1 2 3 4 5 Clustered Index ( 循序式 )
  121. 121. 121/129 2016 特別篇 5: 黑暗執行緒案例 尋找【 WHERE FlowId = 5 】 IO 次數: 0 [FlowId] ... ... 1 ... ... 2 ... ... 3 ... ... 4 ... ... 5 ... ... 3 5 1 2 3 4 5 Clustered Index ( 循序式 )
  122. 122. 122/129 2016 特別篇 5: 黑暗執行緒案例 尋找【 WHERE FlowId = 5 】 IO 次數: 1 [FlowId] ... ... 1 ... ... 2 ... ... 3 ... ... 4 ... ... 5 ... ... 3 5 1 2 3 4 5 Clustered Index ( 循序式 )
  123. 123. 123/129 2016 特別篇 5: 黑暗執行緒案例 尋找【 WHERE FlowId = 5 】 IO 次數: 2 ( 完成 ) [FlowId] ... ... 1 ... ... 2 ... ... 3 ... ... 4 ... ... 5 ... ... 3 5 1 2 3 4 5 Clustered Index ( 循序式 )
  124. 124. 124/129 2016 特別篇 5: 黑暗執行緒案例 新增【 FlowID: 6 】 IO 次數: 0 [FlowId] ... ... 1 ... ... 2 ... ... 3 ... ... 4 ... ... 5 ... ... 6 ... ... 3 5 1 2 3 4 5 Clustered Index ( 循序式 )
  125. 125. 125/129 2016 特別篇 5: 黑暗執行緒案例 新增【 FlowID: 6 】 IO 次數: 1 [FlowId] ... ... 1 ... ... 2 ... ... 3 ... ... 4 ... ... 5 ... ... 6 ... ... 3 5 1 2 3 4 5 Clustered Index ( 循序式 )
  126. 126. 126/129 2016 特別篇 5: 黑暗執行緒案例 新增【 FlowID: 6 】 IO 次數: 2 [FlowId] ... ... 1 ... ... 2 ... ... 3 ... ... 4 ... ... 5 ... ... 6 ... ... 3 5 1 2 3 4 5 Clustered Index ( 循序式 )
  127. 127. 127/129 2016 特別篇 5: 黑暗執行緒案例 新增【 FlowID: 6 】 IO 次數: 3+1 ( 完成 ) [FlowId] ... ... 1 ... ... 2 ... ... 3 ... ... 4 ... ... 5 ... ... 6 ... ... 3 6 1 2 3 4 5 6 Clustered Index ( 循序式 )
  128. 128. 128/129 2016 特別篇 5: 黑暗執行緒案例 小結:本場景為例 黑暗執行緒 亂序式 UUID 循序式 UUID Point-of-query IO 4 2 2 Insert IO 10 6 4 Insert (Page Split) 1 1 0 Space size ++ + + Latch(%) ++ + +
  129. 129. 129/129 2016 特別篇 6: MultiColumn B-Tree Index [Col#1] [Col#2] 1 A 3 B 3 C 4 D 3 C CREATE INDEX ON table (Col#1, Col#2); 1 A 3 B 3 C 4 D

×