基礎入門: 與MySQL的零距離接觸-慕課網html
MySQL開發技巧: MySQL開發技巧(一) MySQL開發技巧(二) MySQL開發技巧(三)java
MySQL5.7新特性及相關優化技巧: MySQL5.7版本新特性 性能優化之MySQL優化mysql
MySQL 是一種關係型數據庫,在Java企業級開發中很是經常使用,由於 MySQL 是開源免費的,而且方便擴展。阿里巴巴數據庫系統也大量用到了 MySQL,所以它的穩定性是有保障的。MySQL是開放源代碼的,所以任何人均可以在 GPL(General Public License) 的許可下下載並根據個性化的須要對其進行修改。MySQL的默認端口號是3306。github
查看MySQL提供的全部存儲引擎面試
mysql> show engines;
從上圖咱們能夠查看出 MySQL 當前默認的存儲引擎是InnoDB,而且在5.7版本全部的存儲引擎中只有 InnoDB 是事務性存儲引擎,也就是說只有 InnoDB 支持事務。redis
查看MySQL當前默認的存儲引擎算法
咱們也能夠經過下面的命令查看默認的存儲引擎。sql
mysql> show variables like '%storage_engine%';
查看錶的存儲引擎數據庫
show table status like "table_name" ;
MyISAM是MySQL的默認數據庫引擎(5.5版以前)。雖然性能極佳,並且提供了大量的特性,包括全文索引、壓縮、空間函數等,但MyISAM不支持事務和行級鎖,並且最大的缺陷就是崩潰後沒法安全恢復。不過,5.5版本以後,MySQL引入了InnoDB(事務性數據庫引擎),MySQL 5.5版本後默認的存儲引擎爲InnoDB。
大多數時候咱們使用的都是 InnoDB 存儲引擎,可是在某些狀況下使用 MyISAM 也是合適的好比讀密集的狀況下。(若是你不介意 MyISAM 崩潰恢復問題的話)。
二者的對比:
READ COMMITTED
和 REPEATABLE READ
兩個隔離級別下工做;MVCC可使用 樂觀(optimistic)鎖 和 悲觀(pessimistic)鎖來實現;各數據庫中MVCC實現並不統一。推薦閱讀:MySQL-InnoDB-MVCC多版本併發控制《MySQL高性能》上面有一句話這樣寫到:
不要輕易相信「MyISAM比InnoDB快」之類的經驗之談,這個結論每每不是絕對的。在不少咱們已知場景中,InnoDB的速度均可以讓MyISAM可望不可即,尤爲是用到了聚簇索引,或者須要訪問的數據均可以放入內存的應用。
通常狀況下咱們選擇 InnoDB 都是沒有問題的,可是某些狀況下你並不在意可擴展能力和併發能力,也不須要事務支持,也不在意崩潰後的安全恢復問題的話,選擇MyISAM也是一個不錯的選擇。可是通常狀況下,咱們都是須要考慮到這些問題的。
字符集指的是一種從二進制編碼到某類字符符號的映射。校對規則則是指某種字符集下的排序規則。MySQL中每一種字符集都會對應一系列的校對規則。
MySQL採用的是相似繼承的方式指定字符集的默認值,每一個數據庫以及每張數據表都有本身的默認值,他們逐層繼承。好比:某個庫中全部表的默認字符集將是該數據庫所指定的字符集(這些表在沒有指定字符集的狀況下,纔會採用默認字符集) PS:整理自《Java工程師修煉之道》
詳細內容能夠參考: MySQL字符集及校對規則的理解
MySQL索引使用的數據結構主要有BTree索引 和 哈希索引 。對於哈希索引來講,底層的數據結構就是哈希表,所以在絕大多數需求爲單條記錄查詢的時候,能夠選擇哈希索引,查詢性能最快;其他大部分場景,建議選擇BTree索引。
MySQL的BTree索引使用的是B樹中的B+Tree,但對於主要的兩種存儲引擎的實現方式是不一樣的。
更多關於索引的內容能夠查看文檔首頁MySQL目錄下關於索引的詳細總結。
執行查詢語句的時候,會先查詢緩存。不過,MySQL 8.0 版本後移除,由於這個功能不太實用
my.cnf加入如下配置,重啓MySQL開啓查詢緩存
query_cache_type=1 query_cache_size=600000
MySQL執行如下命令也能夠開啓查詢緩存
set global query_cache_type=1; set global query_cache_size=600000;
如上,開啓查詢緩存後在一樣的查詢條件以及數據狀況下,會直接在緩存中返回結果。這裏的查詢條件包括查詢自己、當前要查詢的數據庫、客戶端協議版本號等一些可能影響結果的信息。所以任何兩個查詢在任何字符上的不一樣都會致使緩存不命中。此外,若是查詢中包含任何用戶自定義函數、存儲函數、用戶變量、臨時表、MySQL庫中的系統表,其查詢結果也不會被緩存。
緩存創建以後,MySQL的查詢緩存系統會跟蹤查詢中涉及的每張表,若是這些表(數據或結構)發生變化,那麼和這張表相關的全部緩存數據都將失效。
緩存雖然可以提高數據庫的查詢性能,可是緩存同時也帶來了額外的開銷,每次查詢後都要作一次緩存操做,失效後還要銷燬。 所以,開啓緩存查詢要謹慎,尤爲對於寫密集的應用來講更是如此。若是開啓,要注意合理控制緩存空間大小,通常來講其大小設置爲幾十MB比較合適。此外,還能夠經過sql_cache和sql_no_cache來控制某個查詢語句是否須要緩存:
select sql_no_cache count(*) from usr;
事務是邏輯上的一組操做,要麼都執行,要麼都不執行。
事務最經典也常常被拿出來講例子就是轉帳了。假如小明要給小紅轉帳1000元,這個轉帳會涉及到兩個關鍵操做就是:將小明的餘額減小1000元,將小紅的餘額增長1000元。萬一在這兩個操做之間忽然出現錯誤好比銀行系統崩潰,致使小明餘額減小而小紅的餘額沒有增長,這樣就不對了。事務就是保證這兩個關鍵操做要麼都成功,要麼都要失敗。
在典型的應用程序中,多個事務併發運行,常常會操做相同的數據來完成各自的任務(多個用戶對同一數據進行操做)。併發雖然是必須的,但可能會致使如下的問題。
不可重複讀和幻讀區別:
不可重複讀的重點是修改好比屢次讀取一條記錄發現其中某些列的值被修改,幻讀的重點在於新增或者刪除好比屢次讀取一條記錄發現記錄增多或減小了。
SQL 標準定義了四個隔離級別:
隔離級別 | 髒讀 | 不可重複讀 | 幻影讀 |
---|---|---|---|
READ-UNCOMMITTED | √ | √ | √ |
READ-COMMITTED | × | √ | √ |
REPEATABLE-READ | × | × | √ |
SERIALIZABLE | × | × | × |
MySQL InnoDB 存儲引擎的默認支持的隔離級別是 REPEATABLE-READ(可重讀)。咱們能夠經過SELECT @@tx_isolation;
命令來查看
mysql> SELECT @@tx_isolation; +-----------------+ | @@tx_isolation | +-----------------+ | REPEATABLE-READ | +-----------------+
這裏須要注意的是:與 SQL 標準不一樣的地方在於 InnoDB 存儲引擎在 REPEATABLE-READ(可重讀) 事務隔離級別下使用的是Next-Key Lock 鎖算法,所以能夠避免幻讀的產生,這與其餘數據庫系統(如 SQL Server) 是不一樣的。因此說InnoDB 存儲引擎的默認支持的隔離級別是 REPEATABLE-READ(可重讀) 已經能夠徹底保證事務的隔離性要求,即達到了 SQL標準的 SERIALIZABLE(可串行化) 隔離級別。由於隔離級別越低,事務請求的鎖越少,因此大部分數據庫系統的隔離級別都是 READ-COMMITTED(讀取提交內容) ,可是你要知道的是InnoDB 存儲引擎默認使用 REPEAaTABLE-READ(可重讀) 並不會有任何性能損失。
InnoDB 存儲引擎在 分佈式事務 的狀況下通常會用到 SERIALIZABLE(可串行化) 隔離級別。
MyISAM和InnoDB存儲引擎使用的鎖:
表級鎖和行級鎖對比:
詳細內容能夠參考: MySQL鎖機制簡單瞭解一下:http://www.javashuo.com/article/p-omwesioc-ba.html
InnoDB存儲引擎的鎖的算法有三種:
相關知識點:
當MySQL單表記錄數過大時,數據庫的CRUD性能會明顯降低,一些常見的優化措施以下:
務必禁止不帶任何限制數據範圍條件的查詢語句。好比:咱們當用戶在查詢訂單歷史的時候,咱們能夠控制在一個月的範圍內;
經典的數據庫拆分方案,主庫負責寫,從庫負責讀;
根據數據庫裏面數據表的相關性進行拆分。 例如,用戶表中既有用戶的登陸信息又有用戶的基本信息,能夠將用戶表拆分紅兩個單獨的表,甚至放到單獨的庫作分庫。
簡單來講垂直拆分是指數據表列的拆分,把一張列比較多的表拆分爲多張表。 以下圖所示,這樣來講你們應該就更容易理解了。
保持數據表結構不變,經過某種策略存儲數據分片。這樣每一片數據分散到不一樣的表或者庫中,達到了分佈式的目的。 水平拆分能夠支撐很是大的數據量。
水平拆分是指數據錶行的拆分,表的行數超過200萬行時,就會變慢,這時能夠把一張的表的數據拆成多張表來存放。舉個例子:咱們能夠將用戶信息表拆分紅多個用戶信息表,這樣就能夠避免單一表數據量過大對性能形成影響。
水平拆分能夠支持很是大的數據量。須要注意的一點是:分表僅僅是解決了單一表數據過大的問題,但因爲表的數據仍是在同一臺機器上,其實對於提高MySQL併發能力沒有什麼意義,因此 水平拆分最好分庫 。
水平拆分可以 支持很是大的數據量存儲,應用端改造也少,但 分片事務難以解決 ,跨節點Join性能較差,邏輯複雜。《Java工程師修煉之道》的做者推薦 儘可能不要對數據進行分片,由於拆分會帶來邏輯、部署、運維的各類複雜度 ,通常的數據表在優化得當的狀況下支撐千萬如下的數據量是沒有太大問題的。若是實在要分片,儘可能選擇客戶端分片架構,這樣能夠減小一次和中間件的網絡I/O。
下面補充一下數據庫分片的兩種常見方案:
詳細內容能夠參考: MySQL大表優化方案: http://www.javashuo.com/article/p-cclvigrf-k.html
池話設計應該不是一個新名詞。咱們常見的如java線程池、jdbc鏈接池、redis鏈接池等就是這類設計的表明實現。這種設計會初始預設資源,解決的問題就是抵消每次獲取資源的消耗,如建立線程的開銷,獲取遠程鏈接的開銷等。就比如你去食堂打飯,打飯的大媽會先把飯盛好幾份放那裏,你來了就直接拿着飯盒加菜便可,不用再臨時又盛飯又打菜,效率就高了。除了初始化資源,池化設計還包括以下這些特徵:池子的初始值、池子的活躍值、池子的最大值等,這些特徵能夠直接映射到java線程池和數據庫鏈接池的成員屬性中。——這篇文章對池化設計思想介紹的還不錯,直接複製過來,避免重複造輪子了。
數據庫鏈接本質就是一個 socket 的鏈接。數據庫服務端還要維護一些緩存和用戶權限信息之類的 因此佔用了一些內存。咱們能夠把數據庫鏈接池是看作是維護的數據庫鏈接的緩存,以便未來須要對數據庫的請求時能夠重用這些鏈接。爲每一個用戶打開和維護數據庫鏈接,尤爲是對動態數據庫驅動的網站應用程序的請求,既昂貴又浪費資源。**在鏈接池中,建立鏈接後,將其放置在池中,並再次使用它,所以沒必要創建新的鏈接。若是使用了全部鏈接,則會創建一個新鏈接並將其添加到池中。**鏈接池還減小了用戶必須等待創建與數據庫的鏈接的時間。
由於要是分紅多個表以後,每一個表都是從 1 開始累加,這樣是不對的,咱們須要一個全局惟一的 id 來支持。
生成全局 id 有下面這幾種方式: