MYSQL 高階

wangheng1409發表於2021-06-01

SQL查詢流程:

 

  • 1. 通過客戶端/伺服器通訊協議與 MySQL 建立連線
  • 2. 查詢快取,這是 MySQL 的一個可優化查詢的地方,如果開啟了 Query Cache 且在查詢快取過程中查 詢到完全相同的 SQL 語句,則將查詢結果直接返回給客戶端;如果沒有開啟Query Cache 或者沒有查詢到 完全相同的 SQL 語句則會由解析器進行語法語義解析,並生成解析樹。
  • 3. 前處理器生成新的解析樹。
  • 4. 查詢優化器生成執行計劃。
  • 5. 查詢執行引擎執行 SQL 語句,此時查詢執行引擎會根據 SQL 語句中表的儲存引擎型別,以及對應的 API 介面與底層儲存引擎快取或者物理檔案的互動情況,得到查詢結果,由MySQL Server 過濾後將查詢結 果快取並返回給客戶端。若開啟了 Query Cache,這時也會將SQL 語句和結果完整地儲存到 Query Cache 中,以後若有相同的 SQL 語句執行則直接返回結果。

 

MySQL物理檔案:

 

 日誌檔案:

  • error log 錯誤日誌 排錯 /var/log/mysqld.log【預設開啟】
  • bin log 二進位制日誌 備份 增量備份 DDL DML DCL
  • Relay log 中繼日誌 複製 接收 replication master
  • slow log 慢查詢日誌 調優 查詢時間超過指定值
-- 檢視錯誤日誌檔案路徑
show variables like 'log_error';
+---------------+---------------------+
| Variable_name | Value |
+---------------+---------------------+
| log_error | /var/log/mysqld.log |
+---------------+---------------------+
-- 慢查詢日誌檔案路徑
show variables like 'slow_query_log_file';
+---------------------+-----------------------------------+
| Variable_name | Value |
+---------------------+-----------------------------------+
| slow_query_log_file | /var/lib/mysql/localhost-slow.log |
+---------------------+-----------------------------------+
-- bin log 日誌檔案 需要在 my.cnf 中配置
log-bin=/var/log/mysql-bin/bin.log
server-id=2
-- 檢視 relay log 相關引數
show variables like '%relay%'

配置檔案&資料檔案:

配置檔案 my.cnf:

  在 my.cnf 檔案中可以進行一些引數設定, 對資料庫進行調優。

[client] #客戶端設定,即客戶端預設的連線引數
port = 3307 #預設連線埠
socket = /data/mysqldata/3307/mysql.sock #用於本地連線的socket套接字
default-character-set = utf8mb4 #編碼
[mysqld] #服務端基本設定
port = 3307 MySQL監聽埠
socket = /data/mysqldata/3307/mysql.sock #為MySQL客戶端程式和伺服器之間的本地通訊指定一
個套接字檔案
pid-file = /data/mysqldata/3307/mysql.pid #pid檔案所在目錄
basedir = /usr/local/mysql-5.7.11 #使用該目錄作為根目錄(安裝目錄)
datadir = /data/mysqldata/3307/data #資料檔案存放的目錄
tmpdir = /data/mysqldata/3307/tmp #MySQL存放臨時檔案的目錄
character_set_server = utf8mb4 #服務端預設編碼(資料庫級別)
-- 檢視資料檔案的位置
show variables like '%dir%';
+-----------------------------------------+----------------------------+
| Variable_name | Value |
+-----------------------------------------+----------------------------+
| datadir | /var/lib/mysql/ |
+-----------------------------------------+----------------------------
1、.frm檔案
不論是什麼儲存引擎,每一個表都會有一個以表名命名的.frm檔案,與表相關的後設資料(meta)資訊都存放在
此檔案中,包括表結構的定義資訊等。
2、.MYD檔案
myisam儲存引擎專用,存放myisam表的資料(data)。每一個myisam表都會有一個.MYD檔案與之呼應,同
樣存放在所屬資料庫的目錄下
3、.MYI檔案
也是myisam儲存引擎專用,存放myisam表的索引相關資訊。每一個myisam表對應一個.MYI檔案,其存放的
位置和.frm及.MYD一樣
4、.ibd檔案
存放innoDB的資料檔案(包括索引)。
5. db.opt檔案 此檔案在每一個自建的庫裡都會有,記錄這個庫的預設使用的字符集和校驗規。

