Mysql資料庫概念彙總
Mysql資料庫知識彙總
1.資料庫正規化
1.第一正規化(1NF):屬性不可拆分 或 無重複的列
3.第三正規化(3NF):消除傳遞依賴
4.BC正規化(BCNF):(候選鍵存在多個屬性時,多個主屬性直接要消除傳遞依賴關係)
(1)所有非主屬性對每一個碼都是完全函式依賴;
(2)所有的主屬性對於每一個不包含它的碼,也是完全函式依賴;
(3)沒有任何屬性完全函式依賴於非碼的任意一個組合。
2.MySQL的binlog有有幾種錄入格式?分別有什麼區別?
有三種格式,statement,row和mixed。
statement模式下,每一條會修改資料的sql都會記錄在binlog中。不需要記錄每一行的變化,減少了binlog日誌量,節約了IO,提高效能。由於sql的執行是有上下文的,因此在儲存的時候需要儲存相關的資訊,同時還有一些使用了函式之類的語句無法被記錄複製。
row級別下,不記錄sql語句上下文相關資訊,僅儲存哪條記錄被修改。記錄單元為每一行的改動,基本是可以全部記下來但是由於很多操作,會導致大量行的改動(比如alter table),因此這種模式的檔案儲存的資訊太多,日誌量太大。
mixed,一種折中的方案,普通操作使用statement記錄,當無法使用statement的時候使用row。
3.引擎
常用的儲存引擎有以下:
Innodb引擎:Innodb引擎提供了對資料庫ACID事務的支援。並且還提供了行級鎖和外來鍵的約束。它的設計的目標就是處理大資料容量的資料庫系統。
MyIASM引擎(原本Mysql的預設引擎):不提供事務的支援,也不支援行級鎖和外來鍵。
MEMORY引擎:所有的資料都在記憶體中,資料的處理速度快,但是安全性不高。
MySQL儲存引擎MyISAM與InnoDB區別
MyISAM索引與InnoDB索引的區別?
InnoDB是聚集索引,使用B+Tree作為索引結構,資料檔案是和(主鍵)索引綁在一起的(表資料檔案本身就是按B+Tree組織的一個索引結構),必須要有主鍵,通過主鍵索引效率很高。但是輔助索引需要兩次查詢,先查詢到主鍵,然後再通過主鍵查詢到資料。因此,主鍵不應該過大,因為主鍵太大,其他索引也都會很大。
MyISAM是非聚集索引,也是使用B+Tree作為索引結構,索引和資料檔案是分離的,索引儲存的是資料檔案的指標。主鍵索引和輔助索引是獨立的。
InnoDB的B+樹主鍵索引的葉子節點就是資料檔案,輔助索引的葉子節點是主鍵的值;而MyISAM的B+樹主鍵索引和輔助索引的葉子節點都是資料檔案的地址指標。
4.索引
索引是一種特殊的檔案(InnoDB資料表上的索引是表空間的一個組成部分),它們包含著對資料表裡所有記錄的引用指標
索引的優缺點
索引的優點
可以大大加快資料的檢索速度,這也是建立索引的最主要的原因。
通過使用索引,可以在查詢的過程中,使用優化隱藏器,提高系統的效能。
索引的缺點
時間方面:建立索引和維護索引要耗費時間,具體地,當對錶中的資料進行增加、刪除和修改的時候,索引也要動態的維護,會降低增/改/刪的執行效率;
空間方面:索引需要佔物理空間。
mysql索引
索引是在儲存引擎層實現的,而不是在伺服器層實現的,所以不同儲存引擎具有不同的索引型別和實現。
B+ Tree 索引
-
是大多數 MySQL 儲存引擎的預設索引型別。
-
因為不再需要進行全表掃描,只需要對樹進行搜尋即可,所以查詢速度快很多。
-
因為 B+ Tree 的有序性,所以除了用於查詢,還可以用於排序和分組。
-
可以指定多個列作為索引列,多個索引列共同組成鍵。
-
適用於全鍵值、鍵值範圍和鍵字首查詢,其中鍵字首查詢只適用於最左字首查詢。如果不是按照索引列的順序進行查詢,則無法使用索引。
InnoDB 的 B+Tree 索引分為主索引和輔助索引。主索引的葉子節點 data 域記錄著完整的資料記錄,這種索引方式被稱為聚簇索引。因為無法把資料行存放在兩個不同的地方,所以一個表只能有一個聚簇索引。
輔助索引的葉子節點的 data 域記錄著主鍵的值,因此在使用輔助索引進行查詢時,需要先查詢到主鍵值,然後再到主索引中進行查詢,這個過程也被稱作回表。
雜湊索引
雜湊索引能以 O(1) 時間進行查詢,但是失去了有序性:
- 無法用於排序與分組;
- 只支援精確查詢,無法用於部分查詢和範圍查詢。
InnoDB 儲存引擎有一個特殊的功能叫“自適應雜湊索引”,當某個索引值被使用的非常頻繁時,會在 B+Tree 索引之上再建立一個雜湊索引,這樣就讓 B+Tree 索引具有雜湊索引的一些優點,比如快速的雜湊查詢。
全文索引
MyISAM 儲存引擎支援全文索引,用於查詢文字中的關鍵詞,而不是直接比較是否相等。
查詢條件使用 MATCH AGAINST,而不是普通的 WHERE。
全文索引使用倒排索引實現,它記錄著關鍵詞到其所在文件的對映。
InnoDB 儲存引擎在 MySQL 5.6.4 版本中也開始支援全文索引。
空間資料索引
MyISAM 儲存引擎支援空間資料索引(R-Tree),可以用於地理資料儲存。空間資料索引會從所有維度來索引資料,可以有效地使用任意維度來進行組合查詢。
必須使用 GIS 相關的函式來維護資料。
索引使用場景(重點)
where
上圖中,根據id查詢記錄,因為id欄位僅建立了主鍵索引,因此此SQL執行可選的索引只有主鍵索引,如果有多個,最終會選一個較優的作為檢索的依據。
order by
當使用order by將查詢結果按照某個欄位排序時,如果該欄位沒有建立索引,那麼執行計劃會將查詢出的所有資料使用外部排序(將資料從硬碟分批讀取到記憶體使用內部排序,最後合併排序結果),這個操作是很影響效能的,因為需要將查詢涉及到的所有資料從磁碟中讀到記憶體(如果單條資料過大或者資料量過多都會降低效率),更無論讀到記憶體之後的排序了。
我們對該欄位建立索引 alter table 表名 add index(欄位名) ,那麼由於索引本身是有序的,因此直接按照索引的順序和對映關係逐條取出資料即可。而且如果分頁的,那麼只用取出索引表某個範圍內的索引對應的資料,而不用像上述那取出所有資料進行排序再返回某個範圍內的資料。(從磁碟取資料是最影響效能的)
索引型別
主鍵索引: 資料列不允許重複,不允許為NULL,一個表只能有一個主鍵。
唯一索引: 資料列不允許重複,允許為NULL值,一個表允許多個列建立唯一索引。
可以通過 ALTER TABLE table_name ADD UNIQUE (column); 建立唯一索引
可以通過 ALTER TABLE table_name ADD UNIQUE (column1,column2); 建立唯一組合索引
普通索引: 基本的索引型別,沒有唯一性的限制,允許為NULL值。
可以通過ALTER TABLE table_name ADD INDEX index_name (column);建立普通索引
可以通過ALTER TABLE table_name ADD INDEX index_name(column1, column2, column3);建立組合索引
全文索引: 是目前搜尋引擎使用的一種關鍵技術。
可以通過ALTER TABLE table_name ADD FULLTEXT (column);建立全文索引
字首索引
語法:index(field(10)),使用欄位值的前10個字元建立索引,預設是使用欄位的全部內容建立索引。
前提:字首的標識度高。比如密碼就適合建立字首索引,因為密碼幾乎各不相同。
實操的難度:在於字首擷取的長度。
我們可以利用select count(*)/count(distinct left(password,prefixLen));,通過從調整prefixLen的值(從1自增)檢視不同字首長度的一個平均匹配度,接近1時就可以了(表示一個密碼的前prefixLen個字元幾乎能確定唯一一條記錄)
什麼是最左字首原則?什麼是最左匹配原則
顧名思義,就是最左優先,在建立多列索引時,要根據業務需求,where子句中使用最頻繁的一列放在最左邊。
最左字首匹配原則,非常重要的原則,mysql會一直向右匹配直到遇到範圍查詢(>、<、between、like)就停止匹配,比如a = 1 and b = 2 and c > 3 and d = 4 如果建立(a,b,c,d)順序的索引,d是用不到索引的,如果建立(a,b,d,c)的索引則都可以用到,a,b,d的順序可以任意調整。
=和in可以亂序,比如a = 1 and b = 2 and c = 3 建立(a,b,c)索引可以任意順序,mysql的查詢優化器會幫你優化成索引可以識別的形式
B樹和B+樹的區別
在B樹中,你可以將鍵和值存放在內部節點和葉子節點;但在B+樹中,內部節點都是鍵,沒有值,葉子節點同時存放鍵和值。
B+樹的葉子節點有一條鏈相連,而B樹的葉子節點各自獨立。
使用B樹的好處
B樹可以在內部節點同時儲存鍵和值,因此,把頻繁訪問的資料放在靠近根節點的地方將會大大提高熱點資料的查詢效率。這種特性使得B樹在特定資料重複多次查詢的場景中更加高效。
使用B+樹的好處
由於B+樹的內部節點只存放鍵,不存放值,因此,一次讀取,可以在記憶體頁中獲取更多的鍵,有利於更快地縮小查詢範圍。 B+樹的葉節點由一條鏈相連,因此,當需要進行一次全資料遍歷的時候,B+樹只需要使用O(logN)時間找到最小的一個節點,然後通過鏈進行O(N)的順序遍歷即可。而B樹則需要對樹的每一層進行遍歷,這會需要更多的記憶體置換次數,因此也就需要花費更多的時間
Hash索引和B+樹索引有什麼區別或者說優劣呢?
首先要知道Hash索引和B+樹索引的底層實現原理:
hash索引底層就是hash表,進行查詢時,呼叫一次hash函式就可以獲取到相應的鍵值,之後進行回表查詢獲得實際資料。B+樹底層實現是多路平衡查詢樹。對於每一次的查詢都是從根節點出發,查詢到葉子節點方可以獲得所查鍵值,然後根據查詢判斷是否需要回表查詢資料。
hash索引進行等值查詢更快(一般情況下),但是卻無法進行範圍查詢。
因為在hash索引中經過hash函式建立索引之後,索引的順序與原順序無法保持一致,不能支援範圍查詢。而B+樹的的所有節點皆遵循(左節點小於父節點,右節點大於父節點,多叉樹也類似),天然支援範圍。
hash索引不支援使用索引進行排序,原理同上。
hash索引不支援模糊查詢以及多列索引的最左字首匹配。原理也是因為hash函式的不可預測。AAAA和AAAAB的索引沒有相關性。
hash索引任何時候都避免不了回表查詢資料,而B+樹在符合某些條件(聚簇索引,覆蓋索引等)的時候可以只通過索引完成查詢。
hash索引雖然在等值查詢上較快,但是不穩定。效能不可預測,當某個鍵值存在大量重複的時候,發生hash碰撞,此時效率可能極差。而B+樹的查詢效率比較穩定,對於所有的查詢都是從根節點到葉子節點,且樹的高度較低。
因此,在大多數情況下,直接選擇B+樹索引可以獲得穩定且較好的查詢速度。而不需要使用hash索引。
5.事務(重點)
資料庫事務
事務是一個不可分割的資料庫操作序列,也是資料庫併發控制的基本單位,其執行的結果必須使資料庫從一種一致性狀態變到另一種一致性狀態。事務是邏輯上的一組操作,要麼都執行,要麼都不執行。
事務四大特性(ACID)、
原子性: 事務是最小的執行單位,不允許分割。事務的原子性確保動作要麼全部完成,要麼完全不起作用;
一致性: 執行事務前後,資料保持一致,多個事務對同一個資料讀取的結果是相同的;
隔離性: 併發訪問資料庫時,一個使用者的事務不被其他事務所幹擾,各併發事務之間資料庫是獨立的;
永續性: 一個事務被提交之後。它對資料庫中資料的改變是持久的,即使資料庫發生故障也不應該對其有任何影響。
事務的隔離級別
為了達到事務的四大特性,資料庫定義了4種不同的事務隔離級別,由低到高依次為Read uncommitted、Read committed、Repeatable read、Serializable,這四個級別可以逐個解決髒讀、不可重複讀、幻讀這幾類問題。
隔離級別 | 髒讀 | 不可重複讀 | 幻讀 |
---|---|---|---|
讀未提交 | √ | √ | √ |
讀提交 | × | √ | √ |
可重複讀 | × | × | √ |
可序列化 | × | × | × |
- 髒讀(Drity Read):某個事務已更新一份資料,另一個事務在此時讀取了同一份資料,由於某些原因,前一個RollBack了操作,則後一個事務所讀取的資料就會是不正確的。
- 不可重複讀(Non-repeatable read):在一個事務的兩次查詢之中資料不一致,這可能是兩次查詢過程中間插入了一個事務更新的原有的資料。
- 幻讀(Phantom Read):在一個事務的兩次查詢中資料筆數不一致,例如有一個事務查詢了幾列(Row)資料,而另一個事務卻在此時插入了新的幾列資料,先前的事務在接下來的查詢中,就會發現有幾列資料是它先前所沒有的
Mysql 預設採用的 REPEATABLE_READ隔離級別 Oracle 預設採用的 READ_COMMITTED隔離級別
事務隔離機制的實現基於鎖機制和併發排程。其中併發排程使用的是MVVC(多版本併發控制),通過儲存修改的舊版本資訊來支援併發一致性讀和回滾等特性。
隔離級別越低,事務請求的鎖越少,所以大部分資料庫系統的隔離級別都是READ-COMMITTED(讀取提交內容):,但是你要知道的是InnoDB 儲存引擎預設使用 REPEATABLE-READ(可重讀)並不會有任何效能損失。
InnoDB 儲存引擎在 分散式事務 的情況下一般會用到SERIALIZABLE(可序列化)隔離級別。
6.鎖
MyISAM和InnoDB儲存引擎使用的鎖:
MyISAM採用表級鎖(table-level locking)。
InnoDB支援行級鎖(row-level locking)和表級鎖,預設為行級鎖
行級鎖,表級鎖和頁級鎖對比
- 行級鎖 行級鎖是Mysql中鎖定粒度最細的一種鎖,表示只針對當前操作的行進行加鎖。行級鎖能大大減少資料庫操作的衝突。其加鎖粒度最小,但加鎖的開銷也最大。行級鎖分為共享鎖 和 排他鎖。
特點:開銷大,加鎖慢;會出現死鎖;鎖定粒度最小,發生鎖衝突的概率最低,併發度也最高。
- 表級鎖 表級鎖是MySQL中鎖定粒度最大的一種鎖,表示對當前操作的整張表加鎖,它實現簡單,資源消耗較少,被大部分MySQL引擎支援。最常使用的MYISAM與INNODB都支援表級鎖定。表級鎖定分為表共享讀鎖(共享鎖)與表獨佔寫鎖(排他鎖)。
特點:開銷小,加鎖快;不會出現死鎖;鎖定粒度大,發出鎖衝突的概率最高,併發度最低。
- 頁級鎖 頁級鎖是MySQL中鎖定粒度介於行級鎖和表級鎖中間的一種鎖。表級鎖速度快,但衝突多,行級衝突少,但速度慢。所以取了折衷的頁級,一次鎖定相鄰的一組記錄。
特點:開銷和加鎖時間界於表鎖和行鎖之間;會出現死鎖;鎖定粒度界於表鎖和行鎖之間,併發度一般
從鎖的類別上分MySQL都有哪些鎖呢?
從鎖的類別上來講,有共享鎖和排他鎖。
共享鎖: 又叫做讀鎖。 當用戶要進行資料的讀取時,對資料加上共享鎖。共享鎖可以同時加上多個。
排他鎖: 又叫做寫鎖。 當用戶要進行資料的寫入時,對資料加上排他鎖。排他鎖只可以加一個,他和其他的排他鎖,共享鎖都相斥。
用上面的例子來說就是使用者的行為有兩種,一種是來看房,多個使用者一起看房是可以接受的。 一種是真正的入住一晚,在這期間,無論是想入住的還是想看房的都不可以。
鎖的粒度取決於具體的儲存引擎,InnoDB實現了行級鎖,頁級鎖,表級鎖。
他們的加鎖開銷從大到小,併發能力也是從大到小。
MySQL中InnoDB引擎的行鎖是怎麼實現的?
InnoDB是基於索引來完成行鎖
例: select * from tab_with_index where id = 1 for update;
for update 可以根據條件來完成行鎖鎖定,並且 id 是有索引鍵的列,如果 id 不是索引鍵那麼InnoDB將完成表鎖,併發將無從談起
InnoDB儲存引擎的鎖的演算法有三種
Record lock:單個行記錄上的鎖
Gap lock:間隙鎖,鎖定一個範圍,不包括記錄本身
Next-key lock:record+gap 鎖定一個範圍,包含記錄本身
相關知識點:
innodb對於行的查詢使用next-key lock
Next-locking keying為了解決Phantom Problem幻讀問題
當查詢的索引含有唯一屬性時,將next-key lock降級為record key
Gap鎖設計的目的是為了阻止多個事務將記錄插入到同一範圍內,而這會導致幻讀問題的產生
有兩種方式顯式關閉gap鎖:(除了外來鍵約束和唯一性檢查外,其餘情況僅使用record lock) A. 將事務隔離級別設定為RC B. 將引數innodb_locks_unsafe_for_binlog設定為1
什麼是死鎖?怎麼解決?
死鎖是指兩個或多個事務在同一資源上相互佔用,並請求鎖定對方的資源,從而導致惡性迴圈的現象。
常見的解決死鎖的方法
1、如果不同程式會併發存取多個表,儘量約定以相同的順序訪問表,可以大大降低死鎖機會。
2、在同一個事務中,儘可能做到一次鎖定所需要的所有資源,減少死鎖產生概率;
3、對於非常容易產生死鎖的業務部分,可以嘗試使用升級鎖定顆粒度,通過表級鎖定來減少死鎖產生的概率;
如果業務處理不好可以用分散式事務鎖或者使用樂觀鎖
資料庫的樂觀鎖和悲觀鎖
資料庫管理系統(DBMS)中的併發控制的任務是確保在多個事務同時存取資料庫中同一資料時不破壞事務的隔離性和統一性以及資料庫的統一性。樂觀併發控制(樂觀鎖)和悲觀併發控制(悲觀鎖)是併發控制主要採用的技術手段。
悲觀鎖:假定會發生併發衝突,遮蔽一切可能違反資料完整性的操作。在查詢完資料的時候就把事務鎖起來,直到提交事務。實現方式:使用資料庫中的鎖機制
樂觀鎖:假設不會發生併發衝突,只在提交操作時檢查是否違反資料完整性。在修改資料的時候把事務鎖起來,通過version的方式來進行鎖定。實現方式:樂觀鎖一般會使用版本號機制或CAS演算法實現。
CAS演算法:CAS演算法涉及到三個運算元:需要讀寫的記憶體值V、進行比較的值A、擬寫入的新值B。當且僅當V的值等於A時,CAS通過原子方式用新值B來更新V值,否則不會執行任何操作(比較和替換是原子一個原子操作)。一般情況下是一個自旋轉操作,即不斷的重試。
兩種鎖的使用場景
從上面對兩種鎖的介紹,我們知道兩種鎖各有優缺點,不可認為一種好於另一種,像樂觀鎖適用於寫比較少的情況下(多讀場景),即衝突真的很少發生的時候,這樣可以省去了鎖的開銷,加大了系統的整個吞吐量。
但如果是多寫的情況,一般會經常產生衝突,這就會導致上層應用會不斷的進行retry,這樣反倒是降低了效能,所以一般多寫的場景下用悲觀鎖就比較合適。
7.檢視
所謂檢視,本質上是一種虛擬表,在物理上是不存在的,其內容與真實的表相似,包含一系列帶有名稱的列和行資料。但是,檢視並不在資料庫中以儲存的資料值形式存在。行和列資料來自定義檢視的查詢所引用基本表,並且在具體引用檢視時動態生成。
檢視使開發者只關心感興趣的某些特定資料和所負責的特定任務,只能看到檢視中所定義的資料,而不是檢視所引用表中的資料,從而提高了資料庫中資料的安全性。
8.資料庫效能與優化
大表資料查詢優化
1.優化shema、sql語句+索引;
2.第二加快取,memcached, redis;
3.主從複製,讀寫分離;
4.垂直拆分,根據你模組的耦合度,將一個大的系統分為多個小的系統,也就是分散式系統;
5.水平切分,針對資料量大的表,這一步最麻煩,最能考驗技術水平,要選擇一個合理的sharding key, 為了有好的查詢效率,表結構也要改動,做一定的冗餘,應用也要改,sql中儘量帶sharding key,將資料定位到限定的表上去查,而不是掃描全部的表;
mysql 分頁
LIMIT 子句可以被用於強制 SELECT 語句返回指定的記錄數。LIMIT 接受一個或兩個數字引數。引數必須是一個整數常量。如果給定兩個引數,第一個引數指定第一個返回記錄行的偏移量,第二個引數指定返回記錄行的最大數目。初始記錄行的偏移量是 0(而不是 1)
mysql> SELECT * FROM table LIMIT 5,10; // 檢索記錄行 6-15
為了檢索從某一個偏移量到記錄集的結束所有的記錄行,可以指定第二個引數為 -1:
mysql> SELECT * FROM table LIMIT 95,-1; // 檢索記錄行 96-last.
慢查詢日誌(實用性強)
用於記錄執行時間超過某個臨界值的SQL日誌,用於快速定位慢查詢,為我們的優化做參考。
開啟慢查詢日誌
配置項:slow_query_log
可以使用show variables like ‘slov_query_log’檢視是否開啟,如果狀態值為OFF,可以使用set GLOBAL slow_query_log = on來開啟,它會在datadir下產生一個xxx-slow.log的檔案。
設定臨界時間
配置項:long_query_time
檢視:show VARIABLES like ‘long_query_time’,單位秒
設定:set long_query_time=0.5
實操時應該從長時間設定到短的時間,即將最慢的SQL優化掉
檢視日誌,一旦SQL超過了我們設定的臨界時間就會被記錄到xxx-slow.log中
主鍵使用自增ID還是UUID?
推薦使用自增ID,不要使用UUID。
因為在InnoDB儲存引擎中,主鍵索引是作為聚簇索引存在的,也就是說,主鍵索引的B+樹葉子節點上儲存了主鍵索引以及全部的資料(按照順序),如果主鍵索引是自增ID,那麼只需要不斷向後排列即可,如果是UUID,由於到來的ID與原來的大小不確定,會造成非常多的資料插入,資料移動,然後導致產生很多的記憶體碎片,進而造成插入效能的下降。
總之,在資料量大一些的情況下,用自增主鍵效能會好一些。
關於主鍵是聚簇索引,如果沒有主鍵,InnoDB會選擇一個唯一鍵來作為聚簇索引,如果沒有唯一鍵,會生成一個隱式的主鍵。
8.分庫分表
垂直分割槽:
根據資料庫裡面資料表的相關性進行拆分。 例如,使用者表中既有使用者的登入資訊又有使用者的基本資訊,可以將使用者表拆分成兩個單獨的表,甚至放到單獨的庫做分庫。
簡單來說垂直拆分是指資料表列的拆分,把一張列比較多的表拆分為多張表。 如下圖所示,這樣來說大家應該就更容易理解了。
垂直拆分的優點: 可以使得行資料變小,在查詢時減少讀取的Block數,減少I/O次數。此外,垂直分割槽可以簡化表的結構,易於維護。
垂直拆分的缺點: 主鍵會出現冗餘,需要管理冗餘列,並會引起Join操作,可以通過在應用層進行Join來解決。此外,垂直分割槽會讓事務變得更加複雜;
垂直分表
把主鍵和一些列放在一個表,然後把主鍵和另外的列放在另一個表中
適用場景
1、如果一個表中某些列常用,另外一些列不常用
2、可以使資料行變小,一個數據頁能儲存更多資料,查詢時減少I/O次數
缺點
有些分表的策略基於應用層的邏輯演算法,一旦邏輯演算法改變,整個分表邏輯都會改變,擴充套件性較差
對於應用層來說,邏輯演算法增加開發成本
管理冗餘列,查詢所有資料需要join操作
水平分割槽:
保持資料表結構不變,通過某種策略儲存資料分片。這樣每一片資料分散到不同的表或者庫中,達到了分散式的目的。 水平拆分可以支撐非常大的資料量。
水平拆分是指資料錶行的拆分,表的行數超過200萬行時,就會變慢,這時可以把一張的表的資料拆成多張表來存放。舉個例子:我們可以將使用者資訊表拆分成多個使用者資訊表,這樣就可以避免單一表資料量過大對效能造成影響。
資料庫水平拆分
水平拆分可以支援非常大的資料量。需要注意的一點是:分表僅僅是解決了單一表資料過大的問題,但由於表的資料還是在同一臺機器上,其實對於提升MySQL併發能力沒有什麼意義,所以 水平拆分最好分庫 。
水平拆分能夠 支援非常大的資料量儲存,應用端改造也少,但 分片事務難以解決 ,跨界點Join效能較差,邏輯複雜。
《Java工程師修煉之道》的作者推薦 儘量不要對資料進行分片,因為拆分會帶來邏輯、部署、運維的各種複雜度 ,一般的資料表在優化得當的情況下支撐千萬以下的資料量是沒有太大問題的。如果實在要分片,儘量選擇客戶端分片架構,這樣可以減少一次和中介軟體的網路I/O。
水平分表:
表很大,分割後可以降低在查詢時需要讀的資料和索引的頁數,同時也降低了索引的層數,提高查詢次數
適用場景
1、表中的資料本身就有獨立性,例如表中分表記錄各個地區的資料或者不同時期的資料,特別是有些資料常用,有些不常用。
2、需要把資料存放在多個介質上。
水平切分的缺點
1、給應用增加複雜度,通常查詢時需要多個表名,查詢所有資料都需UNION操作
2、在許多資料庫應用中,這種複雜度會超過它帶來的優點,查詢時會增加讀一個索引層的磁碟次數
下面補充一下資料庫分片的兩種常見方案:
客戶端代理: 分片邏輯在應用端,封裝在jar包中,通過修改或者封裝JDBC層來實現。 噹噹網的 Sharding-JDBC 、阿里的TDDL是兩種比較常用的實現。
中介軟體代理: 在應用和資料中間加了一個代理層。分片邏輯統一維護在中介軟體服務中。 我們現在談的 Mycat 、360的Atlas、網易的DDB等等都是這種架構的實現。
分庫分表後面臨的問題
-
事務支援 分庫分表後,就成了分散式事務了。如果依賴資料庫本身的分散式事務管理功能去執行事務,將付出高昂的效能代價; 如果由應用程式去協助控制,形成程式邏輯上的事務,又會造成程式設計方面的負擔。
-
跨庫join
只要是進行切分,跨節點Join的問題是不可避免的。但是良好的設計和切分卻可以減少此類情況的發生。解決這一問題的普遍做法是分兩次查詢實現。在第一次查詢的結果集中找出關聯資料的id,根據這些id發起第二次請求得到關聯資料。 分庫分表方案產品
*跨節點的count,order by,group by以及聚合函式問題 這些是一類問題,因為它們都需要基於全部資料集合進行計算。多數的代理都不會自動處理合並工作。解決方案:與解決跨節點join問題的類似,分別在各個節點上得到結果後在應用程式端進行合併。和join不同的是每個結點的查詢可以並行執行,因此很多時候它的速度要比單一大表快很多。但如果結果集很大,對應用程式記憶體的消耗是一個問題。
*資料遷移,容量規劃,擴容等問題 來自淘寶綜合業務平臺團隊,它利用對2的倍數取餘具有向前相容的特性(如對4取餘得1的數對2取餘也是1)來分配資料,避免了行級別的資料遷移,但是依然需要進行表級別的遷移,同時對擴容規模和分表數量都有限制。總得來說,這些方案都不是十分的理想,多多少少都存在一些缺點,這也從一個側面反映出了Sharding擴容的難度。
- ID問題
一旦資料庫被切分到多個物理結點上,我們將不能再依賴資料庫自身的主鍵生成機制。一方面,某個分割槽資料庫自生成的ID無法保證在全域性上是唯一的;另一方面,應用程式在插入資料之前需要先獲得ID,以便進行SQL路由. 一些常見的主鍵生成策略
UUID 使用UUID作主鍵是最簡單的方案,但是缺點也是非常明顯的。由於UUID非常的長,除佔用大量儲存空間外,最主要的問題是在索引上,在建立索引和基於索引進行查詢時都存在效能問題。 Twitter的分散式自增ID演算法Snowflake 在分散式系統中,需要生成全域性UID的場合還是比較多的,twitter的snowflake解決了這種需求,實現也還是很簡單的,除去配置資訊,核心程式碼就是毫秒級時間41位 機器ID 10位 毫秒內序列12位。
9.主從複製
主從複製
SQL語言共分為四大類:資料查詢語言DQL,資料操縱語言DML,資料定義語言DDL,資料控制語言DCL。
將主資料庫中的DDL和DML操作通過二進位制日誌(BINLOG)傳輸到從資料庫上,然後將這些日誌重新執行(重做);從而使得從資料庫的資料與主資料庫保持一致。
主從複製的作用
主資料庫出現問題,可以切換到從資料庫。
可以進行資料庫層面的讀寫分離。
可以在從資料庫上進行日常備份。
MySQL主從複製解決的問題
資料分佈:隨意開始或停止複製,並在不同地理位置分佈資料備份
負載均衡:降低單個伺服器的壓力
高可用和故障切換:幫助應用程式避免單點失敗
升級測試:可以用更高版本的MySQL作為從庫
MySQL主從複製工作原理
在主庫上把資料更改記錄到二進位制日誌
從庫將主庫的日誌複製到自己的中繼日誌
從庫讀取中繼日誌的事件,將其重放到從庫資料中
基本原理流程,3個執行緒以及之間的關聯
主:binlog執行緒——記錄下所有改變了資料庫資料的語句,放進master上的binlog中;
從:io執行緒——在使用start slave 之後,負責從master上拉取 binlog 內容,放進自己的relay log中;
從:sql執行執行緒——執行relay log(資料庫中繼日誌)中的語句;
10.讀寫分離
讀寫分離是依賴於主從複製,而主從複製又是為讀寫分離服務的。因為主從複製要求slave不能寫只能讀(如果對slave執行寫操作,那麼show slave status將會呈現Slave_SQL_Running=NO,此時你需要按照前面提到的手動同步一下slave)
主伺服器處理寫操作以及實時性要求比較高的讀操作,而從伺服器處理讀操作。
讀寫分離能提高效能的原因在於:
- 主從伺服器負責各自的讀和寫,極大程度緩解了鎖的爭用;
- 從伺服器可以使用 MyISAM,提升查詢效能以及節約系統開銷;
- 增加冗餘,提高可用性。
讀寫分離常用代理方式來實現,代理伺服器接收應用層傳來的讀寫請求,然後決定轉發到哪個伺服器。