[转载] --- 数据库基本知识
里面的很多點,我之前都總結過,但是感覺這篇把這些都連起來了,總結的挺好,轉載保存一下
【從入門到入土】令人脫發的數據庫底層設計
前言
說到數據庫這個詞,我只能用愛恨交加這個詞來形容它。兩年前在自己還單純懵懂的時候進了數據庫的課堂,聽完數據庫的課,覺得這是一門再簡單不過的課程,任何一門編程語言都比SQL要晦澀難懂,任何一門理論課程都比數據庫關系要復雜得多。直到從被面試官按在地上摩擦,到工作中那一條條令人發指的慢查詢SQL,這就已經完全顛覆了我對數據庫的看法。在有各種數據庫工具的今天,我們是看不到那簡單到不能再簡單的一張表的背后,隱藏著多少數據結構的支撐,也看不到我們隨手敲的一條SELECT,背后會有多少算法和數據結構在給我們做優化,作為一個有技術熱情的coder,應該需要對我們每日在用的數據庫做一次深入了解。
數據庫架構
-
如何設計一個關系型數據庫
這個問題很寬泛,需要我們對于整體有一個掌控,對我們平時所用的數據庫要有足夠的了解,對整個數據庫做模塊劃分是這道題的關鍵,這就更需要我們足夠了解數據庫,對數據庫做一個合理的模塊設計。
-
設計
從開始,首先要明白,數據庫的最最根本的作用是什么——存儲數據,所以我們需要一個存儲模塊來存儲我們的數據,它可以是一個文件系統(機械硬盤?SSD固態硬盤?)。但光有存儲模塊是不夠的,我們還需要一個程序實例,來組織或者獲取這些數據,在程序實例中我們需要提供獲取和組織這些數據的方式,所以我們需要在程序實例中實現存儲管理模塊。我們還可以在存儲管理模塊中做一些提升效能的工作,例如同時讀取多行、分塊分頁存儲等。數據庫作為一款對性能要求極高的軟件,我們應該加入緩存機制,來提高其速度,當查詢到緩存中已存在的數據,我們應該直接將其從緩存中讀取,這樣可以減少硬盤IO次數,提高效能。到這里為止,我們已經完成了對數據庫的存儲方面的功能設計,但是作為數據庫,應該需要提供給用戶對數據進行增刪改查的接口,即平時所寫的SQL,所以我們應該提供一個SQL解析模塊,來對日常用戶所寫的SQL語句進行解析,轉換成機器可識別的指令,我們也可以直接將編譯過的SQL加入緩存,下次再有同樣的SQL就直接從緩存中讀取,同樣可以提高效能。作為一款成熟的數據庫,需要應對各種復雜的環境,要時刻記錄數據庫的狀態,所以我們還需要一個日志管理模塊,對操作和錯誤信息進行記錄。數據庫中需要支持多用戶操作,但每個用戶都能操作所有的數據,這是不現實的,所以還需要權限劃分模塊對數據庫用戶進行權限管理。當然數據庫說到底也只是一款軟件,是軟件就會有bug,就會出故障,故障不可怕,可怕的是在數據庫這種敏感軟件下對故障沒有特殊的處理方式,導致數據丟失,畢竟數據是無價的,所以數據庫應該引入容災機制,在數據庫掛了的時候,對數據進行恢復。還有作為數據庫最重要的兩個模塊,也是現今任何一個數據庫都需要考慮的問題——并發和查找效率,所以還需引入索引和鎖這兩個模塊,這就是實現一個最基礎的數據庫所必需的幾大模塊。
-
歸納
綜上對數據庫設計模塊做一個匯總:
1.存儲模塊
2.程序實例
2.1存儲管理模塊
2.2緩存機制
2.3SQL解析模塊
2.4日志管理模塊
2.5權限劃分模塊
2.6容災機制
2.7索引模塊
2.8鎖模塊
索引
-
為什么要使用索引
要考慮這個問題,首先要從最基礎的查找表中數據的過程開始說起。通常我們在查找一個序列中的某一個元素時,用到的最簡單的方式就是遍歷,數據庫也是一樣,在一張表中查找某一行數據時,如果不考慮索引的狀況下,也會采用一個逐行掃描的方式,只不過數據庫通常以塊或者頁為單位,所以它通常將整個塊或者頁加載進內存,然后逐塊輪詢查找到結果并返回。如果數據庫中只有少量數據,那么進行全表掃描,速度還是會很快,但是如果在數據量很大的表中,這種方法就不再適用了,在數據量很大的表中,由于逐行掃描代價變大,通常需要避免采用這種逐行掃描的方式進行數據查找,數據庫為了使查詢變得高效,所以引入了索引這種方式對數據進行查找。
-
什么樣的信息能成為索引
1.主鍵、唯一鍵、普通鍵
-
索引的數據結構
-
二叉查找樹
眾所周知,二叉查找樹是每個節點最多由兩個子樹的樹結構,而其還有一個特點是,在任意一顆樹中,根節點的左孩子永遠小于根節點,根節點的右孩子永遠大于根節點,用二叉查找樹作為索引,確實可以提高查找效率,其可以使用二分查找將時間復雜度控制在O(lgn),但是二叉查找樹有一個顯而易見的缺陷,當某種特殊情況(按照某個特定順序插入樹)發生時,二叉查找樹將變為下圖右側(線性二叉樹)的狀況:
此時二叉查找樹查找任意某個元素時,其查找順序與逐行查找無異,查詢時間復雜度又將回到O(n),查詢效率無法保持。 -
B-Tree
B-Tree,平衡多路查找樹,如果每個節點,最多有N個孩子,那么這樣的樹就叫N階B-Tree, 每個節點中主要包含關鍵字和指向孩子的指針,最多能有幾個孩子,取決于節點的容量和數據庫的相關配置,通常情況下這個N是很大的。
B-Tree作為一種數據結構,有如下特征:
1.根節點至少包含兩個孩子
2.樹中每個節點至多含有N個孩子(N>=2)
3.除根節點和葉節點外,其它每個節點至少有ceil(N/2)個孩子。(ceil表示取上限,例如1.2的上限為2,1.1的上限也為2,非四舍五入)
4.所有葉子節點都位于同一層,即葉子節點的高度都是一樣的。
5.假設每個非終端節點包含n個關鍵字信息(P0,P1...Pn,k1...kn)( a )ki(i=1..n)為關鍵字,且關鍵字按順序升序排序k(i-1)<ki。
遵守上述規則,其目的就是盡量使每個索引塊都盡可能多的存儲數據,盡可能減少查找次數以提升效率。 舉個例子,模擬一下查找過程,以便于理解:假設我們要查詢關鍵字為10的數據,則從根節點出發,10<17,于是通過P1進入其孩子節點,10>8且10<12,于是通過P2進入其孩子節點,最后尋找到10。如果不使用索引,而使用逐行掃描的方式進行查找,則從0開始至少掃描10次才能查找到10號數據,有了索引之后可以看到,查找次數從10變為3,大大提高了查找效率。
( b )關鍵字的個數必須滿足:[ceil(m/2)-1]<=n<=m-1]。
( c )非葉子節點的指針:P[1],P[2]...P[M];其中P[1]指向關鍵字小于K[1]的子樹,P[N]指向關鍵字大于K[N-1]的子樹,其它P[i]指向關鍵字屬于(K[i-1],K[i])的子樹。
如果這里是二叉查找樹,會出現極端情況,使得查找時間復雜度為O(n),而如果是B-Tree,由于上述五個約束,可以讓節點通過合并、分裂、上移、下移等操作,使得樹高度較二叉查找樹小,查找效率顯然更高。 -
B+ -Tree(MySQL)
B+ -Tree是B-Tree的一個變體,其定義基本與B樹相同,除了:
B+樹相較于B樹的優勢:
1.非葉子節點的子樹指針與關鍵字個數相同,其表明B+樹能存儲更多的關鍵字
2.非葉子節點的子樹指針P[i],指向關鍵字值[K[i],K[i+1])的子樹。
3.非葉子節點僅用來做索引,數據到保存在葉子節點中。(B+樹的所有檢索都是從根部開始,直到搜索到葉子節點結束。)
4.所有葉子節點均有一個鏈指針,指向下一個葉子節點。(方便直接在葉子節點直接做范圍統計)
1.B+樹的磁盤讀寫代價更低。
2.B+樹的查詢效率更加穩定。
3.B+樹更有利于對數據庫的掃描。
-
Hash
Hash索引是根據Hash結構的定義,只需要一次運算便可以找到數據所在位置,不像B+樹或者B樹需要從根結點出發尋找數據,所以Hash索引的查詢效率理論上要高于B+樹索引,但是MySQL中并沒有采用這一種索引,這是由于這種索引除查詢效率之外的缺陷是十分明顯的。
1.僅僅只能滿足"=","IN",不能使用范圍查詢。由于其是由Hash運算獲取的數據存放位置,每次Hash運算獲取的是一個確定的值,且這個值并不與數據本身的大小有關系,所以其并不能滿足范圍查詢。
2.無法被用來避免數據的排序操作。和1的意思差不多,Hash的索引值是由Hash運算獲取的,其索引值與數據本身的大小并無明顯關系。
3.不能利用部分索引鍵查詢。
4.不能避免表掃描。由于Hash索引會產生Hash沖突,存在Hash沖突的數據會被連接到同一個鏈表上,當大量數據被連接到相同鏈表上時,查詢某條數據就變成了掃描該鏈表,時間復雜度并不能保證在O(1)。
5.遇到大量Hash值相等的情況后性能并不一定就會比B-Tree索引高。 -
BitMap索引
位圖索引,當表中的某個字段只有幾種值的時候,例如:性別,此時用位圖索引是一個最佳的選擇。目前使用位圖索引的比較主流的數據庫有Oracle數據庫。
-
-
密集索引和稀疏索引的區別
1.密集索引文件中的每個搜索碼都對應一個索引值,稀疏索引文件只為索引碼的某些值建立索引項。
2.密集索引將數據存儲與索引放到了一塊,找到索引也就找到了數據,稀疏索引將數據和索引分開存儲,索引結構的葉子節點指向數據的對應行。- 關于MySQL的MyISAM和InnoDB
MyISAM不論是主鍵索引、唯一鍵索引、還是普通索引,都采用的是稀疏索引,而InnoDB必須有且僅有一個密集索引。
InnoDB密集索引規則:
1.若一個主鍵被定義,該主鍵則作為密集索引。
2.若沒有主鍵被定義,該表的第一個唯一非空索引則作為密集索引。
3.若不滿足以上條件,InnoDB內部會生成一個隱藏主鍵(密集索引)。
4.非主鍵索引存儲相關鍵位和其對應的主鍵值,包含兩次查找。
注:InnoDB如果查詢條件為主鍵索引,則只需查詢一次,但是輔助索引需要查詢兩次,先通過輔助索引查詢到主鍵索引,再查詢到數據。
從上圖中可以看到,如果一個索引是聚集索引,則其葉子節點上存放的即是數據本身,而如果一個索引是稀疏索引,葉子節點存放的僅是地址,指向將要查找的數據。
- 關于MySQL的MyISAM和InnoDB
-
如何定位并優化慢查詢SQL
首先先建立一張表
CREATE DATABASE sqltest; use sqltest; create table tb_test(test_id int primary key auto_increment,test_name varchar(1024),test_date datetime,test_desc varchar(1024) );
總結
以上是生活随笔為你收集整理的[转载] --- 数据库基本知识的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: MAC下配置ZSH
- 下一篇: mongodb数据库,批量插入性能测试记