看了這篇MySQL,開發功力又升級!

你們好,我是小菜,一個渴望在互聯網行業作到蔡不菜的小菜。可柔可剛,點贊則柔,白嫖則剛!
死鬼~看完記得給我來個三連哦!
mysql

本文主要介紹 Mysql開發和麪試中所必知的
本文較長,分爲上下篇(可收藏,勿吃塵)
若有須要,能夠參考
若有幫助,不忘 點贊linux

1、MySQL架構

1)MySQL簡介

MySQL是一個關係型數據庫管理系統,由瑞典MYSQL AB公司開發,目前屬於Oracle公司。
MySQL 是一種關聯數據庫管理系統,將數據保存在不一樣的表中,而不是將全部數據放在一個大倉庫中,這樣就增長了速度並提升了靈活性。
Mysql是開源的,是能夠定製的,採用了GPL協議,你能夠修改源碼來開發本身的MySQL系統。
MySQL支持大型的數據庫。能夠處理擁有上千萬條記錄的大型數據庫。MySQL能夠容許於多個系統上,而且支持多種語言。這些編程語言包括C、C++、Python、Java、Perl、PHP、Eiffel、Ruby和Tcl等。
MySQL支持大型數據庫,支持5000條記錄的數據倉庫,32位系統表文件最大可支持4GB,64位系統支持最大的表文件爲8TB。ios

2)MySQL配置文件

  • binlog(二進制日誌)
    用於主從複製及備份恢復:binlog中存放了全部操做記錄,可用於恢復。至關於Redis中的AOF,my.ini中binlog配置(默認是關閉的)如何開啓:
[mysqld]
log-bin = mysql-bin
binlog-format = row
複製代碼
  • Error log(錯誤日誌)
    默認是關閉的,一般用於記錄數據庫服務端啓動、重啓、主從複製時,記錄錯誤,將日誌詳情保留在文件中,方便DBA、運維開發人員閱讀。如何開啓:
[mysqld]
log-error=/data/mysql_error.log
複製代碼
  • 慢查詢日誌log
    默認是關閉的。記錄查詢的sql語句,若是開啓會減低mysql的總體性能,由於記錄日誌也是須要消耗系統資源的。如何開啓:
[mysqld]
slow_query_log = ON
slow_query_log_file = /usr/local/mysql/data/slow.log     //linux
long_query_time = 1
複製代碼
  • 數據文件
    windows:
    ..\mysql-8.0.19-winx64\data目錄下存儲數據庫文件
    linux:
    默認路徑/var/lib/mysql(可在配置文件中更改/usr/share/mysql/下的my-huge.cnf)每一個目錄表明一個同名的庫。
    Myisam存放方式:
  • frm文件(framework):存放表結構
  • myd文件(data):存放表數據
  • myi文件(index):存放表索引
    innodb存放方式:
  • ibdata1:Innodb引擎將全部表的數據都存放在這裏面/usr/share/mysql/ibdata1而frm文件存放在庫同名的包下
  • frm文件:存放表結構
  • 配置方式
    • windows:my.ini 配置文件
    • linux:my.cnf 配置文件

3)MySQL的用戶與權限管理

  • MysSQL用戶管理
    • 建立用戶
      create user cbuc identified by '123456'
    • 關於 user 表
      select host,user,select_priv,insert_priv,drop_priv from mysql.user;

      host: 表示鏈接類型
      user:表示用戶名
      select_priv,insert_priv,drop_priv等:該用戶所擁有的權限
    • 設置密碼
      --- 修改當前用戶的密碼
      set password = password('123456')
      --- 修改某個用戶的密碼
      update mysql.user set password = password('123456') where user = 'cbuc'
    • 修改用戶
      --- 修改用戶名:
      update mysql.user set user = 'cbuc' where user='c1';
      --- 全部經過user表修改後必須用該命令才能生效
      flush privileges;
    • 刪除用戶
      --- 不要經過delete from user t1 where t1.user='cbuc'進行刪除,系統會有殘留信息保留
      drop user cbuc;
  • 權限管理
    • 授予權限:
      --- 若是發現沒有該用戶,則會直接建立一個用戶
      grant 權限1,權限2,…,權限n on 數據庫名.表名 to 用戶名@用戶地址 identified by '密碼'
      --- 給cbuc用戶賦予對錶增刪改查的權限
      grant select,insert,delete,update on db_crm.* to cbuc@localhost;
    • 收回權限:
      --- 若是已賦全庫的表,就回收全庫全表的全部權限
      revoke 權限1,權限2,…,權限n on 數據庫名.表名 from 用戶名@用戶地址
      revoke all privileges on mysql.* from cbuc@localhost
    • 收回權限:
      --- 查看當前用戶權限
      show grants;
      --- 查看某用戶的全局權限
      select * from mysql.user;
      --- 查看某用戶的某庫的權限
      select * from mysql.db;
      --- 查看某用戶的某個表的權限
      select * from mysql.tables_priv;

