MySQL 學習(2)—— MySQL 體系結構與管理 | 8月更文挑戰

這是我參與8月更文挑戰的第2天,活動詳情查看:8月更文挑戰mysql

1. MySQL 客戶端和服務端模型

MySQL 是一種典型的 C/S 結構,C/S 結構即 客戶端/服務端 模型。git

服務端程序:mysqld MySQL 自帶的客戶端:mysql、mysqladmin、mysqldump 等程序員

2. MySQL 的兩種鏈接方式

經過網絡鏈接串:TCP/IP
# mysql -uroot -p -h 127.0.0.1 -P3306
經過套接字文件,socket
# mysql -uroot -p -S /tmp/mysql.sock
複製代碼

3. 實例

3.1 通俗解釋

首先來講說,數據庫是作什麼的。github

數據庫是用來長久存儲數據的,而咱們你們都知道內存只能臨時存儲,磁盤等才能真正存儲數據。那麼數據庫會放在哪裏呢?確定是存放在磁盤上,因此數據庫其實就是磁盤上的一個文件。算法

簡單的理解就是:數據庫 = 磁盤上的文件。sql

既然數據庫能夠當作是磁盤上文件,那麼咱們怎麼使用數據庫呢?shell

若是說咱們能夠直接使用數據庫,那就等價於直接使用磁盤上的文件。咱們還知道,咱們只有把磁盤上的文件讀入內存中才可使用。這即是正確的數據庫的使用流程。數據庫

那麼數據庫如何把數據讀入內存中呢?緩存

這個時候就須要咱們將要介紹的實例(instance)了,實例能夠理解爲內存結構和一組後臺進程。bash

實例是用來將磁盤中的數據讀入內存中,並使用數據。

3.2 專業解釋

MySQL 在啓動過程當中,會:

  • 啓動後臺守護進程(mysqld);
  • 生成工做線程;
  • 預分配內存結構供 MySQL 處理數據使用;

因此實例是:MySQL 的後臺進程 + 線程 + 預分配的內存結構

而 MySQL 是單進程多線程,也就是說 MySQL 實際在系統中表現的就是一個服務進程,即進程(經過多種方法能夠建立多實例,再安裝一個端口號不一樣的 MySQL,或者經過 workbench 來新建一個端口號不一樣的服務實例等)

4. mysql 和 mysqld 的區別

  • mysqld 是 SQL 的後臺程序(即 MySQL 服務器),mysqld 意思是 mysql daemon,在後臺運行,監聽 3306 端口,要想使用客戶端程序,該程序必須運行,由於客戶端經過鏈接服務器來訪問數據庫。
  • mysql 是交互式輸入 SQL 語句或從文件以批處理模式執行它們的命令行工具。

5. SQL 語句引入

咱們平時在 Linux 常常會使用一些專業的命令來管理咱們操做系統中的對象,好比 touchmkidr。這些命令是 Linux 操做系統 bash shell 支持的一些功能。

對於 MySQL 也同樣,MySQL 可能不會用 ls 這些命令,MySQL 也有一些專用的內置命令,用來管理數據庫中的數據,咱們把這種命令稱爲 SQL(Structured Query Language,結構化查詢語言)。

爲了更方便的學習記憶,咱們將 SQL 語句分爲以下經常使用的幾類:

  • DML:(Data Manipulation Language,數據操做語言),由數據庫管理系統(DBMS)提供,用於讓用戶或程序員使用,實現對數據庫中數據的操做。主要包括 selectinsertupdatedeletemergeexplain plancalllock table 等語句。
  • DDL:(Data Definition Language,數據定義語言),用於定於 SQL 模式、基本表、視圖和索引的建立、撤銷操做,主要包含 createalterdroptruncatecommentreplace(rename) 等語句,通常不須要 commit 等事務操做。
  • DCL:(Data Control Language,數據控制語言),用於數據庫受權、角色控制等管理工做。主要包含 grantrevoke 等語句。
  • TCL:(Transaction Control Language,事務控制語言),用於數據庫的事務管理。主要包含 savepointrollbackcommitset transaction 等語句。

好比咱們熟悉的這條語句,在 Linux 中沒法執行。

# select user,host from mysql.user;
-bash: 未預期的符號 `from' 附近有語法錯誤
複製代碼

咱們得進入到 mysql 中才能運行。

mysql> select user,host from mysql.user;
+---------------+-----------+
| user          | host      |
+---------------+-----------+
| mysql.session | localhost |
| mysql.sys     | localhost |
| root          | localhost |
+---------------+-----------+
3 rows in set (0.00 sec)
複製代碼

整個過程看起來很是簡單,輸入語句,點擊回車,而後就顯示結果了。

可是咱們有沒有想過,爲何咱們在平時的業務開發中,好比要實現一個功能,有的人寫的語句執行就快,有的人寫的語句執行就慢,結果都是同樣的,那麼爲何一個快一個慢呢?

咱們可能會想到有可能執行的慢的語句很是長、寫的很複雜,是的,有多是這個緣由。

那麼咱們再深刻想想,有沒有多是語句在內部執行過程當中,發生了什麼不可預料的操做,或者是一些操做是代價較高的操做。咱們可能不能從表面上看出問題,另外呢,也不必定 SQL 長就慢,反而有多是越長的 SQL 執行越快,越簡易的語句執行的越慢。

所以,咱們不該該僅僅關注結果,而不去關注過程,就沒法找到根本的緣由,接下來,咱們來學習一下,從鏈接數據庫開始,到輸入 SQL 語句,而後點擊回車,而後顯示結果,這個過程當中間到底發生了什麼。

接下來,咱們就經過這一條查詢語句,來學習一下 MySQL 詳細的工做流程。

6. MySQL 內部執行過程

6.1 mysqld 程序結構

mysqld 結構,咱們分紅了三層:鏈接層、SQL 層、存儲引擎層。

MySQL 體系結構

6.2 鏈接層

首先一條語句多是一個用戶發起的,好比 Navicat,Navicat 執行以下一條語句:

select user,host from mysql.user;
複製代碼

那麼首先 Navicat 得鏈接上 MySQL,那麼它怎麼鏈接呢?咱們以前有說過,經過 tcp/ip 或者 socket 方式進行鏈接。這說明鏈接層得支持這兩種協議,並支持使用這兩種協議進行鏈接。

而後,好比咱們使用 tcp/ip 方式鏈接,咱們還要輸入用戶名、密碼、IP、端口號。假設我輸入的端口號是 3307,那麼可以登錄嗎,確定是不能夠的,由於咱們配置的端口號是 3306,那說明鏈接層的做用還有對用戶名、密碼、IP、端口號等進行校驗,驗證合法性。

連上了以後,咱們也說了,在 MySQL 裏面全部要實現的功能都須要工做的線程來提供,好比說,接收請求語句,返回結果。因此,在鏈接層會自動開啓一個鏈接線程,接收語句、查看結果。咱們能夠經過 show processlist 來查看鏈接線程狀況。

mysql> show processlist;
+-----+------+-----------+------+---------+------+----------+------------------+
| Id  | User | Host      | db   | Command | Time | State    | Info             |
+-----+------+-----------+------+---------+------+----------+------------------+
| 282 | root | localhost | NULL | Query   |    0 | starting | show processlist |
+-----+------+-----------+------+---------+------+----------+------------------+
1 row in set (0.01 sec)
複製代碼

而後我在另外一個終端上再啓動一個 MySQL,再執行一下,發現鏈接線程變成了兩個。

mysql> show processlist;
+-----+------+-----------+------+---------+------+----------+------------------+
| Id  | User | Host      | db   | Command | Time | State    | Info             |
+-----+------+-----------+------+---------+------+----------+------------------+
| 282 | root | localhost | NULL | Sleep   |   20 |          | NULL             |
| 286 | root | localhost | NULL | Query   |    0 | starting | show processlist |
+-----+------+-----------+------+---------+------+----------+------------------+
2 rows in set (0.00 sec)
複製代碼

默認鏈接線程最多有 151 個,固然這個數字能夠調整。沒有用戶請求進來都會開闢一個會話,若是這個會話 8 個小時沒有動做的話,就會斷開這個鏈接。

到這裏,鏈接層的工做就作完了,接着把請求傳遞給下一層。

總結一下,鏈接層做用:

  1. 經過鏈接協議:tcp/ip 以及 socket 鏈接;
  2. 登陸驗證:驗證用戶名、密碼、IP、端口號等合法性;
  3. 提供鏈接線程:接收用戶 SQL 語句以及返回結果(使用 show processlist 命令能夠查看用戶鏈接的線程狀況)
  4. 將請求傳遞給下一層,SQL 層。

6.3 SQL 層

  1. 接收上層傳送的 SQL 語句。

    SQL 層確定首先將 SQL 接收到,而後才能執行後面的操做。

  2. 語法檢查:驗證語句語法,判斷是否知足 SQL_MODE。

    語法檢查確定是必要的,若是語法檢查都沒用過,那確定也無法執行了。

    SQL_MODE 經常使用來解決下面幾類問題:

    1. 經過設置 SQL_MODE,能夠完成不一樣嚴格程度的數據校驗,有效地保障數據準確性。
    2. 經過設置 SQL_MODE 爲寬鬆模式,來保證大多數 SQL 符合標準的 SQL 語法,這樣應該用在不一樣數據庫之間進行遷移時,則不須要對業務的 SQL 進行較大的修改。
    3. 在不一樣數據庫以前進行數據遷移以前,經過設置 SQL_MODE 可使 MySQL 上的數據更方便的遷移到目標數據庫中。
  3. 語義檢查。判斷 SQL 語句的類型。

    在 Linux 上,咱們以某個用戶登陸,好比 work 用戶,有些文件是不能刪除的,必須切換到 root 用戶才能夠操做。對於 MySQL 也是如此。可是在進行權限以前,咱們能夠先對 SQL 語句的類型作一下判斷,而後再來判斷相應的權限。

    • DDL:數據定義語言,如 create/drop/alter/
    • DCL:數據控制語言,如 grant/revoke/commit
    • DML:數據操做語言,如 insert/delete/update/select
    • DQL:數據查詢語言,如 select
  4. 權限檢查,檢查用戶對庫、表是否有相應權限。

  5. 解析器:進行 SQL 語句的預處理,生成解析器(explain desc),生成多種執行方案。

    MySQL 執行語句是否能夠直接執行?執行完以後是否會產生很差的效果?咱們是否須要評估一下語句的代價有多高?找到一個最快的、最合適的執行方式。

  6. 優化器:根據解析器得出的多種執行方案,進行判斷,選出最優的執行計劃。

    代價模型:之前 MySQL 是按照時間去衡量 SQL 語句的優劣,如今按(CPU/IO/MEM)的損耗評估性能的好壞(基於代價)。

    各個版本的優化器算法是不一樣的。

  7. 執行器,選擇最優的執行計劃去執行 SQL 語句,產生執行的結果。

    真正運行 SQL。

    執行結果:會提供給存儲引擎層一個結果說明這個查詢的結果在磁盤的哪一個位置。

  8. 提供查詢緩存(默認不開)。

    若是某些 SQL 一直執行,好比執行 1000 萬次,那麼咱們就沒有必要一直執行了,咱們能夠提供一個查詢緩存,將請求結果放到緩存中。

  9. 提供日誌記錄(binlog),記錄二進制日誌,默認不開啓。

    包括審計日誌、通用日誌、binlog。

6.4 存儲引擎層

在 SQL 層中,執行器執行完,會得出一個結果,來展現給咱們,可是咱們的數據在哪呢,其實還在磁盤上。

Linux 上對於磁盤使用是文件系統,不能直接對磁盤進行讀寫。MySQL 也是如此。MySQL 將這個專門負責特殊數據讀寫的文件系統叫作存儲引擎。(相似於 FS)。

存儲引擎層的做用:

  1. 根據 SQL 的執行結果,去磁盤上找到相應數據。

  2. 找到磁盤上的 16 進制數據,再次返回 SQL 層,結構化成二維表的方式,再由鏈接層的專用線程返回用戶,最終展示出來。

7. MySQL 邏輯存儲結構

咱們能夠把 MySQL 理解成一個文件系統,所以不少概念、命令能夠對比 Linux 學習。下標中總結了 MySQL 和 Linux 中相似的概念。

MySQL 中概念 Linux 中概念
目錄
create database account charset utf8mb4; mkdir /account
show databases; ls /
use account; cd /account
文件
列(字段)
數據行(記錄) 數據行
表屬性 文件屬性
列屬性

8. MySQL 物理存儲結構

8.1 數據庫

MySQL 中的庫在文件系統上是使用目錄來表示。咱們 MySQL 的數據存儲在 /data/mysql/data 下。

首先咱們查看一下咱們的數據庫。

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
4 rows in set (0.00 sec)
複製代碼

而後我在 /data/mysql/data 下建立個 account 目錄。

# mkdir account
複製代碼

咱們再來看一下數據庫。

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| account            |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
5 rows in set (0.00 sec)
複製代碼

能夠看到多了一個 account 數據庫。

8.2 表

咱們如今來看一下常見的 MyISAM 存儲引擎和 InnoDB 存儲引擎中數據是如何存儲的。以 mysql.user 表爲例。

8.2.1 MyISAM

# cd /data/mysql/data/mysql
# ls
......
-rw-r----- 1 mysql mysql   10816 1月  13 22:25 user.frm
-rw-r----- 1 mysql mysql     396 1月  14 17:21 user.MYD
-rw-r----- 1 mysql mysql    4096 1月  14 17:21 user.MYI
複製代碼

對於 MyISAM 存儲引擎,MySQL 用 user.frmuser.MYDuser.MYI 三張表來存儲數據。

  • user.frm:存儲表結構(列、屬性)
  • user.MYD:存儲的數據記錄
  • user.MYI:存儲索引

8.2.2 InnoDB

-rw-r----- 1 mysql mysql    8636 1月  13 22:25 time_zone.frm
-rw-r----- 1 mysql mysql   98304 1月  13 22:25 time_zone.ibd
複製代碼

對於 InnoDB 存儲引擎,MySQL 用 time_zone.frmtime_zone.ibd 兩張表來存儲數據。

  • time_zone.frm:存儲表結構(列、屬性)
  • time_zone.ibd:存儲的數據記錄和索引

其實對於 InnoDB 存儲引擎,MySQL 還有一個文件用來存儲元數據,也就是數據字典。該文件名叫 ibdata1。咱們在 /data/mysql/data 目錄下。

9. InnoDB 段、區、頁

通常狀況下(非分區表):

  • 一個表就是一個段;
  • 一個段由多個區構成;
  • 一個區在一個頁是 16k 大小的狀況下,由 64 個連續的頁構成,共 1M 大小;

10. 用戶和權限管理

10.1 用戶做用

  1. 登陸 MySQL
  2. 管理 MySQL

10.2 用戶定義

用戶名@'白名單',例如:root@'localhost'

10.3 用戶操做

10.3.1 建立用戶:

mysql> create user user2@'localhost';
mysql> exit
複製代碼
# mysql -uuser2
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 307
......
複製代碼

10.3.2 建立用戶(帶密碼):

mysql> create user user3@'localhost' identified by '123';
Query OK, 0 rows affected (0.00 sec)
複製代碼

10.3.3 查詢用戶:

mysql> select user,host from mysql.user;
+---------------+-----------+
| user          | host      |
+---------------+-----------+
| user1         | 10.0.0.%  |
| mysql.session | localhost |
| mysql.sys     | localhost |
| root          | localhost |
| user2         | localhost |
| user3         | localhost |
+---------------+-----------+
6 rows in set (0.00 sec)
複製代碼

10.3.3 修改用戶密碼

mysql> alter user user3@'localhost' identified by '123456';
Query OK, 0 rows affected (0.00 sec)
複製代碼

10.3.4 刪除用戶

mysql> drop user user3@'localhost';
Query OK, 0 rows affected (0.01 sec)

mysql> select user,host from mysql.user;
+---------------+-----------+
| user          | host      |
+---------------+-----------+
| user1         | 10.0.0.%  |
| mysql.session | localhost |
| mysql.sys     | localhost |
| root          | localhost |
| user2         | localhost |
+---------------+-----------+
5 rows in set (0.00 sec)
複製代碼

10.4 權限管理

10.4.1 權限列表

  • ALL:全部權限

    select、insert、update、delete ......

  • with grant option:受權權限(能夠給其餘用戶受權)

10.4.2 受權命令

grant 權限 on 做用目標 to 用戶 identified 密碼 with grant option;

做用目標:

  • *.*:MySQL 下全部數據庫全部表。
  • account.*:account 數據庫下面的全部表
  • account.t1:account 數據庫下面的 t1 表

10.4.3 受權需求

  1. 建立一個管理員用戶,能夠經過 10 網段,管理數據庫
mysql> grant all on *.* to root@'10.0.0.*' identified by '123' with grant option;
複製代碼
  1. 建立一個應用用戶,能夠經過 10 網段,能夠對 account 庫下的表進行 select、insert、delete、update
mysql> grant select,insert,delete,update on account.* to user4@'10.0.0.*' identified by '123';
複製代碼

10.4.4 回收權限

  • 查看權限
mysql> show grants for user4@'10.0.0.*';
+---------------------------------------------------------------------------+
| Grants for user4@10.0.0.*                                                 |
+---------------------------------------------------------------------------+
| GRANT USAGE ON *.* TO 'user4'@'10.0.0.*'                                  |
| GRANT SELECT, INSERT, UPDATE, DELETE ON `account`.* TO 'user4'@'10.0.0.*' |
+---------------------------------------------------------------------------+
2 rows in set (0.00 sec)
複製代碼
  • 回收權限
mysql> revoke delete on account.* from user4@'10.0.0.*';
Query OK, 0 rows affected (0.00 sec)

mysql> show grants for user4@'10.0.0.*';
+-------------------------------------------------------------------+
| Grants for user4@10.0.0.*                                         |
+-------------------------------------------------------------------+
| GRANT USAGE ON *.* TO 'user4'@'10.0.0.*'                          |
| GRANT SELECT, INSERT, UPDATE ON `account`.* TO 'user4'@'10.0.0.*' |
+-------------------------------------------------------------------+
2 rows in set (0.00 sec)
複製代碼
相關文章
相關標籤/搜索