MySQL高級部分理論知識細講

文章目錄

1、數據庫分區、分表、分庫、分片

YesOk ,你們好 ,我是小劉,許久不見,甚是想念 ,小劉今天來帶你們學習 分庫分表的基礎知識mysql

生成結果

1.1 單機數據庫的瓶頸

生成結果

  • 單個表數據量越大,讀寫鎖,插入操做從新創建索引效率越低。
  • 單個庫數據量太大(一個庫數據量到1T - 2T就是極限)
  • 單個數據庫服務器壓力過大
  • 讀寫速度遇到瓶頸(併發量幾百)

1.2 分區

數據庫分區是一種物理數據庫的設計技術,它的目的是爲了在特定的 SQL操做中減小數據讀寫的總量以縮減響應時間。面試

分區並非生成新的數據庫表,而是將表的數據均勻分攤到不一樣的硬盤,系統或不一樣服務器存儲介子中,實際上仍是一張表。另外,分區能夠作到將表的數據分攤到不一樣的地方,提升數據檢索的效率,下降數據庫頻繁 IO壓力值,分區的優勢以下:算法

  1. 相對於單個文件系統或硬盤,分區能夠存儲更多的數據。
  2. 數據管理比較方便,如要清理或廢棄某年的數據,就能夠直接刪除該日期的分區數據便可。
  3. 精準定位分區查詢數據,不須要全表掃描查詢,大大提升檢索效率。
  4. 可跨多個分區磁盤查詢,來提升查詢的吞吐量。
  5. 在涉及聚合函數時,很容易進行數據的合併。

1.2.1 何時考慮使用分區?

  • 一張表的查詢速度已經慢到影響使用的時候。
  • sql通過優化
  • 數據量大
  • 表中的數據是分段的
  • 對數據的操做每每只涉及一部分數據,而不是全部的數據

1.2.2 水平分區

這種形式分區是對錶的行進行分區,經過這種的方式不一樣分組裏面的物理列分割的數據集得以組合,從而進行個體分體或集體分割。全部在表中定義的列在每一個數據集中都能找到,因此表的特性得以保持。sql

舉例:一個包含十年發票記錄的表能夠被分區爲10個不一樣的分區,每一個分區包含的是其中一年的記錄。mongodb

1.2.3 垂直分區

這種分區方式通常來講是經過對錶的垂直劃分來減小目標表的寬度,使某些特定的列被劃分到特定的分區,每一個分區都包含了其中的列所對應的行。數據庫

舉例:一個包含了大 textblob列的表,這些 textblod列又不常常被訪問,這時候就要把這些不常用的 textblob了劃分到另外一個分區,在保證它們數據關聯性的同時還能提升訪問速度。服務器

1.2.4 分區實現的方式

mysql5開始支持分區功能微信

建立表session

create table sales(
	id int auto increment,
	amount double not null,
	order_day datetime not null,
	primary key(id,order_day)
) engine=Innodb

設置分區併發

partition by range(year(order_day))(
	partition p_2010 values less than (2000),
	partition p_2011 values less than (2011),
	partition p_2012 values less than (2012),
	partition p_2012 values less than maxvalue
);

1.3 分表

1.3.1 何時考慮分表?

生成結果

  • 一張表的查詢速度已經慢到影響使用的時候
  • sql通過優化
  • 數據量大
  • 當頻繁插入或者聯合查詢時,速度變慢

1.3.2 分表解決的問題

分表後,單表的併發能力提升了,磁盤的 IO性能也提供了,寫操做效率也提升了。

  • 查詢一次的時間短了
  • 數據分佈在不一樣的文件,磁盤 I/O性能提升
  • 讀寫鎖影響的數據量變小
  • 插入數據庫須要從新創建索引的數據減小

1.3.3 分表實現方式

要業務系統配合遷移升級,工做量較大

經常使用分區分表的規則策略

  • Range(範圍)
  • Hash(哈希)
  • 按照時間拆分
  • Hash以後按照分表個數取模
  • 在認證庫中保存數據庫配置,就是創建一個 DB,這個 DB單獨保存 user_idDB的映射關係

1.4 分庫

1.4.1 何時考慮分庫?

  • 單臺 DB的存儲空間不夠
  • 隨着查詢量的增長單臺數據庫服務器已經沒辦法支撐

1.4.2 分庫解決的問題

其主要目的是爲突破單節點數據庫服務器的 I/O 能力限制,解決數據庫擴展性問題。

1.4.3 分庫實現的方式

垂直拆分

把系統中不存在關聯關係或者須要 join的表能夠放在不一樣的數據庫不一樣的服務器中。 按照業務垂直拆分。好比:能夠按照業務分爲資金、會員、訂單三個數據庫。

須要解決的問題:跨數據庫的事務、 join查詢等問題。

水平拆分

例如,大部分的站點。數據都是和用戶有關,那麼能夠根據用戶,將數據按照用戶水平拆分。

按照規則拆分,通常水平庫是在垂直分庫以後的。好比天天處理的訂單數量是海量的,能夠按照必定的規則水平劃分。

須要解決的問題:數據路由、組裝。

讀寫分離

對於時效性不高的數據,能夠經過讀寫分離緩解數據庫壓力。

須要解決的問題:在業務上區分哪些業務是容許必定時間延遲的,以及數據同步問題。

1.5 分區、分表、分庫的對比

分區就是把一張表的數據分紅N個區塊,在邏輯上看最終只是一個表,但底層是由N個物理區塊組成的。分表就是把一張表按必定的規則分解成N個具備獨立存儲空間的實體表。系統讀寫時須要根據定義好的規則獲得對應的字表名,而後操做它。分庫一旦分表,一個數據庫中的表會愈來愈多

優先級:垂直分庫–>水平分庫–>讀寫分離

1.6 拆分後面臨的新問題

  • 事務的支持,分庫分表,就變成了分佈式事務
  • join時跨庫,跨表的問題
  • 分庫分表,讀寫分離使用了分佈式,分佈式爲了保證強一致性,必然帶來延遲,致使性能下降,系統的負責度下降。

解決方案:

對於不一樣的方式之間沒有嚴格的界限,特色不一樣,側重點不一樣。須要根據實際狀況,結合每種方式的特色來進行處理。選用第三方的數據庫中間件( AtlasMycatTDDLDRDS),同時業務系統須要配合數據存儲的升級。

總結:優先考慮分區。當分區不能知足需求時,開始考慮分表,合理的分表對效率的提高會優於分區。

1.7 京東評論案例

現狀

  • 商品的評論數量:數十億條
  • 天天的服務調用:數十億次
  • 每一年成倍增加

總體的數據存儲:基礎數據存儲,文本存儲

基礎數據存儲

MySQL:只存儲非文本的基礎信息。包括:評論狀態,用戶,時間等基礎數據。以及圖片,標籤,點贊等附加信息。數據組織形式(不一樣的數據又可選擇不一樣的庫表拆分方案):

  • 評論基礎數據按用戶 ID進行拆庫並拆表
  • 圖片及標籤處於同一數據庫下,根據商品編號分別進行拆表
  • 其它的擴展信息數據,因數據量不大、訪問量不高,處理於同一庫下且不作分表便可

文本存儲

文本存儲(評論的內容)使用了 mongodbhbase

  • 選擇 nosql而非 mysql。
  • 減輕了 mysql存儲壓力,釋放 msyql,龐大的存儲也有了可靠的保障。
  • nosql的高性能讀寫大大提高了系統的吞吐量並下降了延遲。

1.8 數據分片

在分佈式存儲系統中,數據須要分散在多臺設備上,數據分片( Sharding)就是用來肯定數據在多臺存儲設備上分佈的技術,數據分片要達到三個目的:

  1. 分佈均勻,即每臺設備上的數據量要儘量相近
  2. 負載均衡,即每臺設備上的請求量要儘量相近
  3. 擴縮容時產生的數據遷移儘量少

數據分片方法

  • 劃分號段
  • 取模
  • 檢索表
  • 一致性哈希算法( Consistent Hashing)是在1997年由 MIT提出的一種分佈式哈希 (DHT)實現算法,設計目標是爲了解決因特網的熱點(Hot Spot)問題。一致性哈希的算法簡單而巧妙,很容易作到數據均分佈,其單調性也保證了擴縮容的數據遷移是比較少的。

虛擬服務器

爲了讓系統有更好的擴展性,這裏提出存儲層 VServer(虛擬服務器)的概念,一個 VServer是一個邏輯上的存儲服務器,是分佈式存儲系統的一個存儲單元,一臺物理設備上能夠部署多個 VServer,一個 VServer支持一個寫進程和多個讀進程。

經過 VServer的方式,會有下面一些好處:

  1. 提升單機性能。爲了避免引入複雜的鎖機制,採用了單寫進程的設計,若是單機只有一個寫進程,寫併發能力會受到限制,經過 VServer方式把單機上的存儲資源(內存、硬盤)劃分爲多個存儲單元,這樣就支持多個寫進程同時工做,大大提高單機寫併發能力。
  2. 部署擴展性更好。 VServer的方式在部署上很是靈活,能夠根據單機的資源狀況來肯定 VServer的數量,針對不一樣的機型配置不一樣的 VServer數量,這樣不一樣的機型都能充分利用機器上的資源,即便在一個系統中使用多種機型,也能作到機器的負載比較均衡。

2、事務的ACID和隔離級別

  • 原子性(Atomic):事務中各項操做,要麼全作要麼全不作,任何一項操做失敗都會致使整個事務的失敗
  • 一致性(Consistent):事務結束後系統的狀態是一致的
  • 隔離性(Isolated):併發操做的事務彼此看不到對方的中間狀態
  • 持久性(Durable):事務完成後所作的改動都會被持久化

數據庫事務併發致使的問題

  • 髒讀: 事務 A讀到了事務 B未提交的數據
  • 可重複讀:事務 A查詢獲得一行記錄 row1,事務B提交修改後,事務 A第二次查詢獲得 row1,但列內容發生了改變,側重於次數
  • 幻讀:事務 A第一次查詢獲得一行記錄 row1,事務 B提交修改後,事務 A第二次查詢獲得兩行記錄 row1row2,側重於 insert

MySQL數據庫給咱們提供的4中隔離級別

  • 串行化(Serializable):事務A屢次從一張表中讀取到相同的行,禁止其餘事務對這張表進行CRUD操做
  • 不可重複讀(Repeatable read):事務A能夠讀取到相同的值,禁止其餘事務對字段進行更改
  • 讀已提交(Read committed):事務A只能讀取已提交的數據
  • 讀未提交:(Read uncomitted): 事務A能夠讀取到未提交的數據

髒讀可重複讀幻讀串行化√√√不可重複讀√√×讀已提交√××讀未提交×××

Oracle提供3種隔離級別

讀已提交,串行化,只讀模式:只讀事務只能看到事務執行前就已經提交的數據,且事務中不能執行 insertupdatedelete語句。

3、MySQL鎖機制

3.1 鎖的分類

  • 從對數據操做的類型(讀/寫)分
    • 讀鎖(共享鎖):針對同一份數據,多個讀操做能夠同時進行而不會互相影響。
    • 寫鎖(排它鎖):當前寫操做沒有完成前,它會阻斷其餘寫鎖和讀鎖。
  • *對數據操做的粒度分

爲了儘量數據庫的併發度,每次鎖定的數據範圍越小越好,理論上每次只鎖定當前操做的數據的方案會獲得最大的併發度,可是管理鎖是很耗資源的事情(涉及獲取,檢查,釋放鎖等操做),所以數據庫系統須要在高併發響應和系統性能兩方面進行平衡,這樣就產生了"鎖粒度( Lock granularity)"的機率。

一種提升共享資源併發性的方式是讓鎖定對象更有選擇性。儘可能只鎖定須要修改的部分數據,而不是全部的資源。更理想的方式是,只對會修改的數據片進行精確的鎖定。任什麼時候候,在給定的資源上,鎖定的數據量越少,則系統的併發度越高,只要相互之間不發生衝突便可。

  • 表鎖
  • *行鎖

3.2 表鎖

特色:偏向 MyISAM存儲引擎,開銷小,加鎖快;無死鎖;鎖定粒度大,發生鎖衝突的機率最高,併發度最低。

案例1【加讀鎖】:

[session1]

lock table user read;

	這裏只能執行查詢當前表,不能查詢其餘表,插入或更新當前表都會提示錯誤

unlock tables;

[session2]

在session1鎖定表後,session2能查詢或更新未鎖定的表,能查詢鎖定表,插入或者更新鎖定表會一直等待鎖被釋放。

案例1【加寫鎖】:

[session1]

lock tables user write;

	這裏能夠對鎖定表作查詢、更新、插入操做

unlock tables;

[session2]

在session1鎖定表後,查詢、更新、插入操做均須要等到鎖被釋放。

結論:

  1. MyISAM表的讀操做(加讀鎖),不會阻塞其餘進程對同一表的讀請求,但會堵塞同一表的寫請求。只要當讀鎖釋放後,纔會執行其餘進程的寫操做。
  2. MyISAM表的寫操做(加寫鎖),會阻塞其餘進程的對同一表的讀和寫操做,只有當寫鎖釋放後,纔會執行其它進程的讀寫操做。

查看哪些表被加鎖show open tables;

分析表鎖定: show status like 'table%';


Table_locks_immediate:產生表級鎖定的次數,表示能夠當即獲取鎖的查詢次數,每當即獲取鎖值加1 ;
Table_locks_waited:出現表級鎖定爭用而發生等待的次數(不能當即獲取鎖的次數,每等待一次鎖值加1),此值高則說明存在着較嚴重的表級鎖爭用狀況;

Myisam的讀寫鎖調度是讀優先,這也是myisam不適合作寫爲主表的引擎。由於寫鎖後,其餘線程不能作任何操做,大量的更新會使查詢很可貴到鎖,從而形成永遠阻塞

3.3 行鎖

特色:

  1. 偏向 InnoDB存儲引擎,開銷大,加鎖慢;鎖定粒度最小,發生鎖衝突的機率最低,併發度也最高。
  2. InnoDBMyISAM的最大不一樣有兩點:一是支持事務;二是採用了行級鎖。

案例【加行鎖】

[session1]

set autocommit=0;

	這裏能夠對鎖定表作更新操做

commit;

[session2]

在session2鎖定表後不commit時,這裏對鎖定表進行update操做,會等待鎖釋放。

無索引行鎖升級爲表鎖

當某個索引列沒有正常使用,如賦錯誤的類型的值,會致使行鎖變表鎖。

間隙鎖危害

間隙鎖:當咱們用範圍條件而不是相等條件檢索數據,並請求共享或拍他鎖時, InnoDB會給符合條件的已有數據記錄的索引項加鎖;對於鍵值在條件範圍內但不存在的記錄,叫作"間隙( GAP)", InnoDB也會對這個"間隙"進行加鎖,這種鎖機制就是所謂的間隙鎖( Next-Key)。

危害:當鎖定一個範圍鍵值以後,即便某些不存在的鍵值也會被無辜的鎖定,而形成在鎖定的時候沒法插入鎖定鍵值範圍內的任何數據,在某些場景下這可能會對性能形成很大的危害。

【面試題】 如何鎖定一行

select * from user for update;

結論:

Innodb存儲引擎因爲實現了行級鎖定,雖然在鎖定機制的實現方面所帶來的的性能損耗可能比表級鎖定會要更高一些,可是總體併發處理能力方面要遠遠優於 MyISAM的表級鎖定。當系統併發量較高的時候, InnoDB的總體性能和 MyISAM相比就有比較明顯的優點了。

可是 Innodb的行級鎖定一樣也有脆弱的一面,當咱們使用不當的時候,可能會讓 Innodb的總體性能表現不只不能比 MyISAM高,甚至可能會更差。

分析行鎖定:

經過檢查 InnoDB_row_lock狀態變量來分析系統上的行鎖的爭奪狀況

命令: mysql> show status like 'innodb_row_lock%';

Innodb_row_lock_current_waits:當前正在等待鎖定的數量;
Innodb_row_lock_time:從系統啓動到如今鎖定總時間長度;
Innodb_row_lock_time_avg:每次等待所花平均時間;
Innodb_row_lock_time_max:從系統啓動到如今等待最常的一次所花的時間;
Innodb_row_lock_waits:系統啓動後到如今總共等待的次數;

優化建議

  • 儘量讓全部數據檢索都經過索引來完成,避免無索引行鎖升級爲表鎖。
  • 合理設計索引,儘可能縮小鎖的範圍
  • 儘量較少檢索條件,避免間隙鎖
  • 儘可能控制事務大小,減小鎖定資源量和時間長度
  • 儘量低級別事務隔離

3.4 頁鎖

開銷和加鎖時間界於表鎖和行鎖之間;會出現死鎖;鎖定粒度界於表鎖和行鎖之間,併發度通常。

4、MySQL實戰問題

4.1 重複數據問題

select p1.Email from person p1 where p1.Email in (select p2.Email from person p2 where p1.Id!=p2.Id);

[優]SELECT email FROM `person` group by email HAVING count(email)>1;

[拓展]刪除重複數據
[思路]根據重複數據進行分組,而後查出最小的id,刪除其餘以外的id行,這裏得建立一個臨時表,
在mysql中,不能在一條Sql語句中,即查詢這些數據,同時修改這些數據
DELETE from person  where id not in( select temp.id from (SELECT min(id) id FROM person group by email)as temp);
注意:這裏在mysql5.7以上版本會報錯,由於不支持select那些group by和聚合函數以外的字段

4.2 索引建立和查看

建立: create index idx_a_b on table(col_a,col_b);

查看: show index from table;

4.3 where 1=1和where 1=0的意義

where 1=1用於拼接多條件語句時,這樣就不用管條件是否存在,拼 where仍是拼 and

where1=0不返回數據,僅返回結構,用於快熟建表。

微信搜一搜 : 全棧小劉 ,獲取文章 pdf 版本

相關文章
相關標籤/搜索