4)MySQL其餘配置

  • 大小寫問題

windows系統默認是大小寫不敏感,可是linux系統是大小寫敏感的。web

  • 0(默認): 大小寫敏感
  • 1: 大小寫不敏感。建立的表,數據庫都是以小寫形式存放在磁盤中,對於sql語句都是轉換爲小寫對錶的DB進行查找。
  • 2: 建立的表和DB依據語句上格式存放,凡是查找都是轉換爲小寫進行
SHOW VARIABLES LIKE '%lower_case_table_names%';
複製代碼

設置:

set lower_case_table_names = 1;   #此變量是隻讀權限,須要在配置文件中修改
複製代碼
  1. 在my.inni / my.cnf中添加
    [mysqld]
    lower_case_table_names = 1 
複製代碼
  1. 重啓服務器(重啓前要將原來的數據庫和錶轉換爲小寫,不然更改後將找不到數據庫名
  • sql_mode

sql_mode 是個很容易被忽視的變量,默認值是空值,在這種設置下是能夠容許一些非法操做的, 好比容許一些非法數據的插入。在生產環境必須將這個值設置爲嚴格模式,因此開發、測試環境的數據庫也必需要設置,這樣在開發測試階段就能夠發現問題。面試

經常使用設置:算法

[mysqld]
sql-mode="STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION"
複製代碼

5)MySQL存儲引擎

  • 查看引擎
show engines;
複製代碼

能夠看出默認的存儲引擎是 InooDB

  • 各引擎簡介sql

    • InnoDB存儲引擎:
      InnoDB是MySQL默認的事務型引擎,它被設計用來處理大量的短時間(short-lived)事務。除非有很是特別的緣由須要使用其餘的存儲引擎,不然應該優先考慮InnoDB引擎。具備行級鎖外鍵事務等優點,適合高併發狀況
    • MyISAM存儲引擎:
      MyISAM提供了大量的特性,包括全文索引、壓縮、空間函數(GIS)等,但MyISAM不支持事務和行級鎖(MyISAM改表時會將整個表全鎖住),缺陷:崩潰後沒法安全恢復
    • Archive引擎:
      rchive存儲引擎只支持 insert 和 select操做,在MySQL5.1以前不支持索引。Archive表適合日誌和數據採集類引用。適合低訪問量大數據等狀況
    • Blackhole引擎
      Blackhole引擎沒事實現任何存儲機制,它會丟棄全部插入的數據,不任何保存。但服務器會記錄Blackhole表的日誌,因此能夠用於複製數據到備庫,或者簡單地記錄到日誌。但這種應用方式會碰到不少問題,所以並不推薦。
    • CSV引擎
      CSV引擎能夠將普通的CSV文件做爲MySQL的表來處理,但不支持索引。能夠做爲一種數據交換的機制,很是有用。存儲的數據直接能夠在操做系統裏,用文本編輯器,或者excel讀取。
    • Memory引擎
      若是須要快速地訪問數據,而且這些數據不會被修改,重啓後丟失也沒有關係的話,那麼使用Memory表是很是有用的。Memory表至少比MyISAM表要快一個數量級。
    • Federated引擎
      Federated引擎是訪問其餘MySQL服務器的一個代理,儘管該引擎看起來提供了一種很好的跨服務器的靈活性,但也常常帶來問題,所以默認是禁用的。
  • MyISAM和InnoDB比較
    數據庫

    InnoDB主鍵爲聚簇索引,基於聚簇索引的增刪改查效率很是高
    聚簇索引: 實際存儲的循序結構與數據存儲的物理機構是一致的
    非聚簇索引: 記錄的物理順序與邏輯順序沒有必然的聯繫,與數據的存儲物理結構沒有關係

2、索引優化分析

1)性能降低/SQL執行時間長

  • 查詢數據過多
    能拆則拆,條件過濾儘可能少
  • 過多JOIN
    JOIN原理:用A表的每一條數據掃描B表的全部數據,因此儘可能先過濾再關聯
  • 沒有利用到索引
    索引針對建索引,但並不可能每一列都建索引
    索引並不是越多越好。當數據更新了,索引會進行調整,也會很消耗性能。
    而且MySQL並不會把全部索引都用上,只會根據其算法挑一個索引用。因此建的準很重要
  • 服務器調優及各個參數設置(緩衝、線程數)