MySQL查詢和慢查詢日誌分析:

  等待時間長: 

  • 1.鎖表導致查詢一直處於等待狀態,後續我們從MySQL鎖的機制去分析SQL執行的原理

  執行時間長:

  • 1.查詢語句寫的爛
  • 2.索引失效
  • 3.關聯查詢太多join
  • 4.伺服器調優及各個引數的設定

需要遵守的優化原則:

  • 第一條: 只返回需要的結果

     一定要為查詢語句指定 WHERE 條件,過濾掉不需要的資料行

    避免使用 select * from , 因為它表示查詢表中的所有欄位

  • 第二條: 確保查詢使用了正確的索引

經常出現在 WHERE 條件中的欄位建立索引,可以避免全表掃描;

將 ORDER BY 排序的欄位加入到索引中,可以避免額外的排序操作;

多表連線查詢的關聯欄位建立索引,可以提高連線查詢的效能;

將 GROUP BY 分組操作欄位加入到索引中,可以利用索引完成分組。

  • 第三條: 避免讓索引失效

在 WHERE 子句中對索引欄位進行表示式運算或者使用函式都會導致索引失效

使用 LIKE 匹配時,如果萬用字元出現在左側無法使用索引

如果 WHERE 條件中的欄位上建立了索引,儘量設定為 NOT NULL

SQL的執行順序:

  我們寫的sql:

 

sql的執行順序:

 

 

 MYSQL的7種join:

 

 

 

慢查詢日誌分析: 

   MySQL的慢查詢,全名是慢查詢日誌,是MySQL提供的一種日誌記錄,用來記錄在MySQL中響應時間 超過閾值的語句。

   預設情況下,MySQL資料庫並不啟動慢查詢日誌,需要手動來設定這個引數。

      如果不是調優需要的話,一般不建議啟動該引數,因為開啟慢查詢日誌會或多或少帶來一定的效能影 響。

      慢查詢日誌支援將日誌記錄寫入檔案和資料庫表。

SHOW VARIABLES LIKE "%query%" ;

slow_query_log:是否開啟慢查詢日誌, 1 表示開啟, 0 表示關閉。
slow-query-log-file:新版(5.6及以上版本)MySQL資料庫慢查詢日誌儲存路徑。
long_query_time: 慢查詢閾值,當查詢時間多於設定的閾值時,記錄日誌。
預設情況下slow_query_log的值為OFF,表示慢查詢日誌是禁用的

mysql> SHOW VARIABLES LIKE '%slow_query_log%';
+---------------------+-----------------------------------+
| Variable_name | Value |
+---------------------+-----------------------------------+
| slow_query_log | OFF |
| slow_query_log_file | /var/lib/mysql/localhost-slow.log |
+---------------------+-----------------------------------+
可以通過設定slow_query_log的值來開啟

mysql> set global slow_query_log=1;
mysql> SHOW VARIABLES LIKE '%slow_query_log%';
+---------------------+-----------------------------------+
| Variable_name | Value |
+---------------------+-----------------------------------+
| slow_query_log | ON |
| slow_query_log_file | /var/lib/mysql/localhost-slow.log |
+---------------------+-----------------------------------+

  使用 set global slow_query_log=1 開啟了慢查詢日誌只對當前資料庫生效,MySQL重啟後則 會失效。

  如果要永久生效,就必須修改配置檔案my.cnf(其它系統變數也是如此)

-- 編輯配置
vim /etc/my.cnf
-- 新增如下內容
slow_query_log =1
slow_query_log_file=/var/lib/mysql/lagou-slow.log
-- 重啟MySQL
service mysqld restart
mysql> SHOW VARIABLES LIKE '%slow_query_log%';
+---------------------+-------------------------------+
| Variable_name | Value |
+---------------------+-------------------------------+
| slow_query_log | ON |
| slow_query_log_file | /var/lib/mysql/lagou-slow.log |
+---------------------+-------------------------------+

那麼開啟了慢查詢日誌後,什麼樣的SQL才會記錄到慢查詢日誌裡面呢?

這個是由引數 long_query_time 控制,預設情況下long_query_time的值為10秒

mysql> show variables like 'long_query_time';
+-----------------+-----------+
| Variable_name | Value |
+-----------------+-----------+
| long_query_time | 10.000000 |
+-----------------+-----------+

注意:使用命令 set global long_query_time=1 修改後,需要重新連線或新開一個會話才能 看到修改值。

mysql> set global long_query_time=1;
mysql> show variables like 'long_query_time';
+-----------------+----------+
| Variable_name | Value |
+-----------------+----------+
| long_query_time | 1.000000 |
+-----------------+----------+

