mysql數據庫是當前應用最爲的普遍的數據庫,在實際工做中也常常接觸到。真正用好mysql也不只僅是會寫sql就行,更重要的是真正理解其內部的工做原理。本文先從宏觀角度介紹一些mysql相關的知識點,目的是爲了讓你們對mysql能有一個大致上的認知,後續再逐一對每一個知識點的進行深刻解讀。mysql
本文主要內容是根據掘金小冊《從根兒上理解 MySQL》整理而來。如想詳細瞭解,建議購買掘金小冊閱讀。sql
mysql採用了典型的客戶端/服務器架構(C/S架構)模式。對於計算機而言,數據庫客戶端程序和服務器程序分別運在不一樣的進程中。因此客戶端進程向服務器進程發送sql請求並獲得返回結果的過程本質上就是進程間通訊。mysql支持的進程間通訊方式包括TCP/IP
、命名管道
、共享內存
、unix域套接字文件
。shell
TCP/IP
: 若是服務端進程和客戶端進程運行在不一樣的主機中,只能經過TCP/IP
網絡通訊協議進行通訊。mysql服務器啓動時監聽某個端口(默認3306),等待客戶端進程來鏈接。固然,服務端進程和客戶端進程在同一主機中,經過本機迴環地址(127.0.0.1)也是可使用TCP/IP
進行通訊的。命名管道或共享內存
: 若是服務端進程和客戶端進程都運行在一臺windows主機上,能夠經過命名管道或共享內存方式進行通訊。
命名管道
來進行進程間通訊: 須要在啓動服務器程序的命令中加上--enable-named-pipe
參數,而後在啓動客戶端程序的命令中加入--pipe
或者--protocol=pipe
參數。共享內存
來進行進程間通訊: 須要在啓動服務器程序的命令中加上--shared-memory
參數,在成功啓動服務器後,共享內存便成爲本地客戶端程序的默認鏈接方式,不過咱們也能夠在啓動客戶端程序的命令中加入--protocol=memory
參數來顯式的指定使用共享內存進行通訊。Unix域套接字文件
: 若是咱們的服務器進程和客戶端進程都運行在同一臺操做系統爲類Unix的機器上的話,咱們可使用Unix域套接字文件來進行進程間通訊。真實環境中,服務器和客戶端基本都是運行在不一樣主機中的,它們之間採用的通訊方式就是TCP/IP
。數據庫
不論客戶端進程和服務器進程是採用哪一種方式進行通訊,最後實現的效果都是:客戶端向服務器發送一段文本(sql語句),服務器進程處理後再向客戶端進程發送一段文本(處理結果)。下面以查詢sql爲例,簡單說明一下服務器處理客戶端請求的大體處理過程。windows
從圖中咱們能夠看出,服務器程序處理來自客戶端的查詢請求大體須要通過三個部分,分別是鏈接管理
、解析與優化
、存儲引擎
。緩存
每當有一個客戶端鏈接到服務器時,服務器都會建立一個線程來專門處理與這個客戶端的交互。在客戶端程序發起鏈接的時候,須要攜帶主機信息、用戶名、密碼,服務器程序會對客戶端程序提供的這些信息進行認證,若是認證失敗,服務器程序會拒絕鏈接。
當鏈接創建後,與該客戶端關聯的服務器線程會一直等待客戶端發送請求,MySQL服務器接收到的請求只是一個文本消息,該文本消息還要通過各類處理才能將最後的處理結果返回客戶端。服務器
到如今爲止,MySQL服務器已經得到了文本形式的請求,接着還須要通過查詢緩存
、語法解析
、查詢優化
等進行處理。網絡
若是服務器開啓了查詢緩存,在執行查詢的時候會先從查詢緩存中獲取查詢結果。若是命中緩存則直接返回結果,不然接着執行。mysql不推薦使用查詢緩存,而且在8.0版本已經移除此功能。真實環境中也不會使用,所以不用詳細瞭解。數據結構
這一步主要作的事情是對語句基於SQL語法
進行詞法和語法分析和語義的解析,將要查詢的表、各類查詢條件都提取出來放到MySQL服務器內部使用的一些數據結構上來。架構
由於咱們寫的MySQL語句執行起來效率可能並非很高,MySQL的優化程序會對咱們的語句作一些優化,如外鏈接轉換爲內鏈接、表達式簡化、子查詢轉爲鏈接等等。優化的結果就是生成一個執行計劃,這個執行計劃代表了應該使用哪些索引進行查詢,表之間的鏈接順序等。咱們可使用EXPLAIN
語句來查看某個語句的執行計劃。
mysql數據是保存在數據表
裏面,但表只是邏輯上的概念,數據真正是保存在物理磁盤上的。存儲引擎負責的就是物理上數據的保存和提取。爲了實現不一樣的功能,MySQL提供了各式各樣的存儲引擎,不一樣存儲引擎在物理上的存儲結構存在一些差別。可是不一樣的存儲引擎提供了統一的調用接口(也就是存儲引擎API)。
mysql支持多種存儲引擎,能夠經過以下命令查看:
show engines ;
雖然支持的存儲引擎不少,可是咱們須要重點關注InnoDB以及適當瞭解MyISAM存儲引擎便可!
爲了管理方便,人們把鏈接管理
、查詢緩存
、語法解析
、查詢優化
這些並不涉及真實數據存儲的功能劃分爲MySQL server
的功能,把真實存取數據的功能劃分爲存儲引擎
的功能。
mysql程序(包括服務器相關程序和客戶端相關程序)在啓動的時候能夠指定啓動參數,來控制程序啓動後的行爲。這些啓動參數能夠放在命令行中指定,也能夠把它們放在配置文件中指定。
啓動mysql程序的命令行後邊指定啓動選項的通用格式以下:
--啓動選項1[=值1] --啓動選項2[=值2] ... --啓動選項n[=值n]
各個啓動選項之間使用空白字符隔開,在每個啓動選項名稱前邊添加--
。對於不須要值的啓動選項,比方說skip-networking
,它們就不須要指定對應的值。對於須要指定值的啓動選項,好比default-storage-engine
咱們在指定這個設置項的時候須要顯式的指定它的值,比方說InnoDB
、MyISAM
。
mysqld --default-storage-engine=MyISAM --skip-networking
好比上面的啓動項就表示默認存儲引擎爲MyISAM
,而且禁止使用TCP/IP
方式通訊。
爲了使用的方便,對於一些經常使用的選項提供了短形式,好比:
長形式 | 短形式 | 含義 |
---|---|---|
--host | -h | 主機名 |
--user | -u | 用戶名 |
--password | -p | 密碼 |
--port | -P | 主機名 |
--host | -h | 端口 |
相比於使用命令行的方式設置啓動選項,mysql更推薦使用配置文件來設置啓動選項。咱們把須要設置的啓動選項都寫在這個配置文件中,每次啓動服務器的時候都從這個文件里加載相應的啓動選項。
MySQL程序在啓動時會尋找多個路徑下的配置文件,這些路徑有的是固定的,有的是能夠在命令行指定的。根據操做系統的不一樣,配置文件的路徑也有所不一樣,而且越後面路徑下的配置優先級越好。總之就是多個路徑下均可以存在配置文件,而且有個優先級的關係。這裏就不展開了。
與在命令行中指定啓動選項不一樣的是,配置文件中的啓動選項被劃分爲若干個組,每一個組有一個組名,用中括號[]
擴起來,像這樣:
[server] (具體的啓動選項...) [mysqld] (具體的啓動選項...) [mysqld_safe] (具體的啓動選項...) [client] (具體的啓動選項...) [mysql] (具體的啓動選項...) [mysqladmin] (具體的啓動選項...)
啓動mysql程序時,會使用對應的一個或多個組下的啓動選項。每一個組下邊能夠定義若干個啓動選項,咱們以[server]
組爲例來看一下填寫啓動選項的形式(其餘組中啓動選項的形式是同樣的):
[server] option1 #這是option1,該選項不須要選項值 option2 = value2 #這是option2,該選項須要選項值
mysql系統變量是指可以影響服務器程序運行行爲的變量。好比容許同時連入的客戶端數量由系統變量max_connections
控制,表的默認存儲引擎由系統變量default_storage_engine
控制。每一個系統變量都有一個默認值,咱們可使用命令行或者配置文件中的選項在啓動服務器時改變一些系統變量的值,或者在運行時動態修改(大多數系統變量支持動態修改)。
多個客戶端程序能夠同時鏈接到一個服務器程序。對於同一個系統變量,咱們有時想讓不一樣的客戶端有不一樣的值,mysql經過系統變量的做用範圍來解決上述問題。具體來講做用範圍分爲下面兩種:
GLOBAL
:全局變量,影響服務器的總體操做。SESSION
:會話變量,影響某個客戶端鏈接的操做。(注:SESSION
有個別名叫LOCAL
)很顯然,經過啓動選項設置的系統變量的做用範圍都是GLOBAL
的,也就是對全部客戶端都有效的。經過客戶端動態修改系統變量語法以下:
SET [GLOBAL|SESSION] 系統變量名 = 值;
若是在設置系統變量的語句中省略了做用範圍,默認的做用範圍就是SESSION。同理,咱們可使用下列命令查看MySQL服務器程序支持的系統變量以及它們的當前值:
SHOW [GLOBAL|SESSION] VARIABLES [LIKE 匹配的模式];
mysql狀態變量是指描述服務器運行狀態的變量,比方說Threads_connected
表示當前有多少客戶端與服務器創建了鏈接。
因爲狀態變量是用來顯示服務器程序運行情況的,因此它們的值只能由服務器程序本身來設置(對客戶端而言是隻讀的)。與系統變量相似,狀態變量也有GLOBAL
和SESSION
兩個做用範圍的,因此查看狀態變量的語句能夠這麼寫:
SHOW [GLOBAL|SESSION] STATUS [LIKE 匹配的模式];
在計算機中,數據最終都是以二進制的形式保存的。所以,若是咱們要保存字符串,首先就先得肯定字符串中的每一個字符對應的二進制數據是什麼,而後再將這些二進制數據保存到計算機中。將一個字符映射成一個二進制數據的過程也叫作編碼
,將一個二進制數據映射到一個字符的過程叫作解碼
。
使用字符集能夠解決數據存儲的問題,可是沒法徹底解決字符之間相互比較的問題。簡單場景下,咱們能夠直接經過比較字符的二進制數據來判斷大小,這種方式其實就是二進制比較規則
。而有些場景下,二進制比較規則
並不適用,好比忽略大小寫的時候。所以爲了應對不一樣的場景,同一種字符集能夠有多種比較規則。
mysql中支持不少種字符集,能夠經過如下語句查看:
SHOW CHARSET [LIKE 匹配的模式];
mysql> SHOW CHARSET; +----------+---------------------------------+---------------------+--------+ | Charset | Description | Default collation | Maxlen | +----------+---------------------------------+---------------------+--------+ | utf8 | UTF-8 Unicode | utf8_general_ci | 3 | | ucs2 | UCS-2 Unicode | ucs2_general_ci | 2 | ... | latin7 | ISO 8859-13 Baltic | latin7_general_ci | 1 | | utf8mb4 | UTF-8 Unicode | utf8mb4_general_ci | 4 | | utf16 | UTF-16 Unicode | utf16_general_ci | 4 | | utf16le | UTF-16LE Unicode | utf16le_general_ci | 4 | ... +----------+---------------------------------+---------------------+--------+ 41 rows in set (0.01 sec)
Charset
: 字符集名稱Description
: 字符集描述Default collation
: 默認的比較規則Maxlen
: 一個字符最大佔用的字節數。對於採用變長編碼方式
的字符集而言,一個字符佔用的字節數不是固定的。好比在GB2312字符集
中,一個字母只佔用1個字節,而一個漢字佔用了2個字節。在mysql中,utf8
和utf8mb4
的區別就在於1個字符佔用的最大字節數不一樣。utf8
一個字符佔用1-3個字節,而utf8mb4
一個字符佔用1-4個字節。實際上,mysql的utf8
是utf8mb3
的別名。若是須要保存一些佔用4個字節的特殊字符(好比emoji表情),建議使用utf8mb4
字符集。
能夠經過如下語句查看mysql中支持的比較規則:
SHOW COLLATION [LIKE 匹配的模式];
mysql> SHOW COLLATION LIKE 'utf8\_%'; +--------------------------+---------+-----+---------+----------+---------+ | Collation | Charset | Id | Default | Compiled | Sortlen | +--------------------------+---------+-----+---------+----------+---------+ | utf8_general_ci | utf8 | 33 | Yes | Yes | 1 | | utf8_bin | utf8 | 83 | | Yes | 1 | ... +--------------------------+---------+-----+---------+----------+---------+ 27 rows in set (0.00 sec)
Collation
: 比較規則名稱,基本符合字符集名稱_語言_後綴
模式。第一部分字符集名稱
就是與其關聯的字符集的名稱開頭,第二部分表示該比較規則做用的語言,好比utf8_spanish_ci
是以西班牙語的規則比較,utf8_general_ci
是一種通用的比較規則。第三部分後綴主要用來表示要不要區分大小寫和重音之類的。Charset
: 關聯的字符集的名稱。Default
: yes表示是字符集默認的比較規則。後綴 | 英文釋義 | 描述 |
---|---|---|
_ai | accent insensitive | 不區分重音 |
_as | accent | sensitive |
_ci | case insensitive | 不區分大小寫 |
_cs | case sensitive | 區分大小寫 |
_bin | binary | 以二進制方式比較 |
mysql中字符集和比較規則有4種做用域級別:
實際上,字符集和比較較規則最後確定是做用在列級別
字段上的。能夠簡單的認爲,若是列級別
沒有指定字符集和比較較規則,就使用表級別
的;若是表級別
沒有指定字符集和比較較規則,就使用數據庫級別
的;以此類推。
MySQL提供了兩個系統變量來表示服務器級別的字符集和比較規則:
character_set_server
: 服務器級別的字符集collation_server
: 服務器級別的比較規則服務器級別默認的字符集是utf8
,默認的比較規則是utf8_general_ci
。
咱們在建立和修改數據庫的時候能夠指定該數據庫的字符集和比較規則,具體語法以下:
CREATE DATABASE 數據庫名 CHARACTER SET 字符集名稱 COLLATE 比較規則名稱; ALTER DATABASE 數據庫名 CHARACTER SET 字符集名稱 COLLATE 比較規則名稱;
好比:
mysql> CREATE DATABASE charset_demo_db -> CHARACTER SET gb2312 -> COLLATE gb2312_chinese_ci; Query OK, 1 row affected (0.01 sec)
若是想查看當前數據庫使用的字符集和比較規則,能夠查看下面兩個系統變量的值:
character_set_database
: 當前數據庫的字符集collation_database
: 當前數據庫的比較規則咱們能夠在建立和修改表的時候指定表的字符集和比較規則,語法以下:
CREATE TABLE 表名 (列的信息) CHARACTER SET 字符集名稱 COLLATE 比較規則名稱 ALTER TABLE 表名 CHARACTER SET 字符集名稱 COLLATE 比較規則名稱
好比:
mysql> CREATE TABLE t( -> col VARCHAR(10) -> ) CHARACTER SET utf8 COLLATE utf8_general_ci; Query OK, 0 rows affected (0.03 sec)
須要注意的是,對於存儲字符串的列,同一個表中的不一樣的列也能夠有不一樣的字符集和比較規則。咱們在建立和修改列定義的時候能夠指定該列的字符集和比較規則,語法以下:
CREATE TABLE 表名( 列名 字符串類型 CHARACTER SET 字符集名稱 COLLATE 比較規則名稱, 其餘列... ); ALTER TABLE 表名 MODIFY 列名 字符串類型 CHARACTER SET 字符集名稱 COLLATE 比較規則名稱;
好比咱們修改一下表t中列col的字符集和比較規則能夠這麼寫:
mysql> ALTER TABLE t MODIFY col VARCHAR(10) CHARACTER SET gbk COLLATE gbk_chinese_ci; Query OK, 0 rows affected (0.04 sec) Records: 0 Duplicates: 0 Warnings: 0
還須要注意的一點是:因爲字符集和比較規則是相互聯繫的,若是咱們只修改了字符集和比較規則,均可能引發關聯的字符集和比較規則發生變化。