2)JOIN查詢

  • SQL執行順序編程

    人工讀取順序:windows

    SELECT (DISTINCT)
        < select_list >
    FROM
        < left_table > < join_type >
    JOIN < right_table > ON < join_condition >
    WHERE
        < where_condition >
    GROUP BY 
        < group_by_list >
    HAVING
        < having_condition>
    ORDER BY
        < order_by_condition >
    LIMIT < limit_number >
    複製代碼

    引擎執行順序:

    FROM < left_table >
    ON < join_condition >
    < join_type > JOIN < right_table >
    WHERE < where_condition >
    GROUP BY < group_by_list >
    HAVING < having_condition >
    SELECT 
    (DISTINCT) < select_list >
    ORDER BY < order_by_condition >
    LIMIT < limit_number >
    複製代碼

總結:

  • 共有/獨有
    有兩個表,員工表Employee和部門表Dept,員工表裏面有Dept字段與部門表的主鍵ID相對應。
    共有:知足employee.deptId = dept.id 的數據 稱爲兩表共有
    獨有:employee.deptId <> dept.id 的數據 稱爲員工表獨有
  • 七種JOIN
    有兩個表,t1 表是員工表 emp,t1 表是部門表 dept

一、 t1 表和 t2 表共有 (inner join)

在這裏插入圖片描述
在這裏插入圖片描述
select * from emp t1 inner join dept t2 on t1.deptId = t2.id
複製代碼

二、t1 表和 t2 表共有 + t1 表獨有 (left join)

在這裏插入圖片描述
在這裏插入圖片描述
select * from emp t1 left join dept t2 on t1.deptId = t2.id
複製代碼

三、t1 表和 t2 表共有 + t2表獨有(right join

在這裏插入圖片描述
在這裏插入圖片描述
select * from emp t1 right join dept t2 on t1.deptId = t2.id
複製代碼

四、 t1 表的獨有(left join…where t2.id is null

在這裏插入圖片描述
在這裏插入圖片描述
select * from emp t1 left join dept t2 on t1.deptId = t2.id where t2.id is null
複製代碼

5.t2 表的獨有(right join…where t1.id is null

在這裏插入圖片描述
在這裏插入圖片描述

6. t1 表和 t2 表全有( union
在這裏插入圖片描述
在這裏插入圖片描述

MySQL中不支持FULL JOIN
UNION: 可去除重複數據
UNION ALL: 不去除重複數據

select * from emp t1 left join dept t2 on t1.deptId = t2.id
union
select * from emp t1 right join dept t2 on t1.deptid = t2.id
複製代碼

七、 t1 表的獨有 + t2 表的獨有(union

在這裏插入圖片描述
在這裏插入圖片描述
select * from emp t1 left join dept t2 on t1.deptId = t2.id where t2.id is null
UNION
select * from emp t1 right join dept t2 on t1.deptId = t2.id 
where t1.deptId is null 
複製代碼

3)索引簡介

MySQL官方對索引的定義爲:索引(Index)是幫助MySQL高效獲取數據的數據結構。能夠獲得索引的本質:索引是數據結構。 目的在於提升查詢效率,能夠類比字典。

  • 簡單理解爲 「排好序的快速查找數據結構」
    在數據以外,數據庫系統還維護着知足特定查找算法的數據結構,這些數據結構以某種方式引用(指向)數據。

    在這裏插入圖片描述
    在這裏插入圖片描述

    左邊是數據表,一共有兩列七條數據,最左邊是數據記錄的物理地址,爲了加快Col2 的查找,能夠維護一個右邊所示的二叉查找樹,每一個節點分別包含索引值和一個指向對應數據記錄物理地址的指針,這樣就能夠運用二叉查找在必定的複雜度內獲取到相應數據,從而快速的檢索出符合條件的記錄。
    二叉樹: 二叉樹極可能會發生兩邊不平衡的狀況。
    B-Tree: 會自動根據兩邊的狀況自動調節,使兩端無限趨近於平衡狀態,可使性能最穩定。可是插入/修改操做過多時,B-TREE會不斷調整平衡,消耗性能。

  • 通常來講索引自己也很大,不可能所有存儲在內存中,所以索引每每以索引文件的形式存儲在磁盤上。

  • 咱們日常所說的索引,若是沒有特別指明,都是指B樹 (多路搜索樹,並不必定是二叉的)結構組織的索引。其中彙集索引,次要索引,覆蓋索引,複合索引,前綴索引,惟一索引默認都是使用B+樹這種類型的索引以外,還有哈希索引(hash index)等。

  • 索引優點

    • 相似圖書館簡歷書目索引,提升數據檢索的效率,下降數據庫的IO成本。
    • 經過索引列對數據進行排序,下降數據排序的成本,下降了CPU的消耗。
  • 索引劣勢

    • 實際上索引也是一張表,該表保存了主鍵與索引字段,並指向實體表的記錄,因此索引列也是要佔用空間的。
    • 雖然索引大大提升了查詢速度,同時卻會下降更新表的速度,如對錶進行INSERT、UPDATE、和DELETE,由於更新表時,MySQL不只要保存數據,還要保存一下索引文件每次更新添加了索引列的字段,都會調整由於更新所帶來的鍵值變化後的索引信息。
    • 索引只是提升效率的一個因素,若是你的MySQL有大量的表,就須要花時間研究創建最優秀的索引,或優化查詢語句
  • 索引結構

    • BTree索引:
      真實數據存在於葉子節點,即三、五、九、十、1三、1五、2八、2九、3六、60、7五、7九、90、99.
      非葉子節點不存儲真實的數據,只存儲指引搜索方向的數據項,如1七、35並不真實存在於數據表中。
      在這裏插入圖片描述
      在這裏插入圖片描述

      【查找過程】
      若是要查找數據29,那麼首先會把磁盤塊1有磁盤加載到內存,此時發生一次IO,在內存中用二分查找肯定29在17和35之間,鎖定磁盤塊1的P2指針,內存時間由於很是短(相比磁盤的IO)能夠忽略不計,經過磁盤塊1的的P2指針的磁盤的磁盤地址把磁盤塊3由磁盤加載到內存,發生第二次IO,29在26和30之間,鎖定磁盤塊3的P2指針,經過指針加載磁盤塊8到內存,發生第三次IO,同時內存中作二分查找到29,結束查詢,總計三次IO
    • B+Tree索引:
      在這裏插入圖片描述
      在這裏插入圖片描述

      B+Tree 第二級的數據並不能直接取出來,只做索引使用。在內存有限的狀況下,查詢效率高於BTree
      BTree第二級能夠直接取出來,樹形結構比較重,在內存無限大到時候有優點。

    【B+Tree 和 BTree 的區別】
    1) 內存有限的狀況下,B+Tree永遠比BTree好,無限內存則反之
    2) B樹的關鍵字和記錄是放在一塊兒的,葉子節點能夠看作外部節點,不包含任何信息;B+樹葉子節點中國你只有關鍵字和指向下一個節點的索引,記錄只放在葉子節點中。(一次查詢可能進行兩次I/O操做)
    3) 在B樹中,越靠近根節點的記錄查找時間越快,只要找到關鍵字便可肯定記錄存在;而B+樹每一個記錄的查找時間基本是同樣的,都須要從根節點走到葉子節點,並且在葉子節點中還要在比較關鍵字。從這個角度看B樹的性能好像會比B+樹好,而在實際應用中倒是B+樹的性能要好些。由於B+樹的非葉子節點不存放實際的數據,這樣每一個節點可容納的元素個數比B數多,樹高比B樹小,這樣帶來的好處是減小磁盤訪問次數。儘管B+樹找到一個記錄所需的比較次數比B樹多可是一次磁盤訪問時間至關於成百上千次內存比較時間,所以實際中B+樹的性能可能還會好寫,並且B+樹的葉子節點使用指針鏈接在一塊兒,方便順序遍歷(例如查看一個目錄下的全部文件,一個表中的全部記錄等)
    4) B+樹的磁盤讀寫代價更低,相對來講IO讀寫次數也就下降了。
    5) B+樹的查詢效率更加穩定。因爲非終結點並非指向文件內容的節點,而只是葉子節點中關鍵字的索引。因此任何關鍵字的查找必須走一條從根節點到葉子節點的路。因此關鍵字查詢的路徑長度相同,致使每個數據的查詢效率至關。

    • 聚簇索引

      在這裏插入圖片描述
      在這裏插入圖片描述

      好處:
      按照聚簇索引排序順序,查詢顯示必定範圍數據的時候,因爲數據都是緊密相連,數據庫不用從多個數據塊中提取數據,因此節省了大量的IO操做。
      限制:

      • 對於MySQL數據庫目前只有InnoDB數據引擎支持聚簇索引,而MyISAM並不支持聚簇索引。
      • 因爲數據物理存儲排序方式只能有一種,因此每一個MySQL的表只能有一個聚簇索引。通常狀況下就是該表的主鍵
    • full-text全文索引

      全文索引(也稱全文檢索)是目前搜索引擎使用的一種關鍵技術。它可以利用分詞技術等多種算法智能分析出文本文字中關鍵詞的頻率和重要性,而後按照必定的算法規則智能地篩選出咱們想要的搜索結果。

      • 查詢:
      # 傳統 LIKE 查詢
      select * from blink t1 where t1.content like '%菜%'

      # 全文檢索
      select * from blink t1 where MATCH(title,content) AGAINST('菜'
      複製代碼
      • 限制: MySQL5.6.4以前只用MyISAM 支持,5.6.4之後 InnoDB才支持,可是官方版不支持中文分詞,須要第三方分詞插件。
    • Hash索引

      • Hash 索引只有Memory,NDB兩種引擎支持,Memory引擎默認支持。
      • Hash索引,若是多個Hash值相同,出現哈希碰撞,那麼索引以鏈表的方式存儲。
      • NoSql採用此索引結構。
    • RTree索引
      R-Tree在MySQL不多使用,僅支持geometry 數據結構,支持該類型的存儲引擎只有MyISAM、bdb、InnoDB、ndb、archive幾種。相對於B-Tree,R-Tree的優點在於查找

  • 索引分類

    • 主鍵索引
      設定爲主鍵後數據庫會自動簡歷索引,InnoDB採用聚簇索引
      語法:
    # 隨表一塊兒建立
    CREATE TABLE emp (
        # 使用AUTO_INCREMENT關鍵字的列必需要有索引
        ID int(10UNSIGNED AUTO_INCREMENT
        , NAME varchar(8)
        , PRIMARY KEY(ID)
     )

    # 單獨建主鍵索引
    ALTER TABLE emp add PRIMARY KEY emp(id);

    # 刪除主鍵索引
    ALTER TABLE emp drop PRIMARY KEY;   # 修改主鍵索引前必須刪除(drop)原索引,再新建(add)索引
    複製代碼
    • 單值索引
      即一個索引只包含單個列,一個表能夠有多個單列索引。
      語法:
    # 隨表一塊兒建立
    CREATE TABLE emp (
        # 使用AUTO_INCREMENT關鍵字的列必需要有索引
        ID int(10UNSIGNED AUTO_INCREMENT
        , EMP_NO varchar(8)
        , NAME varchar(8)
        , KEY(EMP_NO)
     )

    # 單獨建單列索引
    create index idx_emp_no on emp(EMP_NO)

    # 刪除單列索引
    drop index idx_emp_no
    複製代碼
    • 惟一索引
      索引列的值必須惟一,但容許有空值。
      創建惟一索引是必須保證全部的值是惟一的(除了null),如有重複數據,會報錯
    # 隨表一塊兒建立
    CREATE TABLE emp (
        # 使用AUTO_INCREMENT關鍵字的列必需要有索引
        ID int(10UNSIGNED AUTO_INCREMENT
        , EMP_NO varchar(8)
        , NAME varchar(8)
        , UNIQUE(EMP_NO)
     )

    # 單獨建惟一索引
    create unique index idx_emp_no on emp(EMP_NO)

    # 刪除主鍵索引
    drop index idx_emp_no on emp
    複製代碼
    • 複合索引
      在數據庫操做期間,複合索引比單值索引所須要的開銷更小(對於相同的多個列建索引);
      當表的行數遠大於索引列的數目時可使用複合索引。
    # 隨表一塊兒建立
    CREATE TABLE emp (
        # 使用AUTO_INCREMENT關鍵字的列必需要有索引
        ID int(10UNSIGNED AUTO_INCREMENT
        , EMP_NO varchar(8)
        , NAME varchar(8)
        , key(EMP_NO,NAME)
     )
    #創建惟一索引是必須保證全部的值是惟一的(除了null),如有重複數據,會報錯

    # 單獨建惟一索引
    create index idx_no_name on emp(EMP_NO,NAME)

    # 刪除主鍵索引
    drop index idx_no_name on emp
    複製代碼

    【基本語法】

    # 建立
    alter < table_name > add [uniqueindex <index_name> on <column_name>

    # 刪除
    drop index <index_name> on <table_name>

    #查看
    show index from <table_name>

    #使用ALTER命令
    #方式1:該語句添加一個主鍵,這意味着索引值必須是惟一的,且不能爲null
    alter table <table_name> add primary key <column_name>

    #方式2:該語句添加一個惟一索引,值必須是惟一的(null外,null可能會出現不少次)
    alter table <table_name> add unique key <column_name>

    #方式3:該語句添加普通索引,索引值能夠出現不少次
    alter table <table_name> add index <index_name>(column_name)

    #方式4:該語句指定了索引爲FULLTEXT,用戶全文索引
    alter table <table_name> add FULLTEXT <index_name>(column_name)
    複製代碼
  • 哪些狀況須要創建索引

    • 主鍵自動創建惟一索引
    • 頻繁做爲查詢條件的字段應該建立索引(where後面的語句)
    • 查詢中與其餘表關聯的字段,外鍵關係創建索引
    • 單鍵/組合索引的選擇問題(在高併發下傾向建立組合索引)
    • 查詢中排序的字段,排序字段若經過索引去訪問將大大提升排序速度
    • 查詢中統計或者分組字段
  • 哪些狀況不須要創建索引

    • 表記錄太少
    • 常常增刪改的表(由於更新表時,MySQL不只要保存數據,還要保存一下索引文件)
    • where 條件裏用不到的字段不建立索引
    • 數據重複且分佈平均的表字段,所以應該只爲最常常查詢和最常常排序的數據列創建索引。注意,若是某個數據列包含許多重複的內容,爲它創建索引就沒有太大的實際效果。

4)性能分析

  • MySQL常見瓶頸

    • CPU
      SQL中對大量數據進行比較、關聯、排序、分組(最大的壓力在於比較
    • IO
      實例內存知足不了緩存數據或排序等須要,致使產生大量物理IP。查詢執行效率低,掃描過多數據行。

    • 不適宜的鎖的設置,致使線程阻塞,性能降低。死鎖,線程之間交叉調用資源,致使死鎖,程序卡主。

    服務器硬件的性能瓶頸:
    top,free,iostat和vmstat來查看系統的性能狀態

  • Explain的使用

    使用Explain關鍵字能夠模擬優化器執行SQL查詢語句,從而知道MySQL是如何處理你的SQL語句的。分析你的查詢語句或是表結構的性能瓶頸

    • 能夠查看的內容
    1. 表的讀取順序
    2. 哪些索引可使用
    3. 哪些索引被實際使用
    4. 表之間的引用
    5. 每張表有多少行被優化器查詢
    • 怎麼用
      explain + SQL語句
      包含的信息:
    • 各字段解釋

1.【 id】
select查詢的序列號,包含一組數字,表示查詢中執行select字句或操做表的順序。
三種狀況:

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

  • id不一樣,若是是子查詢,id的序號會遞增,id值越大優先級越高,越被先執行

  • id相同和不一樣同時存在

id若是相同,能夠認爲是一組,從上往下順序執行;在全部組中,id值越大,優先級越高,越先執行。
2.【select_type】

  • SIMPLE
    簡單的select查詢,查詢中不包含子查詢或者UNION
  • PRIMARY
    查詢中若包含任何複雜的子部分,最外層查詢則被標記爲Primary
  • DERIVED
    在FROM列表中包含的子查詢被標記爲DERIVED(衍生)MySQL會遞歸執行這些子查詢,把結果放在臨時表裏。
  • SUBQUERY
    在SELECT或WHERE列表中包含了子查詢
  • DEPENDENT SUBQUERY
    在SELECT或WHERE列表中包含了子查詢,子查詢基於外層

    【dependent subquery 和 subquery 的區別】
    依賴子查詢:子查詢結果爲多值
    子查詢:查詢結果爲單值
  • UNCACHEABLE SUBQUERY
    沒法被緩存的子查詢

    @@表示查的是環境參數,沒辦法緩存
  • UNION
    若第二個SELECT出如今UNION以後,則被標記爲UNION;
    若UNION 包含在FROM字句的子查詢中,外層SELECT將被標記爲:DERIVED
  • UNION RESULT
    從UNION表獲取結果的SELECT

3.【table】
顯示這一行的數據是關於哪張表的
4.【type】
type顯示的是訪問類型,是較爲重要的一個指標,結果值從最好到最壞的依次排序:
system > const > eq_ef > ref > range(儘可能保證) > index > ALL
通常來講,得保證查詢至少達到range級別,最好能達到ref

  • system
    表只有一行記錄(等於系統表),這是const類型的特列,平時不會出現,這個也能夠忽略不計
  • const
    表示經過索引一次就找到了,const 用於比較primary key或者 unique索引。由於只匹配一行數據,因此很快將主鍵置於where列表中,MySQL就能將該查詢轉換爲一個常量
  • eq_ref
    惟一性索引掃描,對於每一個索引鍵,表中只有一條記錄與之匹配。常見於主鍵或惟一索引掃描
  • ref
    非惟一性索引掃描,返回匹配某個單獨值的全部行,本質上也是一種索引訪問,它返回全部匹配某個單獨值的行,然而,他可能會找到多個符合條件的行,因此他應該屬於查找和掃描的混合體
  • range
    檢索給定範圍的行,使用一個索引來選擇行。key列顯示使用了哪一個索引,通常就是在你的where語句中出現了between<>in等查詢。這種範圍掃描索引比全表掃描要好,由於它只須要開始於索引的某一個點,而結束於另外一點,不用掃描所有索引。
  • index
    Full Index Scan,index與ALL區別爲index類型只遍歷索引樹。這一般比ALL快,由於索引文件一般比數據文件小。(也就是說雖然all和index都是讀全表的),但index是從索引中讀取的,而all是從硬盤中讀的。
  • all
    Full Table Scan,將遍歷全表以找到匹配的行

5.【possible_keys】
顯示可能應用到這張表中的索引,一個或多個。查詢涉及到的字段上若存在的索引,則該索引將被列出,但不必定被查詢實際使用
6.【key】
實際使用的索引,若是爲NULL,則沒有使用索引。查詢中若使用了覆蓋索引,則該索引和查詢的select字段重疊。
7.【key_len】
表示索引中使用的字節數,可經過該列計算查詢中使用的索引的長度。key_len字段可以幫你檢查是否充分利用上了索引。


計算方式:

動態類型包括:varchar,detail text()截取字符串
本張的表結構以下:

第一組計算爲:
key_len=deptno(int)+null+ename(varchar(20)3+動態=4+1+203+2=67
第二組計算爲:
key_len=deptno(int)+null=4+1=5
8.【ref】
顯示索引的哪一列被使用了,若是可能的話,是一個常數。哪些列或者常量被用於查找索引列上的值

9.【row】
rows列顯示MySQL認爲它執行查詢時必須檢查的行數(越少越好)

10.【Extra】
包含不適合在其餘列中顯示但十分重要的額外信息。

  • Using filesort
    說明mysql會對數據使用一個外部的索引排序,而不是按照表內的索引順序進行讀取。MySQL中沒法利用索引完成的排序操做稱爲「文件排序」。
  • Using temporary
    使用了臨時表保存中間結果,MySQL在對查詢結果排序時使用臨時表。常見於排序order by 和分組查詢 group by。
  • Using index
    表示相應的select操做中使用了覆蓋索引(Covering Index),避免了表的數據行,效率不錯。若是同時出現using where,代表索引被用來執行索引鍵值的查找;若是沒有同時出現using where,代表索引只是用來讀取數據而非利用索引執行查找。
    覆蓋索引:
    一個索引包含了(或覆蓋了)【select子句】與查詢條件【where 子句】中全部須要的字段就叫作覆蓋索引。
    注意: 只取出須要的列,不可select *,不可將全部字段一塊兒作索引
  • Using where
    代表使用了 where 過濾
  • Using join buffer
    使用了鏈接緩存

5)查詢優化

  • 索引的使用
  1. 全值匹配我最愛
    staffs 表創建索引 idx_staffs_nameAgePos,以name,age,pos的順序創建,全值匹配標識按順序匹配。
  2. 最佳左前綴原則
    若是索引了多列,要遵照最左前綴原則,值得是查詢從索引的最左前列開始,而且不跳過索引中的列
    and 忽略左右關係,即便沒有按順序,因爲優化器的存在,會自動優化
  3. 不在索引列上作任何操做(計算、函數、(自動或手動)類型轉換),會致使索引失效而轉向全表掃描。
  4. 存儲引擎不能使用索引中範圍條件右邊的列
    範圍如有索引則能使用到索引,範圍條件右邊的索引會失效(範圍條件右邊與範圍條件使用的同一個組合索引,右邊的纔會失效,如果不一樣索引則不會失效)
  5. **儘可能使用覆蓋索引(只訪問索引的查詢(索引列和查詢列一致)),減小select ***
  6. MySQL在使用不等於(!= 或 <>)的時候沒法使用索引,會致使全表掃描。
    where age != 10 and name = 'xxx' 這種狀況下,mysql會自動優化將 name = 'xxx' 放在 age != 10 以前,name依然能使用索引,只是age的索引失效
  7. is not null 也沒法使用索引,可是 is null 是可使用索引
  8. like 以通配符開頭('%xxx')索引失效變成全表掃描
    like '%xxx':type 類型會變成all
    like 'xxx%':type 類型爲range,算是範圍,可使用索引
  9. 字符串不加單引號索引失效
    底層進行類型轉換時索引失效,使用了函數形成了索引失效

10.少用or,用它鏈接時索引會失效

【例子小節】
此時複合索引index(a,b,c)

【使用建議】

  1. 對於單鍵索引,儘可能選擇針對當前query過濾性更好的索引
  2. 在選擇組合索引的時候,當前query中過濾性最好的字段在索引字段順序中,位置越靠前越好。(避免索引過濾性好的索引失效)
  3. 在選擇組合索引的時候,儘可能選擇能夠可以包含當前query中where字句中更多字段的索引
  4. 儘量經過分析統計信息和調整query的寫法來達到選擇合適索引的目的
  • 關聯查詢優化
    一、保證被驅動表的join字段已經被索引(join後的表爲驅動表)
    二、left join時,選擇小表做爲驅動表,大表做爲被驅動表(left join必定是左邊是驅動表,右邊是被驅動表)
    三、inner join時,MySQL會本身幫你把小結果集選爲驅動表。由於驅動表不管如何都會被全表掃描,因此掃描次數越少越好。
    四、子查詢儘可能不要放在被驅動表,有可能使用不到索引。
# 未加索引,type爲ALL
explain select * from class left join book on class.card = book.card
# 添加索引優化,第二行的type變成了ref
alter table book add index idx_card_B(card);
# 這是由左鏈接特效決定的,left join條件用於肯定如何從右表搜索行,左邊必定都有
# 繼續優化,刪除舊索引,新建新索引
drop index idx_card_B on book;
alter table class add index idx_card_A(card)
複製代碼
  • 子查詢優化
    一、 有索引的狀況下用 inner join 是最好的,其次是 in,exists最糟糕
    二、 無索引的狀況下用小表驅動大表,由於 join 方式須要 distinct ,沒有索引distinct 消耗性能比較大,因此 exists 性能最佳,其次 in 其次,join性能最差
    三、 無索引的狀況下大表驅動小表,in和exists的性能應該是接近的,都比較糟糕,exists稍微好一點,可是超不過5%
  • order by關鍵字優化
    儘可能使用Index方式排序,避免使用FileSort 方式排序。MySQL中支持兩種方式的排序,FileSortIndex,其中index效率高,它指Mysql掃描索引自己完成排序,FileSort方式效率比較低。知足三種狀況會使用Index排序。
  • Order By語句使用索引最左前列
  • 使用where子句與order by子句條件列組合知足索引最左前列
  • where子句中若是出現索引的範圍查詢(即explain中出現range)會致使order by索引失效。

例子:talA 表中有索引 (age,birth,name)


  • 分頁查詢的優化--limit
explain select sql_no_chache  * from emp order by deptno limit 10000,40
複製代碼
#加上索引
create index emp on emp(deptno)
複製代碼
# 經過以上結果能夠看出加上索引並不能改變
# 進一步優化:先利用覆蓋索引把要取的數據行的主鍵取到,而後再用這個主鍵列與數據表作關聯(查詢數據量小了後)
explain select sql_no_cache * from emp e inner join (select id from emp e order by deptno limit 10000,40)a on a.id = e.id 
複製代碼
  • GROUP BY 關鍵字優化
    一、group by實質上是先排序後進行分組,遵守索引建的最佳左前綴
    二、當沒法使用索引列,增大max_length_for_sort_data參數的設置+增大sort_buffer_size參數的設置
    三、where高於having,能寫在where限定的條件就不要去having限定了。
  • 去重優化
    儘可能不要使用distinct關鍵字去重
    例子:
# 使用distinct關鍵字去重消耗性能
select distinct BOOK_NAME from book where id in(1,2,5,4,8)
# 使用 group by可以利用到索引
select BOOK_NAME from book where id in(1,2,5,4,8group by BOOK_NAME
複製代碼
看完不讚,都是壞蛋
看完不讚,都是壞蛋

本文較長,能看到這裏的都是最棒的!成長之路學無止境~
今天的你多努力一點,明天的你就能少說一句求人的話!
好久好久以前,有個傳說,聽說:
看完不讚,都是壞蛋

相關文章
相關標籤/搜索