Mysql客戶端和服務器之間的通訊協議是「半雙工」的,意味着在任何一個時刻,要麼是由服務器向客戶端發送數據,要麼是有客戶端向服務器發送數據,這兩個動做不能同時發生。當咱們發送一條SQL命令引擎時,MySql執行過程以下圖所示mysql
查詢緩存
在解析一個查詢語句以前,若是查詢緩存是打開的,那麼MySQL會優先檢查這個查詢是否命中查詢緩存中的數據,若是命中緩存直接從緩存中拿到結果並返回給客戶端。這種狀況下,查詢不會被解析,不用生成執行計劃,不會被執行。sql
語法解析和預處理器
MySQL經過關鍵字將SQL語句進行解析,並生成一棵對應的「解析樹」。MySQL解析器將使用MySQL語法規則驗證和解析查詢。數據庫
查詢優化器
語法書被校驗合法後由優化器轉成查詢計劃,一條語句能夠有不少種執行方式,最後返回相同的結果。優化器的做用就是找到這其中最好的執行計劃。緩存
查詢執行引擎
在解析和優化階段,MySQL將生成查詢對應的執行計劃,MySQL的查詢執行引擎則根據這個執行計劃來完成整個查詢。最常使用的也是比較最多的引擎是MyISAM引擎和InnoDB引擎。mysql5.5開始的默認存儲引擎已經變動爲innodb了。性能優化
下面簡單的羅列幾點差異:MyISAM類型不支持事務處理等高級處理,強調的是性能,InnoDB支持事物;MyISAM支持表級鎖,InnoDB支持行級鎖;MyISAM不支持外鍵,InnoDB支持外鍵(雖然不建議使用外鍵約束)。
查詢當前默認的引擎能夠經過SHOW VARIABLES LIKE '%storage_engine%'語句來查看。服務器
InnoDB是支持事務的,那麼到底什麼是事務呢?
數據庫事務(Database Transaction) ,是指做爲單個邏輯工做單元執行的一系列操做,要麼徹底地執行,要麼徹底地不執行。併發
事物的基本特性(ACID)
原子性(atomicity):
事務中的操做要麼都發生,要麼都不發生。
一致性 (consistent):
在事務開始和完成時,數據必須保持一致狀態(讀一致、寫一致)。
隔離性 (isolation):
隔離性指併發的事務是相互隔離的。一個事物操做不能對另外一個事物產生影響。
持久性(durable):
事務完成以後,它對於數據的修改是永久性的,即便出現系統故障也可以保持。性能
事務的隔離級別
若是不考慮事物的隔離級別會出現如下三種異常狀況測試
幻讀和提交讀都是讀取了另外一條已經提交的事物(這一天與不提交讀有區別),所不一樣的是不可重複讀查詢的都是同一個數據項,而幻讀針對的是一批數據總體。優化
Mysql數據庫爲咱們定義了四種隔離級別
Repeatable read是mysql默認的隔離級別
InnoDB的鎖分類及加鎖方法
1、鎖分類
InnoDB的鎖定模式能夠分爲四類
按照鎖定級別劃分爲
1.表鎖
開銷小,加鎖快;不會出現死鎖;鎖定粒度大,發生鎖衝突的機率最高,併發度最低;適合於以查詢爲主,只有少許按索引條件更新數據的應用。
例如MyISAM引擎在執行查詢語句的時候會自動給涉及的全部表加讀鎖,在執行更新操做(UPDATE、DELETE、INSERT)前,自動給涉及的表加寫鎖。
2.行鎖
開銷大,加鎖慢;會出現死鎖;鎖定粒度最小,發生鎖衝突的機率最低,併發度也最高;適合有大量按索引條件併發更新狀況。
InnoDB的行級鎖定一樣分爲兩種類型,共享鎖和排他鎖,而在鎖定機制的實現過程當中爲了讓行級鎖定和表級鎖定共存,InnoDB也一樣使用了意向鎖(表級鎖定)的概念,也就有了意向共享鎖和意向排他鎖這兩種。
當一個事務須要給本身須要的某個資源加鎖的時候,若是遇到一個共享鎖正鎖定着本身須要的資源的時候,本身能夠再加一個共享鎖,不過不能加排他鎖。可是,若是遇到本身須要鎖定的資源已經被一個排他鎖佔有以後,則只能等待該鎖定釋放資源以後本身才能獲取鎖定資源並添加本身的鎖定。
3.頁鎖
開銷和加鎖時間界於表鎖和行鎖之間,咱們不多場景下會使用。
鎖定級別的選擇是由存儲引擎來自行選擇的。
4.間隙鎖
當咱們用範圍條件而不是相等條件檢索數據,並請求共享或排他鎖時,InnoDB會給符合條件的已有數據記錄的索引項加鎖;對於鍵值在條件範圍內但並不存在的記錄,叫作「間隙(GAP)」,InnoDB也會對這個「間隙」加鎖,這種鎖機制就是所謂的間隙鎖(Next-Key鎖)。
例如:select * from emp where empid > 100 for update;
是一個範圍條件的檢索,InnoDB不只會對符合條件的empid值爲101的記錄加鎖,也會對empid大於101(這些記錄並不存在)的「間隙」加鎖。
二. 加鎖方法
意向鎖是InnoDB引擎自動加的,不須要用戶干預。對於UPDATE、DELETE和INSERT語句,InnoDB會自動給涉及數據集加排他鎖(X);對於UPDATE、DELETE和INSERT語句,InnoDB會自動給涉及數據集加排他鎖(X);對於普通SELECT語句,InnoDB不會加任何鎖;事務能夠經過如下語句顯示給記錄集加共享鎖或排他鎖。
共享鎖:SELECT … LOCK IN SHARE MODE
排他鎖:SELECT … FOR UPDATE
InnoDB行鎖是經過給索引上的索引項加鎖來實現的,只有經過索引條件檢索數據,InnoDB才使用行級鎖,不然,InnoDB將使用表鎖。如下幾種狀況須要避免:
三.死鎖
Mysql MyISAM老是一次得到所需的所有鎖,要麼所有知足,要麼等待,所以不會出現死鎖。但在InnoDB中,除單個SQL組成的事務外,鎖是逐步得到的,當兩個事務都須要得到對方持有的排他鎖才能繼續完成事務,這種循環鎖等待就是典型的死鎖。
一般來講,死鎖都是應用設計的問題,經過調整業務流程、數據庫對象設計、事務大小,以及訪問數據庫的SQL語句,絕大部分死鎖均可以免。
須要注意:
數據類型優化
更短的列一般更好,例如varchar(5)和varhchar(200)存儲hello的空間開銷是同樣的,事實證實更長的列會消耗更多的內存,由於MySQL一般會分配固定大小的內存塊來保存內部值。
使用緩存表和彙總表
以網站爲例,假設須要計算以前24小時內發送的消息數,在一個繁忙的網站不可能維護一個實時精確的計算器,能夠每一小時統計一次,而後把24個小時訪問數疊加。
建立高性能的索引
1.使用獨立的列
若是不是獨立的列,則MySQL就不會使用索引
例如:
Select actor_id from actor where actor_id + 1 = 5;沒法使用actor_id列的索引
2.聯合索引
不少人對多列索引的理解不夠,常見的錯誤是爲每一個列建立獨立的索引,或者按錯誤的順序建立多列索引。當出現服務器對多個索引作相交操做時(一般是多個AND條件),一般意味着須要一個包含全部相關列的多列索引,而不是多個單獨的單列索引。
當服務器須要多個索引作聯合操做時(一般有多個OR條件),一般須要耗費大量的CPU和內存資源。一般有兩種作法:
①使用union all
Select film_id,actor_id from film_actor where actor_id
Union all
Select film_id,actor_id from film_actor where film_id =1 and actor_id <>1;
②分別對film_id 和 actor_id建立索引。
3.選擇合適的索引列順序
Select * from payment where staff_id = 2 AND customer_id = 584
應該建立一個(staff_id,customer_id)索引仍是應該顛倒一下順序?哪一個字段選擇性更高,選擇哪一個字段做爲索引列的第一列。customer_id對應篩選掉的數據更多,則索引customer_id應該放在第一位。
4.冗餘和重複索引
索引並非越多越好,過多的索引會對系統產生負擔,一直未使用的索引應該把它刪掉,而不是留在咱們的系統中。
例若有一張參保人表裏面有100000行數據,每一個state_id值大概有20000條記錄。在state_id列有一個索引對下面查詢有用,查詢名爲Q1:
Select count(*) from table where state_id = 5;
一個簡單的測試查詢的執行速度每秒115次(QPS)。還有一個查詢
Select state_id,city,address from userinfo where state_id = 5;
對於這個查詢,測試結果QPS小於10。提高性能最簡單的辦法就是擴展索引爲(state_id,city,address),索引擴展後Q2變快了,可是Q1變慢了,若是咱們想讓兩個查詢都變得更快,就須要兩個索引。多個索引的缺點是索引的成本更高。向表中插入100萬數據,InnoDB引擎在一個索引狀況下須要80秒,兩個索引的狀況下須要136秒。能夠看出表中的索引越多插入速度越慢。
索引和鎖
咱們在寫查詢語句的時候,要利用索引鎖住最小範圍內的行。
例如:
Select actor_id from sakila.actor where actor_id < 5
And actor_id <> 1 for update
這條語句僅僅返回 2-4,但實際上獲取了1-4之間的行的排他鎖,InnoDB 會鎖住第1行,這是由於MySQL爲該查詢選擇的執行計劃是索引範圍掃描。
就像這個例子顯示的,即便使用了索引,InnoDB也可能鎖住一些不須要的數據,若是不使用索引查找和鎖定行的話問題可能會更糟,mysql會作全表掃描並鎖住全部的行,而無論是否是須要。避免使用多個範圍條件:
例如:select actor_id from actor where actor_id > 45
若是能改爲select actor_id from actor where actor_id in (46,99)
這兩種範圍條件查詢,MySQL沒法再使用範圍列後面的索引了,可是對於「多個等值條件查詢」則沒有這個限制。若是多個範圍查詢則索引就無能爲力了。
查詢性能優化
執行計劃
執行計劃能夠查看數據軟件是如何掃描表,如何使用索引的,所以明白MySql語句的執行計劃,對咱們優化mysql的性能很是有用。
查看執行計劃可使用以下語句:
EXPLAIN SELECT * FROM inventory WHERE item_id = 16102176G; 這樣的命令時,會給咱們反饋以下信息:
Key: 列指出優化器選擇使用的索引
Rows:用於分析結果集中的行數估計值,最好估值是1,通常來講這種狀況發生在當尋找的行在表中能夠經過主鍵或者惟一鍵找到的時候。
Possible_keys:指出優化器爲查詢選定的索引
Key_len: 列定義了用於SQL語句的鏈接條件的鍵的長度。
Table:這個值多是個是代表、表的別名或者一個爲查詢產生臨時表的標識符
Select_type:
提供了表示table列引用的使用方式的類型。最多見的值包括simple、primary,derived和union
extra
extra列提供了有關不一樣種類的MySQL 優化器路徑的一系列
額外信息,下面給 出經常使用值的列表