log_output 引數是指定日誌的儲存方式。 log_output='FILE' 表示將日誌存入檔案,預設值 是'FILE'。

log_output='TABLE' 表示將日誌存入資料庫,這樣日誌資訊就會被寫入到 mysql.slow_log 表中。

mysql> SHOW VARIABLES LIKE '%log_output%';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| log_output | FILE |
+---------------+-------+

 系統變數 log-queries-not-using-indexes :未使用索引的查詢也被記錄到慢查詢日誌中(可選 項)。如果調優的話,建議開啟這個選項。

mysql> show variables like 'log_queries_not_using_indexes';
+-------------------------------+-------+
| Variable_name | Value |
+-------------------------------+-------+
| log_queries_not_using_indexes | OFF |


mysql> set global log_queries_not_using_indexes=1;
Query OK, 0 rows affected (0.00 sec)
mysql> show variables like 'log_queries_not_using_indexes';

+-------------------------------+-------+
| Variable_name | Value |
+-------------------------------+-------+
| log_queries_not_using_indexes | ON |
+-------------------------------+-------+
1 row in set (0.00 sec)

MySQL儲存引擎:

InnoDB(推薦):

  優點:

  • Innodb引擎提供了對資料庫ACID事務的支援,並且實現了SQL標準的四種隔離級別
  • 支援多版本併發控制的行級鎖,由於鎖粒度小,寫操作和更新操作併發高、速度快。
  • 支援自增長列。
  • 支援外來鍵。
  • 適合於大容量資料庫系統,支援自動災難恢復。

   缺點:

  • 它沒有儲存表的行數,當SELECT COUNT(*) FROM TABLE時需要掃描全表

 應用場景 :

  •  當需要使用資料庫事務時,該引擎當然是首選。由於鎖的粒度更小,寫操作不會鎖定全表, 所以在併發較高時,使用Innodb引擎會提升效率
  • 更新密集的表, InnoDB儲存引擎特別適合處理多重併發的更新請求

MyISAM:

優點:

  • MyISAM儲存引擎在查詢大量資料時非常迅速,這是它最突出的優點
  • 另外進行大批量插入操作時執行速度也比較快。

缺點:

  • MyISAM表沒有提供對資料庫事務的支援。
  • 不支援行級鎖和外來鍵。
  • 不適合用於經常UPDATE(更新)的表,效率低。

應用場景:

  • 以讀為主的業務,例如:圖片資訊資料庫,部落格資料庫,商品庫等業務。
  • 對資料一致性要求不是非常高的業務(不支援事務)
  • 硬體資源比較差的機器可以用 MyiSAM (佔用資源少)

MySQL索引優化:

普通索引:

CREATE INDEX <索引的名字> ON tablename (欄位名);
ALTER TABLE tablename ADD INDEX [索引的名字] (欄位名);
CREATE TABLE tablename ( [...], INDEX [索引的名字] (欄位名) );

唯一索引:

