MySQL相關筆記整理
1.MySQL中的儲存引擎
儲存引擎-MyISAM:
MyIASM是MySQL預設的引擎,但是它沒有提供對資料庫事務的支援,也不支援行級鎖和外來鍵,因此當INSERT(插入)或UPDATE(更新)資料時即寫操作需要鎖定整個表,效率便會低一些。不過和Innodb不同,MyIASM中儲存了表的行數,於是SELECT COUNT(*) FROM TABLE時只需要直接讀取已經儲存好的值而不需要進行全表掃描。如果表的讀操作遠遠多於寫操作且不需要資料庫事務的支援,那麼MyIASM也是很好的選擇。
- MySQL5.5之前的預設儲存引擎
- MyISAM 儲存引擎由三個檔案組成。.frm檔案存放表結構;.MYD(MYData)儲存資料;.MYI(MYIndex)儲存索引檔案
- 特性
- 併發性與鎖級別-表級鎖
- 支援全文檢索
- 支援資料壓縮
- myisampack -b -f testmysam.MYI
- 適用場景
- 非事務型應用(資料倉庫,報表,日誌資料)
- 只讀類應用
- 空間類應用(空間函式,座標)
- 不支援事務,回滾將造成不完全回滾,不具有原子性
- 支援全文搜尋
- 儲存表的具體行數,不帶where時,直接返回儲存的行數
- DELETE 表時,先drop表,然後重建表
- 跨平臺很難直接拷貝
- MyISAM中可以使AUTO_INCREMENT型別欄位建立聯合索引
- 表格可以被壓縮
- ISAM執行讀取操作的速度很快,而且不佔用大量的記憶體和儲存資源。ISAM的兩個主要不足之處在於,它不支援事務處理,也不能夠容錯:如果你的硬碟崩潰了,那麼資料檔案就無法恢復了。
- 修復資料庫檔案的MyISAMCHK工具和用來恢復浪費空間的 MyISAMPACK工具
- 不支援外來鍵
儲存引擎-InnoDB:
Innodb引擎提供了對資料庫ACID事務的支援,並且實現了SQL標準的四種隔離級別。該引擎還提供了行級鎖和外來鍵約束,它的設計目標是處理大容量資料庫系統,它本身其實就是基於MySQL後臺的完整資料庫系統,MySQL執行時Innodb會在記憶體中建立緩衝池,用於緩衝資料和索引。但是該引擎不支援FULLTEXT型別的索引,而且它沒有儲存表的行數,當SELECT COUNT(*) FROM TABLE時需要掃描全表。當需要使用資料庫事務時,該引擎當然是首選。由於鎖的粒度更小,寫操作不會鎖定全表,所以在併發較高時,使用Innodb引擎會提升效率。但是使用行級鎖也不是絕對的,如果在執行一個SQL語句時MySQL不能確定要掃描的範圍,InnoDB表同樣會鎖全表。
- MySQL 5.5及以後版本預設的儲存引擎
- innodb_file_per_table
- ON:獨立的表空間:tablename.ibd
- OFF:系統表空間:ibdataX
- MySQL 5.6以前預設為系統表空間
- 系統表空間和獨立表空間
- 系統表空間無法簡單的收縮檔案大小
- 獨立表空間可以通過optimize table收縮系統檔案
- 系統表空間會產生IO瓶頸
- 獨立表空間可以同時向多個檔案重新整理資料
- 建議:InnoDB使用獨立表空間
- 特性:
- InnoDB是一種事務性儲存引擎
- 完全支援事務的ACID特性
- 實現了SQL標準的四種隔離級別
- Redo Log和Undo Log
- InnoDB支援行級鎖(併發程度更高)
- InnoDB是一種事務性儲存引擎
- 適用場景:
- InnoDB適合於大多數OLTP應用
- 支援事務處理等
- 不加鎖讀取
- 支援外來鍵
- 支援行鎖
- 支援崩潰修復能力和併發控制
- 不支援FULLTEXT型別的索引
- 不儲存表的具體行數,掃描表來計算有多少行
- DELETE 表時,是一行一行的刪除
- InnoDB 把資料和索引存放在表空間裡面
- 跨平臺可直接拷貝使用
- InnoDB中必須包含AUTO_INCREMENT型別欄位的索引
- 表格很難被壓縮
選擇:
- 因為MyISAM相對簡單所以在效率上要優於InnoDB.如果系統讀多,寫少。對原子性要求低。那麼MyISAM最好的選擇。且MyISAM恢復速度快。可直接用備份覆蓋恢復。
- 如果系統讀少,寫多的時候,尤其是併發寫入高的時候。InnoDB就是首選了。
兩種型別都有自己優缺點,選擇那個完全要看自己的實際類弄。 - InnoDB:支援事務處理,支援外來鍵,支援崩潰修復能力和併發控制。如果需要對事務的完整性要求比較高(比如銀行),要求實現併發控制(比如售票),那選擇InnoDB有很大的優勢。如果需要頻繁的更新、刪除操作的資料庫,也可以選擇InnoDB,因為支援事務的提交(commit)和回滾(rollback)。
- MyISAM:插入資料快,空間和記憶體使用比較低。如果表主要是用於插入新記錄和讀出記錄,那麼選擇MyISAM能實現處理高效率。如果應用的完整性、併發性要求比較低,也可以使用。
- MEMORY:所有的資料都在記憶體中,資料的處理速度快,但是安全性不高。如果需要很快的讀寫速度,對資料的安全性要求較低,可以選擇MEMOEY。它對錶的大小有要求,不能建立太大的表。所以,這類資料庫只使用在相對較小的資料庫表。
- 注意,同一個資料庫也可以使用多種儲存引擎的表。如果一個表要求比較高的事務處理,可以選擇InnoDB。這個資料庫中可以將查詢要求比較高的表選擇MyISAM儲存。如果該資料庫需要一個用於查詢的臨時表,可以選擇MEMORY儲存引擎。
- 儲存結構
- 每個MyISAM在磁碟上儲存成三個檔案。第一個檔案的名字以表的名字開始,副檔名指出檔案型別。
.frm檔案儲存表定義。
資料檔案的副檔名為.MYD (MYData)。
索引檔案的副檔名是.MYI (MYIndex)。
- 每個MyISAM在磁碟上儲存成三個檔案。第一個檔案的名字以表的名字開始,副檔名指出檔案型別。
- 儲存空間
- MyISAM:可被壓縮,儲存空間較小。
- InnoDB:需要更多的記憶體和儲存,它會在主記憶體中建立其專用的緩衝池用於高速緩衝資料和索引。
- MyISAM的索引和資料是分開的,並且索引是有壓縮的,記憶體使用率就對應提高了不少。能載入更多索引,而Innodb是索引和資料是緊密捆綁的,沒有使用壓縮從而會造成Innodb比MyISAM體積龐大不小
- 事務處理
- MyISAM型別的表強調的是效能,其執行數度比InnoDB型別更快,但是不支援外來鍵、不提供事務支援。
- InnoDB提供事務支援事務,外部鍵(foreign key)等高階資料庫功能。
- SELECT、UPDATE、INSERT、Delete操作
- 如果執行大量的SELECT,MyISAM是更好的選擇。
如果你的資料執行大量的INSERT或UPDATE,出於效能方面的考慮,應該使用InnoDB表。
DELETE FROM table時,InnoDB不會重新建立表,而是一行一行的刪除。而MyISAM則是重新建立表。在innodb上如果要清空儲存有大量資料的表,最好使用truncate table這個命令。
- 如果執行大量的SELECT,MyISAM是更好的選擇。
- AUTO_INCREMENT
- MyISAM:可以和其他欄位一起建立聯合索引。引擎的自動增長列必須是索引,如果是組合索引,自動增長可以不是第一列,他可以根據前面幾列進行排序後遞增。
InnoDB:InnoDB中必須包含只有該欄位的索引。引擎的自動增長列必須是索引,如果是組合索引也必須是組合索引的第一列。
- MyISAM:可以和其他欄位一起建立聯合索引。引擎的自動增長列必須是索引,如果是組合索引,自動增長可以不是第一列,他可以根據前面幾列進行排序後遞增。
- 表的具體行數
- MyISAM:儲存有表的總行數,如果select count(*) from table;會直接取出該值。
- InnoDB:沒有儲存表的總行數,如果使用select count(*) from table;就會遍歷整個表,消耗相當大,但是在加了where後,myisam和innodb處理的方式都一樣。
- 全文索引
- MyISAM:支援 FULLTEXT型別的全文索引。不支援中文。
- InnoDB:不支援FULLTEXT型別的全文索引,但是innodb可以使用sphinx外掛支援全文索引,並且效果更好。
- 表鎖差異
- MyISAM:只支援表級鎖,只支援表級鎖,使用者在操作myisam表時,select,update,delete,insert語句都會給表自動加鎖。
- InnoDB:支援事務和行級鎖,是innodb的最大特色。行鎖大幅度提高了多使用者併發操作的新能。但是InnoDB的行鎖也不是絕對的,如果在執行一個SQL語句時MySQL不能確定要掃描的範圍,InnoDB表同樣會鎖全表, 例如update table set num=1 where name like “%aaa%”
對比項 | MyISAM | InnoDB |
---|---|---|
主外來鍵 | 不支援 | 支援 |
事務 | 不支援 | 支援 |
行表鎖 | 表鎖,即使操作一條記錄也會鎖住整個表,不適合高併發的操作 | 行鎖,操作時只鎖某一行,不對其他行有影響,適合高併發操作 |
索引型別 | 支援全文型別索引 | 不支援全文型別索引 |
快取 | 只快取索引,不快取真實資料 | 不僅快取索引還要快取真實資料,對記憶體要求較高,而且記憶體大小對效能有決定性的影響 |
表空間 | 小 | 大 |
效率 | 相對簡單,效率高 | 實現複雜,效率一般 |
跨平臺 | 表儲存成檔案形式,跨平臺方便 | 不支援跨平臺 |
關注點 | 效能 | 事務 |
預設安裝 | Y | Y |
儲存引擎-CSV
- 組成
- 資料以文字方式儲存檔案
- .csv檔案儲存內容
- .csm檔案儲存表的元資料,如表狀態和資料量
- .frm表結構
- 特點
- 以csv格式進行資料儲存
- 所有列都不能為null
- 不支援索引(不適合大表,不適合線上處理)
- 可以對資料檔案直接編輯(儲存文字檔案內容)
儲存引擎-Archive
- 組成
- 以zlib對錶資料進行壓縮,磁碟I/O更少
- 資料儲存在ARZ為字尾的檔案中
- 特點
- 只支援insert和select操作
- 只允許在自增ID列上加索引
- 使用場景
- 日誌和資料採集應用
儲存引擎-Memory
- 特點
- 檔案系統儲存特點,也稱Heap儲存引擎,所以資料儲存在記憶體中
- 支援Hash索引和BTree索引,MEMORY預設使用雜湊索引。速度比使用B型樹索引快。
- 所有欄位都是固定長度varchar(10)=char(10)
- 不支援Blog和Text等大欄位
- Memory儲存引擎使用表級鎖
- 最大大小由max_heap_table_size引數決定
- 每個基於MEMORY儲存引擎的表實際對應一個磁碟檔案。該檔案的檔名與表名相同,型別為frm型別。該檔案中只儲存表的結構。而其資料檔案,都是儲存在記憶體中,這樣有利於資料的快速處理,提高整個表的效率。
- Memory儲存引擎表 VS 臨時表
- 系統使用臨時表
- 超過限制使用MyISAM臨時表
- 未超限制使用Memory表
- create temporary table 建立的臨時表
- 系統使用臨時表
- 使用場景
- hash索引用於查詢或者是對映表(郵編和地區的對應表)
- 用於儲存資料分析中產生的中間表
- 用於快取週期性聚合資料的結果表
- memory資料容易丟失,所以要求資料可再生
- MEMORY用到的很少,因為它是把資料存到記憶體中,如果記憶體出現異常就會影響資料。如果重啟或者關機,所有資料都會消失。因此,基於MEMORY的表的生命週期很短,一般是一次性的。
儲存引擎-Ferderated
- 特點
- 提供了訪問遠端MySQL伺服器上表的方法
- 本地不儲存資料,資料全部放到遠端伺服器上
- 本地需要儲存表結構和遠端伺服器的連線資訊
- 使用場景
- 偶爾的統計分析及手工查詢
- 如何使用
- 預設禁止,啟用需要在啟動時增加ferderated引數
2.redo和undo 幹什麼用的?
Undo Log
Undo Log 是為了實現事務的原子性,在MySQL資料庫InnoDB儲存引擎中,還用Undo Log來實現多版本併發控制(簡稱:MVCC)。
- 事務的原子性(Atomicity)
事務中的所有操作,要麼全部完成,要麼不做任何操作,不能只做部分操作。如果在執行的過程中發生
了錯誤,要回滾(Rollback)到事務開始前的狀態,就像這個事務從來沒有執行過。
- 原理
Undo Log的原理很簡單,為了滿足事務的原子性,在操作任何資料之前,首先將資料備份到一個地方
(這個儲存資料備份的地方稱為Undo Log)。然後進行資料的修改。如果出現了錯誤或者使用者執行了
ROLLBACK語句,系統可以利用Undo Log中的備份將資料恢復到事務開始之前的狀態。
除了可以保證事務的原子性,Undo Log也可以用來輔助完成事務的持久化。
- 事務的永續性(Durability)
事務一旦完成,該事務對資料庫所做的所有修改都會持久的儲存到資料庫中。為了保證永續性,資料庫
系統會將修改後的資料完全的記錄到持久的儲存上。
-
用Undo Log實現原子性和持久化的事務的簡化過程
假設有A、B兩個資料,值分別為1,2。
A.事務開始.
B.記錄A=1到undo log.
C.修改A=3.
D.記錄B=2到undo log.
E.修改B=4.
F.將undo log寫到磁碟。
G.將資料寫到磁碟。
H.事務提交
這裡有一個隱含的前提條件:‘資料都是先讀到記憶體中,然後修改記憶體中的資料,最後將資料寫回磁碟’。
之所以能同時保證原子性和持久化,是因為以下特點:
A. 更新資料前記錄Undo log。
B. 為了保證永續性,必須將資料在事務提交前寫到磁碟。只要事務成功提交,資料必然已經持久化。
C. Undo log必須先於資料持久化到磁碟。如果在G,H之間系統崩潰,undo log是完整的,
可以用來回滾事務。D. 如果在A-F之間系統崩潰,因為資料沒有持久化到磁碟。所以磁碟上的資料還是保持在事務開始前的狀態。
缺陷:每個事務提交前將資料和Undo Log寫入磁碟,這樣會導致大量的磁碟IO,因此效能很低。
如果能夠將資料快取一段時間,就能減少IO提高效能。但是這樣就會喪失事務的永續性。因此引入了另外一
種機制來實現持久化,即Redo Log.
Redo Log
-
原理
和Undo Log相反,Redo Log記錄的是新資料的備份。在事務提交前,只要將Redo Log持久化即可,
不需要將資料持久化。當系統崩潰時,雖然資料沒有持久化,但是Redo Log已經持久化。系統可以根據
Redo Log的內容,將所有資料恢復到最新的狀態。 -
Undo + Redo事務的簡化過程
假設有A、B兩個資料,值分別為1,2.
A.事務開始.
B.記錄A=1到undo log.
C.修改A=3.
D.記錄A=3到redo log.
E.記錄B=2到undo log.
F.修改B=4.
G.記錄B=4到redo log.
H.將redo log寫入磁碟。
I.事務提交
-
Undo + Redo事務的特點
A. 為了保證永續性,必須在事務提交前將Redo Log持久化。
B. 資料不需要在事務提交前寫入磁碟,而是快取在記憶體中。
C. Redo Log 保證事務的永續性。
D. Undo Log 保證事務的原子性。
E. 有一個隱含的特點,資料必須要晚於redo log寫入持久儲存。
-
IO效能
Undo + Redo的設計主要考慮的是提升IO效能。雖說通過快取資料,減少了寫資料的IO.
但是卻引入了新的IO,即寫Redo Log的IO。如果Redo Log的IO效能不好,就不能起到提高效能的目的。
為了保證Redo Log能夠有比較好的IO效能,InnoDB 的 Redo Log的設計有以下幾個特點:
A. 儘量保持Redo Log儲存在一段連續的空間上。因此在系統第一次啟動時就會將日誌檔案的空間完全分配。
以順序追加的方式記錄Redo Log,通過順序IO來改善效能。B. 批量寫入日誌。日誌並不是直接寫入檔案,而是先寫入redo log buffer.當需要將日誌重新整理到磁碟時
(如事務提交),將許多日誌一起寫入磁碟.C. 併發的事務共享Redo Log的儲存空間,它們的Redo Log按語句的執行順序,依次交替的記錄在一起,
以減少日誌佔用的空間。
例如,Redo Log中的記錄內容可能是這樣的:記錄1: <trx1, insert …>
記錄2: <trx2, update …>
記錄3: <trx1, delete …>
記錄4: <trx3, update …>
記錄5: <trx2, insert …>
D. 因為C的原因,當一個事務將Redo Log寫入磁碟時,也會將其他未提交的事務的日誌寫入磁碟。
E. Redo Log上只進行順序追加的操作,當一個事務需要回滾時,它的Redo Log記錄也不會從
Redo Log中刪除掉。
02 – 恢復(Recovery)
-
恢復策略
前面說到未提交的事務和回滾了的事務也會記錄Redo Log,因此在進行恢復時,這些事務要進行特殊的
的處理.有2中不同的恢復策略:A. 進行恢復時,只重做已經提交了的事務。
B. 進行恢復時,重做所有事務包括未提交的事務和回滾了的事務。然後通過Undo Log回滾那些
未提交的事務。 -
InnoDB儲存引擎的恢復機制
MySQL資料庫InnoDB儲存引擎使用了B策略, InnoDB儲存引擎中的恢復機制有幾個特點:
A. 在重做Redo Log時,並不關心事務性。 恢復時,沒有BEGIN,也沒有COMMIT,ROLLBACK的行為。
也不關心每個日誌是哪個事務的。儘管事務ID等事務相關的內容會記入Redo Log,這些內容只是被當作
要操作的資料的一部分。B. 使用B策略就必須要將Undo Log持久化,而且必須要在寫Redo Log之前將對應的Undo Log寫入磁碟。
Undo和Redo Log的這種關聯,使得持久化變得複雜起來。為了降低複雜度,InnoDB將Undo Log看作
資料,因此記錄Undo Log的操作也會記錄到redo log中。這樣undo log就可以象資料一樣快取起來,
而不用在redo log之前寫入磁碟了。包含Undo Log操作的Redo Log,看起來是這樣的:
記錄1: <trx1, Undo log insert <undo_insert …>>
記錄2: <trx1, insert …>
記錄3: <trx2, Undo log insert <undo_update …>>
記錄4: <trx2, update …>
記錄5: <trx3, Undo log insert <undo_delete …>>
記錄6: <trx3, delete …>
C. 到這裡,還有一個問題沒有弄清楚。既然Redo沒有事務性,那豈不是會重新執行被回滾了的事務?
確實是這樣。同時Innodb也會將事務回滾時的操作也記錄到redo log中。回滾操作本質上也是
對資料進行修改,因此回滾時對資料的操作也會記錄到Redo Log中。一個回滾了的事務的Redo Log,看起來是這樣的:
記錄1: <trx1, Undo log insert <undo_insert …>>
記錄2: <trx1, insert A…>
記錄3: <trx1, Undo log insert <undo_update …>>
記錄4: <trx1, update B…>
記錄5: <trx1, Undo log insert <undo_delete …>>
記錄6: <trx1, delete C…>
記錄7: <trx1, insert C>
記錄8: <trx1, update B to old value>
記錄9: <trx1, delete A>
一個被回滾了的事務在恢復時的操作就是先redo再undo,因此不會破壞資料的一致性.
-
InnoDB儲存引擎中相關的函式
Redo: recv_recovery_from_checkpoint_start()
Undo: recv_recovery_rollback_active()
Undo Log的Redo Log: trx_undof_page_add_undo_rec_log()
3.hash索引是什麼,什麼儲存引擎支援? 有什麼優缺點?
雜湊索引(hash index)基於雜湊表實現,只有精確匹配索引所有列的査詢才有效。對 於每一行資料,儲存引擎都會對所有的索引列計算一個雜湊碼(hash code),雜湊碼是 一個較小的值,並且不同鍵值的行計算出來的雜湊碼也不一樣。雜湊索引將所有的雜湊 碼儲存在索引中,同時在雜湊表中儲存指向每個資料行的指標。
在My SQL中,只有Memory引擎顯式支援雜湊索引。這也是Memory引擎表的預設索 引型別,Memory引擎同時也支援B-Tree索引。值得一提的是,Memory引擎是支援非 唯一雜湊索引的,這在資料庫世界裡面是比較與眾不同的。如果多個列的雜湊值相同, 索引會以連結串列的方式存放多個記錄指標到同一個雜湊條目中。
B+樹是一個平衡的多叉樹,從根節點到每個葉子節點的高度差值不超過1,而且同層級的節點間有指標相互連結。
在B+樹上的常規檢索,從根節點到葉子節點的搜尋效率基本相當,不會出現大幅波動,而且基於索引的順序掃描時,也可以利用雙向指標快速左右移動,效率非常高。
因此,B+樹索引被廣泛應用於資料庫、檔案系統等場景。順便說一下,xfs檔案系統比ext3/ext4效率高很多的原因之一就是,它的檔案及目錄索引結構全部採用B+樹索引,而ext3/ext4的檔案目錄結構則採用Linked list, hashed B-tree、Extents/Bitmap等索引資料結構,因此在高I/O壓力下,其IOPS能力不如xfs。
雜湊索引就是採用一定的雜湊演算法,把鍵值換算成新的雜湊值,檢索時不需要類似B+樹那樣從根節點到葉子節點逐級查詢,只需一次雜湊演算法即可立刻定位到相應的位置,速度非常快。
如果是等值查詢,那麼雜湊索引明顯有絕對優勢,因為只需要經過一次演算法即可找到相應的鍵值;當然了,這個前提是,鍵值都是唯一的。如果鍵值不是唯一的,就需要先找到該鍵所在位置,然後再根據連結串列往後掃描,直到找到相應的資料;
從示意圖中也能看到,如果是範圍查詢檢索,這時候雜湊索引就毫無用武之地了,因為原先是有序的鍵值,經過雜湊演算法後,有可能變成不連續的了,就沒辦法再利用索引完成範圍查詢檢索;
同理,雜湊索引也沒辦法利用索引完成排序,以及like ‘xxx%’ 這樣的部分模糊查詢(這種部分模糊查詢,其實本質上也是範圍查詢);
雜湊索引也不支援多列聯合索引的最左匹配規則;
B+樹索引的關鍵字檢索效率比較平均,不像B樹那樣波動幅度大,在有大量重複鍵值情況下,雜湊索引的效率也是極低的,因為存在所謂的雜湊碰撞問題。
為索引自身只需儲存對應的雜湊值,所以索引的結構十分緊湊,這也讓雜湊索引査找的速度非常快。
(1)Hash 索引僅僅能滿足"=",“IN"和”<=>"查詢,不能使用範圍查詢。
由於 Hash 索引比較的是進行 Hash 運算之後的 Hash 值,所以它只能用於等值的過濾,不能用於基於範圍的過濾,因為經過相應的 Hash 演算法處理之後的 Hash 值的大小關係,並不能保證和Hash運算前完全一樣。
(2)Hash 索引無法被用來避免資料的排序操作。
由於 Hash 索引中存放的是經過 Hash 計算之後的 Hash 值,而且Hash值的大小關係並不一定和 Hash 運算前的鍵值完全一樣,所以資料庫無法利用索引的資料來避免任何排序運算;
(3)Hash 索引不能利用部分索引鍵查詢。
對於組合索引,Hash 索引在計算 Hash 值的時候是組合索引鍵合併後再一起計算 Hash 值,而不是單獨計算 Hash 值,所以通過組合索引的前面一個或幾個索引鍵進行查詢的時候,Hash 索引也無法被利用。
(4)Hash 索引在任何時候都不能避免表掃描。
前面已經知道,Hash 索引是將索引鍵通過 Hash 運算之後,將 Hash運算結果的 Hash 值和所對應的行指標資訊存放於一個 Hash 表中,由於不同索引鍵存在相同 Hash 值,所以即使取滿足某個 Hash 鍵值的資料的記錄條數,也無法從 Hash 索引中直接完成查詢,還是要通過訪問表中的實際資料進行相應的比較,並得到相應的結果。
(5)Hash 索引遇到大量Hash值相等的情況後效能並不一定就會比B-Tree索引高。
對於選擇性比較低的索引鍵,如果建立 Hash 索引,那麼將會存在大量記錄指標資訊存於同一個 Hash 值相關聯。這樣要定位某一條記錄時就會非常麻煩,會浪費多次表資料的訪問,而造成整體效能低下。
4.btree和b+tree有什麼樣的區別,對於範圍檢索來說,b+tree好在哪裡?
參考見:MySQL索引使用的資料結構:B-Tree和B+Tree
B-Tree 索引是 MySQL 資料庫中使用最為頻繁的索引型別,除了 Archive 儲存引擎之外的其他所有的儲存引擎都支援 B-Tree 索引。不僅僅在 MySQL 中是如此,實際上在其他的很多資料庫管理系統中B-Tree 索引也同樣是作為最主要的索引型別,這主要是因為 B-Tree 索引的儲存結構在資料庫的資料檢 索中有非常優異的表現。
一般來說, MySQL 中的 B-Tree 索引的物理檔案大多都是以 Balance Tree 的結構來儲存的,也就是所有實際需要的資料都存放於 Tree 的 Leaf Node ,而且到任何一個 Leaf Node 的最短路徑的長度都是完全相同的,所以我們大家都稱之為 B-Tree 索引當然,可能各種資料庫(或 MySQL 的各種儲存引擎)在存放自己的 B-Tree 索引的時候會對儲存結構稍作改造。如 Innodb 儲存引擎的 B-Tree 索引實際使用的儲存結構實際上是 B+Tree ,也就是在 B-Tree 資料結構的基礎上做了很小的改造,在每一個
Leaf Node 上面出了存放索引鍵的相關資訊之外,還儲存了指向與該 Leaf Node 相鄰的後一個 LeafNode 的指標資訊,這主要是為了加快檢索多個相鄰 Leaf Node 的效率考慮。
在 Innodb 儲存引擎中,存在兩種不同形式的索引,一種是 Cluster 形式的主鍵索引( Primary Key ),另外一種則是和其他儲存引擎(如 MyISAM 儲存引擎)存放形式基本相同的普通 B-Tree 索引,這種索引在 Innodb 儲存引擎中被稱為 Secondary Index 。下面我們通過圖示來針對這兩種索引的存放
形式做一個比較。
圖示中左邊為 Clustered 形式存放的 Primary Key ,右側則為普通的 B-Tree 索引。兩種 Root Node 和 Branch Nodes 方面都還是完全一樣的。而 Leaf Nodes 就出現差異了。在 Prim中, Leaf Nodes 存放的是表的實際資料,不僅僅包括主鍵欄位的資料,還包括其他欄位的資料據以主鍵值有序的排列。而 Secondary Index 則和其他普通的 B-Tree 索引沒有太大的差異,Leaf Nodes 出了存放索引鍵 的相關資訊外,還存放了 Innodb 的主鍵值。
所以,在 Innodb 中如果通過主鍵來訪問資料效率是非常高的,而如果是通過 Secondary Index 來訪問資料的話, Innodb 首先通過 Secondary Index 的相關資訊,通過相應的索引鍵檢索到 Leaf Node之後,需要再通過 Leaf Node 中存放的主鍵值再通過主鍵索引來獲取相應的資料行。MyISAM 儲存引擎的主鍵索引和非主鍵索引差別很小,只不過是主鍵索引的索引鍵是一個唯一且非空 的鍵而已。而且 MyISAM 儲存引擎的索引和 Innodb 的 Secondary Index 的儲存結構也基本相同,主要的區別只是 MyISAM 儲存引擎在 Leaf Nodes 上面出了存放索引鍵資訊之外,再存放能直接定位到 MyISAM 資料檔案中相應的資料行的資訊(如 Row Number ),但並不會存放主鍵的鍵值資訊
5.全文索引是怎麼回事?
一、概述
MySQL全文檢索是利用查詢關鍵字和查詢列內容之間的相關度進行檢索,可以利用全文索引來提高匹配的速度。
二、語法
MATCH (col1,col2,…) AGAINST (expr [search_modifier])
search_modifier: { IN BOOLEAN MODE | WITH QUERY EXPANSION }
例如:SELECT * FROM tab_name WHERE MATCH (‘列名1,列名2…列名n’) AGAINST(‘詞1 詞2 詞3 … 詞m’);
即:MATCH 相當於要匹配的列,而 AGAINST 就是要找的內容。
這裡的table需要是MyISAM型別的表,col1、col2 必須是char、varchar或text型別,在查詢之前需要在 col1 和 col2 上分別建立全文索引(FULLTEXT索引)。
三、檢索方式
1、自然語言檢索: IN NATURAL LANGUAGE MODE
2、布林檢索: IN BOOLEAN MODE
剔除一半匹配行以上都有的詞,譬如說,每個行都有this這個字的話,那用this去查時,會找不到任何結果,這在記錄條數特別多時很有用,原因是資料庫認為把所有行都找出來是沒有意義的,這時,this幾乎被當作是stopword(中斷詞);但是若只有兩行記錄時,是啥鬼也查不出來的,因為每個字都出現50%(或以上),要避免這種狀況,請用IN BOOLEAN MODE。
● IN BOOLEAN MODE的特色:
·不剔除50%以上符合的row。
·不自動以相關性反向排序。
·可以對沒有FULLTEXT index的欄位進行搜尋,但會非常慢。
·限制最長與最短的字串。
·套用Stopwords。
● 搜尋語法規則:
+ 一定要有(不含有該關鍵詞的資料條均被忽略)。
- 不可以有(排除指定關鍵詞,含有該關鍵詞的均被忽略)。
> 提高該條匹配資料的權重值。
< 降低該條匹配資料的權重值。
~ 將其相關性由正轉負,表示擁有該字會降低相關性(但不像 - 將之排除),只是排在較後面權重值降低。
* 萬用字,不像其他語法放在前面,這個要接在字串後面。
" " 用雙引號將一段句子包起來表示要完全相符,不可拆字。
SELECT * FROM articles WHERE MATCH (title,content) AGAINST ('+apple -banana' IN BOOLEAN MODE);
+ 表示AND,即必須包含。- 表示NOT,即必須不包含。即:返回記錄必需包含 apple,且不能包含 banner。
SELECT * FROM articles WHERE MATCH (title,content) AGAINST ('apple banana' IN BOOLEAN MODE);
apple和banana之間是空格,空格表示OR。即:返回記錄至少包含apple、banana中的一個。
SELECT * FROM articles WHERE MATCH (title,content) AGAINST ('+apple banana' IN BOOLEAN MODE);
返回記錄必須包含apple,同時banana可包含也可不包含,若包含的話會獲得更高的權重。
SELECT * FROM articles WHERE MATCH (title,content) AGAINST ('+apple ~banana' IN BOOLEAN MODE);
~ 是我們熟悉的異或運算子。返回記錄必須包含apple,若也包含了banana會降低權重。
但是它沒有 +apple -banana 嚴格,因為後者如果包含banana壓根就不返回。
SELECT * FROM articles WHERE MATCH (title,content) AGAINST ('+apple +(>banana <orange)' IN BOOLEAN MODE);
返回必須同時包含“apple banana”或者必須同時包含“apple orange”的記錄。
若同時包含“apple banana”和“apple orange”的記錄,則“apple banana”的權重高於“apple orange”的權重。
3、查詢擴充套件檢索: WITH QUERY EXPANSION
四、MySQL全文檢索的條件限制
1、在MySQL5.6以下,只有MyISAM表支援全文檢索。在MySQL5.6以上Innodb引擎表也提供支援全文檢索。
2、相應欄位建立FULLTEXT索引
五、與全文檢索相關的系統變數:
ft_min_word_len = 全文檢索的最小許可字元(預設4,通過 SHOW VARIABLES LIKE ‘ft_min_word_len’ 可檢視),中文通常是兩個字就是一個詞,所以做中文的話需要修改這個值為2最好。
六、總結事項
1、預設搜尋是不分大小寫,若要分大小寫,columne 的 character set要從utf8改成utf8_bin。
2、預設 MATCH…AGAINST 是以相關性排序,由高到低。
3、MATCH(title, content)裡的欄位必須和FULLTEXT(title, content)裡的欄位一模一樣。
如果只要單查title或content一個欄位,那得另外再建一個 FULLTEXT(title) 或 FULLTEXT(content),也因為如此,MATCH()的欄位一定不能跨table,但是另外兩種搜尋方式好像可以。
4、MySQL不支援中文全文索引,原因很簡單:與英文不同,中文的文字是連著一起寫的,中間沒有MySQL能找到分詞的地方,截至目前MySQL5.6版本是如此,但是有變通的辦法,就是將整句的中文分詞,並按urlencode、區位碼、base64、拼音等進行編碼使之以“字母+數字”的方式儲存於資料庫中。
6.MySQL 中 InnoDB 支援的四種事務隔離級別是什麼? 有什麼區別
隔離級別 | 髒讀(Dirty Read) | 不可重複讀(NonRepeatable Read) | 幻讀(Phantom Read) |
---|---|---|---|
未提交讀(Read uncommitted) | 可能 | 可能 | 可能 |
已提交讀(Read committed) | 不可能 | 可能 | 可能 |
可重複讀(Repeatable read) | 不可能 | 不可能 | 可能 |
可序列化(Serializable ) | 不可能 | 不可能 | 不可能 |
- 未提交讀(Read Uncommitted):允許髒讀,也就是可能讀取到其他會話中未提交事務修改的資料
- 提交讀(Read Committed):只能讀取到已經提交的資料。Oracle等多數資料庫預設都是該級別 (不重複讀)
- 可重複讀(Repeated Read):可重複讀。在同一個事務內的查詢都是事務開始時刻一致的,InnoDB預設級別。在SQL標準中,該隔離級別消除了不可重複讀,但是還存在幻象讀
- 序列讀(Serializable):完全序列化的讀,每次讀都需要獲得表級共享鎖,讀寫相互都會阻塞
7.MYSQL中的間隙鎖是怎麼回事,有幾種方式產生間隙鎖?
參考文章:InnoDB Gap鎖
MySQL InnoDB支援三種行鎖定方式:
- 行鎖(Record Lock):鎖直接加在索引記錄上面。
- 間隙鎖(Gap Lock):鎖加在不存在的空閒空間,可以是兩個索引記錄之間,也可能是第一個索引記錄之前或最後一個索引之後的空間。
- Next-Key Lock:行鎖與間隙鎖組合起來用就叫做Next-Key Lock。
什麼是間隙鎖
當我們用範圍條件而不是相等條件檢索資料,並請求共享或排他鎖時,InnoDB會給符合條件的已有資料記錄的索引項加鎖;對於鍵值在條件範圍內但不存在的記錄,叫做“間隙(GAP)”,InnoDB也會對這個“間隙”加鎖,這種鎖機制就是所謂的間隙鎖(NEXT-KEY)鎖。
因為Query執行過程中通過範圍查詢的話,他會鎖定整個範圍內所有的索引鍵值,即使這個鍵值並不存在。
間隙鎖有一個比較致命的弱點,就是當鎖定一個範圍鍵值之後,即使某些不存在的鍵值也會被無辜的鎖定,而造成在鎖定的時候無法插入鎖定值範圍內的任何資料,在某些場景下這可能會針對性造成很大的危害。
預設情況下,InnoDB工作在可重複讀隔離級別下,並且以Next-Key Lock的方式對資料行進行加鎖,這樣可以有效防止幻讀的發生。Next-Key Lock是行鎖與間隙鎖的組合,這樣,當InnoDB掃描索引記錄的時候,會首先對選中的索引記錄加上行鎖(Record Lock),再對索引記錄兩邊的間隙(向左掃描掃到第一個比給定引數小的值, 向右掃描掃描到第一個比給定引數大的值, 然後以此為界,構建一個區間)加上間隙鎖(Gap Lock)。如果一個間隙被事務T1加了鎖,其它事務是不能在這個間隙插入記錄的。
間隙鎖在InnoDB的唯一作用就是防止其它事務的插入操作,以此來達到防止幻讀的發生,所以間隙鎖不分什麼共享鎖與排它鎖。另外,在上面的例子中,我們選擇的是一個普通(非唯一)索引欄位來測試的,這不是隨便選的,因為如果InnoDB掃描的是一個主鍵、或是一個唯一索引的話,那InnoDB只會採用行鎖方式來加鎖,而不會使用Next-Key Lock的方式,也就是說不會對索引之間的間隙加鎖。
要禁止間隙鎖的話,可以把隔離級別降為讀已提交,或者開啟引數innodb_locks_unsafe_for_binlog。
innodb實現可重複讀和防止幻讀,用的是讀取快照的方式。間隙鎖的目的只是為了事務中的防止刪除或修改不該被刪除或修改的資料而已,因此在innodb中insert語句是沒有間隙鎖的,只有在update和delete語句中才存在間隙鎖。
間隙鎖鎖定了輔助索引兩個葉子節點之間的內容,會造成鎖定多餘區域的資料。
在可重複讀的隔離級別下,檢索條件必須有索引(非唯一索引)的情況下,先delete再insert的操作時常會導致死鎖情況的出現。
應用程式sql中,在做刪除或者更新操作中,對於過濾條件儘量選擇主鍵列或者唯一索引列。
8.能談談mysql實現讀寫分離的原理嗎,和儲存引擎有什麼關係?
參考:【mysql 讀寫分離】10分鐘瞭解讀寫分離的作用;MySQL 主從複製與讀寫分離概念及架構分析;Mysql主從配置,實現讀寫分離
主伺服器(Master)負責網站NonQuery操作,從伺服器負責Query操作,使用者可以根據網站功能模特性塊固定訪問Slave伺服器,或者自己寫個池或佇列,自由為請求分配從伺服器連線。主從伺服器利用MySQL的二進位制日誌檔案,實現資料同步。二進位制日誌由主伺服器產生,從伺服器響應獲取同步資料庫。
1、 mysq支援的複製型別
1) 基於語句的複製。在伺服器上執行sql語句,在從伺服器上執行同樣的語句,mysql預設採用基於語句的複製,執行效率高。
2) 基於行的複製。把改變的內容複製過去,而不是把命令在從伺服器上執行一遍。
3) 混合型別的複製。預設採用基於語句的複製,一旦發現基於語句無法精確複製時,就會採用基於行的複製。
2、 複製的工作過程
1) 在每個事務更新資料完成之前,master在二進位制日誌記錄這些改變。寫入二進位制日誌完成後,master通知儲存引擎提交事務。
2) Slave將master的binary log複製到其中繼日誌。首先slave開始一個工作執行緒(I/O),I/O執行緒在master上開啟一個普通的連線,然後開始binlog dump process。binlog dump process從master的二進位制日誌中讀取事件,如果已經跟上master,它會睡眠並等待master產生新的事件,I/O執行緒將這些事件寫入中繼日誌。
3) Sql slave thread(sql從執行緒)處理該過程的最後一步,sql執行緒從中繼日誌讀取事件,並重放其中的事件而更新slave資料,使其與master中的資料一致,只要該執行緒與I/O執行緒保持一致,中繼日誌通常會位於os快取中,所以中繼日誌的開銷很小。