CREATE UNIQUE INDEX <索引的名字> ON tablename (欄位名);
ALTER TABLE tablename ADD UNIQUE INDEX [索引的名字] (欄位名);
CREATE TABLE tablename ( [...], UNIQUE [索引的名字] (欄位名) ;

主鍵索引:

CREATE TABLE tablename ( [...], PRIMARY KEY (欄位名) );
ALTER TABLE tablename ADD PRIMARY KEY (欄位名);

複合索引:

  使用者可以在多個列上建立索引,這種索引叫做組複合索引(組合索引)。複合索引可以代替 多個單一索引,相比多個單一索引複合索引所需的開銷更小。

CREATE INDEX <索引的名字> ON tablename (欄位名1,欄位名2...);
ALTER TABLE tablename ADD INDEX [索引的名字] (欄位名1,欄位名2...);
CREATE TABLE tablename ( [...], INDEX [索引的名字] (欄位名1,欄位名2...) );

複合索引注意事項:

  • 1. 何時使用複合索引,要根據where條件建索引,注意不要過多使用索引,過多使用會對 更新操作效率有很大影響。
  • 2. 如果表已經建立了(col1,col2),就沒有必要再單獨建立(col1);如果現在有(col1)索 引,如果查詢需要col1和col2條件,可以建立(col1,col2)複合索引,對於查詢有一定提 高。

全文索引:

  查詢操作在資料量比較少時,可以使用like模糊查詢,但是對於大量的文字資料檢索,效率很 低。如果使用全文索引,查詢速度會比like快很多倍。

CREATE FULLTEXT INDEX <索引的名字> ON tablename (欄位名);
ALTER TABLE tablename ADD FULLTEXT [索引的名字] (欄位名);
CREATE TABLE tablename ( [...], FULLTEXT KEY [索引的名字] (欄位名) ;

和常用的like模糊查詢不同,全文索引有自己的語法格式,使用 match 和 against 關鍵字,比如:

SELECT * FROM users3 WHERE MATCH(NAME) AGAINST('aabb');
-- * 表示萬用字元,只能在詞的後面
SELECT * FROM users3 WHERE MATCH(NAME) AGAINST('aa*' IN BOOLEAN MODE);

全文索引使用注意事項:

  • 全文索引必須在字串、文字欄位上建立。
  • 全文索引欄位值必須在最小字元和最大字元之間的才會有效。(innodb:3-84; myisam:4-84)

建立索引的原則:

  • 在經常需要搜尋的列上建立索引,可以加快搜尋的速度;
  • 在作為主鍵的列上建立索引,強制該列的唯一性和組織表中資料的排列結構;
  • 在經常用在連線的列上,這些列主要是一些外來鍵,可以加快連線的速度;
  • 在經常需要根據範圍進行搜尋的列上建立索引,因為索引已經排序,其指定的範圍是連續 的;
  • 在經常需要排序的列上建立索引,因為索引已經排序,這樣查詢可以利用索引的排序,加快 排序查詢時間;
  • 在經常使用在WHERE子句中的列上面建立索引,加快條件的判斷速度。
  • group by欄位

索引原理:

  hash 結構:

    Hash底層實現是由Hash表來實現的,是根據鍵值 <key,value> 儲存資料的結構。非常適合根據 key查詢value值,也就是單個key查詢,或者說等值查詢。

  B+Tree結構

    非葉子節點不儲存data資料,只儲存索引值,這樣便於儲存更多的索引值 葉子節點包含了所有的索引值和data資料 葉子節點用指標連線,提高區間的訪問效能

 

 

 EXPLAIN效能分析:

  

 

id:

   id相同,執行順序由上至下

  id不同,如果是子查詢,id的序號會遞增,id值越大優先順序越高,越先被執行

 

 

 select_type:

  simple : 簡單的select查詢,查詢中不包含子查詢或者UNION

  primary : 查詢中若包含任何複雜的子部分,最外層查詢被標記

  subquery : 在select或where列表中包含了子查詢

  

 

union : 如果第二個select出現在UNION之後,則被標記為UNION,如果union包含在from子句 的子查詢中,外層select被標記為derived

 

 

 type介紹:

  type顯示的是連線型別,是較為重要的一個指標。

  下面給出各種連線型別,按照從最佳型別到最壞型別 進行排序:

     system > const > eq_ref > ref > range > index > ALL

system : 表僅有一行 (等於系統表)。這是const連線型別的一個特例,很少出現。

const : 表示通過索引 一次就找到了, const用於比較 primary key 或者 unique 索引. 因為只匹配 一行資料,所以如果將主鍵 放在 where條件中, MySQL就能將該查詢轉換為一個常量

 

 

 eq_ref : 唯一性索引掃描,對於每個索引鍵,表中只有一條記錄與之匹配. 常見與主鍵或唯一索引掃描

 

 

 ref : 非唯一性索引掃描, 返回匹配某個單獨值的所有行, 本質上也是一種索引訪問, 它返回所有匹配 某個單獨值的行, 這是比較常見連線型別.

 

 

 range : 只檢索給定範圍的行,使用一個索引來選擇行。

 

 

 index : 出現index 是 SQL 使用了索引, 但是沒有通過索引進行過濾,一般是使用了索引進行排序分 組

 

 

 

ALL : 對於每個來自於先前的表的行組合,進行完整的表掃描。

 

 

 possible_keys:顯示可能應用到這張表上的索引, 一個或者多個. 查詢涉及到的欄位上若存在索引, 則該索引將 被列出, 但不一定被查詢實際使用

key :實際使用的索引

 

key_len介紹:

 

 表示索引中使用的位元組數, 可以通過該列計算查詢中使用索引的長度.

CREATE TABLE T1(
a INT PRIMARY KEY,
b INT NOT NULL,
c INT DEFAULT NULL,
d CHAR(10) NOT NULL
);

EXPLAIN SELECT * FROM T1 WHERE a > 1 AND b = 1;

ALTER TABLE T1 ADD INDEX idx_b(b);

 

 

ALTER TABLE T1 ADD INDEX idx_d(d);

 

 

 

 

    

 

相關文章