主頁 > 資料庫 > 🍖索引原理與慢查詢優化

🍖索引原理與慢查詢優化

2021-02-26 07:12:22 資料庫

引入

本篇博客偏理論, 將會介紹以下知識:

  • 索引介紹
  • 索引原理
  • 索引的資料結構(二叉樹--->平衡二叉樹--->B樹--->B+樹)
  • 聚集索引與輔助索引
  • MySQL索引管理
  • 創建和洗掉索引的語法
  • 創建索引后的測驗 (查詢速度的變化)
  • 如何正確使用索引
  • 回表
  • 覆寫索引
  • 聯合索引
  • 最左前綴匹配
  • 索引下推
  • MySQL查詢優化 : explain
  • 慢查詢優化的基本步驟
  • 慢日志管理

一.索引介紹

1.什么是索引

  • 索引是對資料庫表中一列或多列的值進行排序的一種資料結構, 使用索引可以快速訪問資料庫表中的特定資訊
  • 為資料庫建立索引, 就好比為書建立目錄

2.為什么要有索引

  • 優化資料查詢效率

資料庫的資料一般存盤在磁盤中, 相比較記憶體, 磁盤的訪問速度較慢索引就是可以幫助資料庫快速從磁盤中找到資料的一種資料結構

  • 注意 : 創建索引后會降低增、刪、改的效率

雖然會降低, 但是一般的應用系統,讀寫比例在10:1左右,而且插入操作和一般的更新操作很少出現性能問題,遇到最多的,也是最容易出問題的,還是一些復雜的查詢操作,所以查詢陳述句的優化顯然是重中之重

3.為表創建的索引是不是越多越好?

  • 多數情況下, 我們知道索引能夠提高查詢效率, 但過多也會影回應用程式效率, 怎么加才是關鍵
  • 一個應用程式的設計, 資料上過多或過少的索引都會引發應用程式的效率問題, 所以我們需要找到一個平衡點
  • 當表有大量資料的情況下, 創建索引的速度會很慢, 并且對于寫的性能也會大幅度降低

4.索引應該什么時候加才最合適

  • 任何一個軟體都有其吸參考戶的亮點, 亮點背后對應的是熱資料, 無疑開發人員對熱資料的所對應的資料庫欄位有哪些, 應該在開發軟體的程序中就提前為相應的欄位加上索引, 而不是等軟體上線后讓DBA發現慢查詢sql后再做處理

原因 :

1.一個軟體慢會影響用戶體驗, 但是慢的原因有很多, 你不能立即確定就是 SQL 的問題, 當你定位到 SQL 問題的時候就已經過去很久了, 問題沒有得到及時的解決

2.大多數DBA都是管理型DBA而非開發型, 所以即便是DBA從日志中看到了慢查詢sql, 也會因為其不懂業務而很難分析出慢的原因

二.索引原理

1.索引的原理

  • 通過不斷的縮小想要查詢的資料范圍篩選出最終的結果

就比如買火車票(無索引) : 如果沒有12360火車票訂購軟體, 擺在我們面前的就是成千上萬輛火車, 選擇那一輛的條件有火車型別、出發和終點、時間等等, 我們需要一輛一輛火車去比對自己的篩選條件, 運氣好第一輛就是要找的火車, 運氣不好第一千輛才是要找的火車

加入索引 : 現在我們只需要在12360軟體上選擇高鐵, 就能篩選掉不是高鐵的火車, 縮小了查詢范圍; 再輸入出發點和終點, 又縮小了查詢范圍; 再輸入時間, 范圍又減少, 最終找到自己需要的車次, 由不固定查詢次數變成很小的固定查詢次數

2.磁盤I/O與預讀

  • I\O延遲

IO延遲 = 平均尋道時間 + 平均延遲時間(一般為9ms)--->例子:假設當前硬碟轉軸(盤片)轉速是7200/min,也就是120/s,那么轉一圈需要花費1/120≈8ms,半圈也就是4ms(假設找到資料要半圈)

9ms左右對于我們來講很短, 但對于一臺500-MIPS的機器來說每秒可以執行5億條指令, 換句話說執行一次IO的時間可以執行40萬條指令,資料庫動輒十萬百萬乃至千萬級資料,每次9毫秒的時間, 這簡直是場災難

  • 預讀

考慮到磁盤IO是非常高昂的操作,計算機作業系統做了一些優化,當一次IO時,不光把當前磁盤地址的資料,而是把相鄰的資料也都讀取到記憶體緩沖區內,因為區域預讀性原理告訴我們,當計算機訪問一個地址的資料的時候,與其相鄰的資料也會很快被訪問到,每一次IO讀取的資料我們稱之為一頁(page),具體一頁有多大資料跟作業系統有關,一般為4k或8k,也就是我們讀取一頁內的資料時候,實際上才發生了一次IO,這個理論對于索引的資料結構設計非常有幫助

三.索引的資料結構

索引的資料結構是 B+樹, 而 B+樹 是經過 二叉排序樹 到 二叉平衡樹 再到 B樹 最后到 B+樹 演變過來的, 下面簡單介紹一下:

1.二叉排序樹(二叉查找樹)

  • 頂端的節點我們稱為根節點,沒有子節點的節點我們稱之為葉節點(就是最下面一排)

對于一列數字 : 5、6、7、8、9、10

image-20210224174432982

  • 如果我們需要找到 key=9 的節點, 先將 9 與根節點比較, 大于根節點, 于是往右邊找; 繼續與右邊的 10 比較, 小于, 于是往左邊找, 正好找到九

利用二叉排序樹我們只需要3次即可找到匹配的資料; 如果在數字列中一條條的查找的話,我們需要5次才能找到

2.平衡二叉樹(AVL樹)

  • 平衡二叉樹可以說是二叉排序樹的改進版, 是特殊的二叉排序樹

上面我們講解了利用二叉排序樹可以快速的找到資料; 但是,如果上面的二叉排序樹是這樣的構造:

image-20210224175721158

平均查找長度是3, 如果我們調整一下關鍵字的序列

image-20210224180204999

調整之后平均查找長度是 2.2, 從上面我們可以看出平均查找長度與數的高度有關, 平均查找長度越小, 查找速度就越快, 所以我們應該盡可能的讓這棵樹矮

  • 怎么判斷一顆二叉樹是否是平衡二叉樹?

這里引入了平衡因子的概念, 左子樹的高度減右子數的高度就是平衡因子, 平衡因子的絕對值小于或等于一就是平衡二叉樹, 大于一就是非平衡二叉樹, 如下圖平衡因子為 4 就是非平衡二叉樹

image-20210224181012776

我們調整一下關鍵字序列, 各子數平衡因子絕對值都小于或等于 1, 那么這就是一顆平衡二叉樹

image-20210224181425555

3.B 樹 ( Balanced Tree)多路平衡查找樹

  • 我們知道平衡二叉樹每個節點只能存盤一個鍵值和資料

如果我們要存盤海量的資料呢?可以想象到二叉樹的節點將會非常多,高度也會及其高,我們查找資料時也會進行很多次磁盤IO,我們查找資料的效率將會極低

  • 為了解決平衡二叉樹的這個弊端,我們應該尋找一種單個節點可以存盤多個鍵值和資料的平衡樹, 也就是 B樹

img

從上圖可以看出,B樹相對于平衡二叉樹,每個節點(B樹中節點稱之為頁)存盤了更多的鍵值(key)和資料(data),并且每個節點擁有更多的子節點,子節點的個數一般稱為階,上述圖中的B樹為3階B樹,高度也會很低, 基于這個特性,B樹查找資料讀取磁盤的次數將會很少,資料的查找效率也會比平衡二叉樹高很多

假設每個節點可以儲存兩個值(不代表只能存兩個), 我們找到75:

  • 先與 頁1 比較,在 35 右邊找到 p3指標 定位到 頁4
  • 與 頁4 中的索引對比, 在 65-87 之間, 找到指標 p2, 定位到 頁10
  • 與 頁10 中的索引對比, 找到相對應的 75

4.B+ 樹

  • B+ 樹是對 B樹的進一步優化

img

  • 通過上圖我們來對比下 B+ 樹與 B樹的不同:
  • B+ 樹非葉子節點上是不存盤資料的,僅存盤鍵值,而 B 樹節點中不僅存盤鍵值,也會存盤資料

  • 之所以這么做是因為在資料庫中頁的大小是固定的,InnoDB 中頁的默認大小是 16KB,如果不存盤資料,那么就會存盤更多的鍵值,相應的樹的階數(節點的子節點樹)就會更大,樹就會更矮更胖,如此一來我們查找資料進行磁盤的 IO 次數又會再次減少,資料查詢的效率也會更快

  • B+ 樹的階數是等于鍵值的數量的,如果我們的 B+ 樹一個節點可以存盤 1000 個鍵值,那么 3 層 B+ 樹可以存盤 1000×1000×1000=10 億個資料,

  • 一般根節點是常駐記憶體的,所以一般我們查找 10 億資料,只需要 2 次磁盤 IO

  • 3層的b+樹可以表示上百萬的資料,如果上百萬的資料查找只需要兩次IO,性能提高將是巨大的,如果沒有索引,每個資料項都要發生一次IO,那么總共需要百萬次的IO,顯然成本非常非常高

  • B+ 樹的兩種性質
  • 索引欄位要盡量的小 : 磁盤塊的大小也就是一個資料頁的大小,是固定的. 如果資料項占的空間越小,資料項的數量越多,樹的高度就越低, 查詢過的IO次數就越少. 這就是為什么每個資料項,即索引欄位要盡量的小,比如int占4位元組,要比bigint8位元組少一半,這也是為什么b+樹要求把真實的資料放到葉子節點而不是內層節點,一旦放到內層節點,磁盤塊的資料項會大幅度下降, 下降則會導致每層可存盤的資料就少, 因為磁盤塊是固定的, 從而要增加層次, 進而導致樹增高, 樹增高意味著找到底層資料的IO次數增多, 導致查詢速度大幅度下降
  • 索引的最左匹配特性 : 當b+樹的資料項是復合的資料結構,比如(name,age,sex)的時候,b+數是按照從左到右的順序來建立搜索樹的. 比如當(張三,20,F)這樣的資料來檢索的時候,b+樹會優先比較name來確定下一步的所搜方向,如果name相同再依次比較age和sex,最后得到檢索的資料. 但當(20,F)這樣的沒有name的資料來的時候,b+樹就不知道下一步該查哪個節點,因為建立搜索樹的時候name就是第一個比較因子,必須要先根據name來搜索才能知道下一步去哪里查詢, 比如當(張三,F)這樣的資料來檢索時,b+樹可以用name來指定搜索方向,但下一個欄位age的缺失,所以只能把名字等于張三的資料都找到,然后再匹配性別是F的資料了, 這個是非常重要的性質,即索引的最左匹配特性

5.總結 B+ 樹優點

  • 在二叉樹、平衡二叉樹、B樹的基礎上做了進一步優化, 只有葉子節點放真正的資料,這意味著在等量資料的前提下,B+樹的高度是最低的
  • B+的葉子節點都是排好序的,這意味著在范圍查詢上,B+樹比B樹更快,快就快在一旦找到一個樹葉節點,就不需要在再從樹根查起了

四.聚集索引與輔助索引

資料庫中的 B+樹 索引可以分為聚集索引(clustered index)和輔助索引(secondary index), 聚集索引與輔助索引相同的是:不管是聚集索引還是輔助索引,其內部都是B+樹的形式,即高度是平衡的, 不同的是 :

聚集索引的葉子節點存放的是一整行完整的資訊, 而輔助索引的葉子節點存放的并非完整資訊(下面介紹)

1.聚集索引 (Clustered Index)

InnoDB 聚集索引的葉子節點存盤行記錄,因此 InnoDB 必須要有且只有一個聚集索引

  • 如果表定義了 PK (Primary Key,主鍵),那么 PK 就是聚集索引

  • 如果表沒有定義 PK,則第一個不為空且唯一(NOT NULL UNIQUE) 的列就是聚集索引

  • 否則 InnoDB 會另外創建一個隱藏的 ROWID 作為聚集索引

由于這種機制是直接定位行記錄,因此使得基于 PK 的查詢速度非常快

2.輔助索引( Secondary Index )

表中除了聚集索引外其他索引都是輔助索引(Secondary Index,也稱為非聚集索引)

  • 與聚集索引的區別是:輔助索引的葉子節點不包含行記錄的全部資料,葉子節點除了包含鍵值以外,每個葉子節點中的索引行中還包含一個書簽(bookmark),該書簽用來告訴InnoDB存盤引擎去哪里可以找到與索引相對應的行資料

  • 輔助索引的存在并不影響資料在聚集索引中的組織,因此每張表上可以有多個輔助索引,但只能有一個聚集索引

  • 當通過輔助索引來尋找資料時,InnoDB存盤引擎會遍歷輔助索引并通過葉子級別的指標獲得指向主鍵索引的主鍵,然后再通過主鍵索引來找到一個完整的行記錄

五.Mysql 索引管理

1.功能

  • 索引的功能就是加速查找
  • mysql中的primary key,unique,聯合唯一也都是索引,這些索引除了加速查找以外,還有約束的功能

2.mysql 中常用的索引(鍵)

  • 普通索引: index 加速查找
  • 唯一索引:
    • 主鍵索引: primary key 加速查找+約束
    • 唯一索引: unique key 加速查找+約束
  • 聯合索引:
    • 聯合主鍵索引: primary key
    • 聯合唯一索引: unique(欄位1, 欄位2, ...)
    • 聯合普通索引: unique(欄位1, 欄位2, ...)

上面的三種索引, 唯一索引除了可以增加查詢速度之外各自還具有約束條件, 而普通索引index key沒有任何的約束條件,只是用來幫助你加快速查詢資料

注意:聯合索引不是用來加速查詢用的,不在我們的而研究范圍之內

3.索引的兩大型別

  • 我們可以在創建索引的時候, 為其指定索引型別(兩類)
hash型別的索引:查詢單條快,范圍查詢慢
btree型別的索引:b+樹,層數越多,資料量指數級增長(我們就用它,因為innodb默認支持它)
  • 不同的存盤引擎支持的索引型別也不一樣
InnoDB 支持事務,支持行級別鎖定,支持 B-tree、Full-text 等索引,不支持 Hash 索引
MyISAM 不支持事務,支持表級別鎖定,支持 B-tree、Full-text 等索引,不支持 Hash 索引
Memory 不支持事務,支持表級別鎖定,支持 B-tree、Hash 等索引,不支持 Full-text 索引
NDB 支持事務,支持行級別鎖定,支持 Hash 索引,不支持 B-tree、Full-text 等索引
Archive 不支持事務,支持表級別鎖定,不支持 B-tree、Hash、Full-text 等索引

六.創建和洗掉索引語法

1.創建的三種方法

  • 語法
??方式一 : 創建表時建索引
create table [表名] (
    [unique|fulltext|spatial] [index|key] [索引名] [欄位名(長度)] [asc|desc]
    );
    
??方式二 : 在已存在的表上創建
create [unique|fulltext|spatial] index [索引名]
    on [表名] [欄位名(長度)] [asc|desc];

??方式二 : alter 在已存在的表上創建索引
alter table [表名] add [unique|fulltext|spatial] index 
    [索引名] [欄位名(長度)] [asc|desc];
  • 示例代碼
??方式一
create table t01(
    id int,
    name char(10),
    age int,
    sex enum("male","female"),
    unique key unique_id(id),
    index index_name(name)  # index沒有key
);

??方式二
create index index_age on t01(age);

??方式三
alter table t01 add index index_sex(sex);

2.洗掉索引

drop index [索引名] on t01;    # 語法
drop index index_age on t01;  # 示例

七.索引測驗

1.先準備一張表, 并插入大量的資料

??創建表
create table t01(
    id int,
    name varchar(10),
    sex enum("male","female"),
    email varchar(18)
);

??創建存盤程序,進行自動插入記錄
delimiter %%%
create procedure p01()
begin
    declare i int default 1;
    while(i<3000000)do
        insert t01 value(i,"shawn","male",concat("shawn",i,"@163.com"));
        set i=i+1;
    end while;
end %%%
delimiter ;

??查看存盤程序
show create procedure p01\G  # \G 垂直顯示結果

??呼叫存盤程序
call p01();  # windows執行測驗大概一個半小時,3百萬條記錄,200多M

??洗掉存盤程序
drop procedure p01;

image-20210225095534649

2.沒有建立索引的情況下測驗查詢速度

select * from t01 where id=3000000;

沒有索引,mysql不知道有沒有這條記錄, 所以從頭到尾的對記錄進行遍歷,有多少磁盤塊就要進行多少I\O,速度很慢

image-20210225095645650

3.為表的某個欄位建立索引(表已經存在大量記錄,創建速度會很慢)

create index index_id on t01(id);  # 為 id 欄位建立普通索引

觀察 data 檔案夾下的 t01 表資料檔案大小增加了

image-20210225100323340

image-20210225110724526

4.使用建立了索引的欄位設定為條件進行查詢

select * from t01 where id=3000000;  # 可以觀察到速度明顯的提升

image-20210225101246174

5.步驟分析

  • mysql先去索引表里根據 b+樹 的搜索原理很快搜索到 id 等于3000000的記錄,直接命中索引, IO大大降低,因而速度明顯提升

  • 我們以沒有建立索引的欄位設定為條件來進行查詢, 可以發現速度依然很慢

    select * from t01 email="[email protected]";  # 并且記錄越大查詢越慢
    

    image-20210225110358350

  • 對 email 欄位建立索引試試

create index index_email on t01(email);  # 欄位資料越大,建立的時間越長(所以建議不要使用資料很大的欄位建立索引,這里只是做實驗)
select * from t01 where email="[email protected]";  # 再去查詢,可以發現速度是數量級的提升

image-20210225111132774

八.正確使用索引

并不是說創建了索引就一定能加速查詢, 有些情況就算命中了索引也未必能起到很好的提速效果, 下面來測驗一下各種情況 (如果不想看程序,可以直接看小結末尾的結論)

1.范圍查詢情況 : 或者說條件不明確, 條件中有 : >、>=、<、<=、!= 、between...and...、like

  • 大小于 : >、<

image-20210225145700684

  • 不等于 : !=

image-20210225145844390

  • between...and...

image-20210225150055303

  • 模糊匹配 : like

like

2.區分度情況 : 區分度表示欄位不重復的比例, 區分度越大, 掃描的速度就越快,像主鍵唯一, 而性別欄位區分度就很低

image-20210225153807708

出現上面的情況就是因為欄位的區分度太低, 在 B+樹 中對于這些欄位無法比較大小, 因為值都是相等的, 毫無疑問,只能增加樹的高度來保證這些資料的存盤, 樹的高度越高, 查詢速度就越慢

3.=和in可以亂序,比如a = 1 and b = 2 and c = 3 建立(a,b,c)索引可以任意順序,mysql的查詢優化器會幫你優化成索引可以識別的形式

4.索引列不要參與計算或者函式, 比如薪資乘與12 : 不要使用欄位相乘(salary*12=10000), 可以使用該欄位所對應的值相乘(salary=10000*12)

image-20210225155533918

5.索引下推技術

??"and"與"or"的邏輯
    [條件1] and [條件2] : 所有條件都成立才算成立,但凡要有一個條件不成立則最終結果不成立
    [條件1] or [條件2] : 只要有一個條件成立則最終結果就成立

??"and"的作業原理
    條件:        
        a = 10 and b = 'xxx' and c > 3 and d =4    
    索引:        
        制作聯合索引(d,a,b,c)    
    作業原理:        
        對于連續多個and:mysql會按照聯合索引,從左到右的順序找一個區分度高的索引欄位(這樣便可以快速鎖定很小的范圍),加速查詢,即按照d—>a->b->c的順序

??"or"的作業牌原理
    條件:        
        a = 10 or b = 'xxx' or c > 3 or d =4    
    索引:        
        制作聯合索引(d,a,b,c)            
    作業原理:        
        對于連續多個or:mysql會按照條件的順序,從左到右依次判斷,即a->b->c->d

6.最左前綴匹配原則

7.總結 (怎么建立索引能提高查詢效率)

  • 對區分度高并且占用空間小的欄位建立索引
  • 針對范圍查詢命中了索引,如果范圍很大,查詢效率依然很低,如何解決
    • 要么把范圍縮小
    • 要么就分段取值,一段一段取最終把大范圍給取完
  • 不要把查詢欄位放到函式或者參與運算
  • 索引下推技術,mysql自動選擇查詢速度最優的那條陳述句 (默認是開啟)
  • 索引覆寫 (下面介紹)
  • 最左前綴匹配原則 (下面介紹)

8.其他注意事項

  • 避免使用select *
  • count(1)或count(列) 代替 count(*)
  • 創建表時盡量時 char 代替 varchar
  • 表的欄位順序固定長度的欄位優先
  • 組合索引代替多個單列索引(經常使用多個條件查詢時)
  • 盡量使用短索引
  • 使用連接(JOIN)來代替子查詢(Sub-Queries)
  • 連表時注意條件型別需一致
  • 索引散列值(重復少)不適合建索引,例:性別不適合

九.回表、覆寫索引、聯合索引、最左前綴

匹配原則、索引下推

1.創建一張表, 并插入記錄

create table user(
    -> id int not null auto_increment,
    -> name char(16) not null,
    -> age int not null,
    -> primary key(id),            # id 為主鍵并設定索引(聚集索引)
    -> index index_name(name));    # name 欄位設定索引(輔助索引)

insert user(name,age) value
    -> ("shawn",23),
    -> ("song",22),
    -> ("hai",20),
    -> ("xing",18),
    -> ("yanxi",45),
    -> ("zichen",25);

image-20210225170144065

2.回表

select * from user where id=2;

上面為主鍵查詢方式, 即通過聚集索引, 能找到 id 為 2 的完整記錄

select * from user where name="song";

上面為輔助索引查詢方式, 則需要先搜索 name 索引樹,得到 song 對應的 id 值為 2,再到 id 索引樹搜索一次, 這個程序稱為回表

  • 結論 : 所以基于輔助索引的查詢需要多掃描一棵索引樹,因此,我們在應用中應該盡量使用聚集索引

3.覆寫索引

select id from user where name="hai";

上面陳述句查詢的條件是 name 欄位, name 欄位有索引樹, 并且上面保存有 name 和 id 的值, 可以直接提供查詢結果, 不需要進行回表操作, 也就是說, 在這個查詢里面, 索引 name 已經覆寫了我們所要查詢的 id 欄位需求, 這就稱為覆寫索引

select age from user where name="xing";

上面陳述句通過 name 索引樹找到 name 欄位對應的 "xing" 和 id 值, 但沒有 age 欄位資訊, 于是通過 id 欄位進行回表操作查找到滿足條件的資料

  • 回表操作無疑是降低效率的, 我們可以再為 age 建立索引, 避免索引太多可能引起的效率問題, 也可以為其建立聯合索引

4.聯合索引、最左匹配原則

??聯合索引是指對表上的多個列合起來做一個索引. 聯合索引的創建方法與單個索引的創建方法一樣,不同之處在僅在于有多個索引列

??最左前綴匹配原則, 是非常重要的原則, mysql會從左到右進行匹配

  • 先洗掉 name 欄位的索引, 再與 age 一起建立聯合索引
drop index index_name on user;
create index index_name_age on user(name,age);  # 實際應用中應該把最常用的欄位放在最左邊
  • 當查詢條件中出現以下欄位,可以命中聯合索引,因為符合最左前綴原則
select name,age from user where name="song";  # 條件欄位 name
select name,age from user where name="song" and age>18;  # 條件欄位 name + age
  • 查詢條件中只出現一個 age 欄位,不能命中聯合索引
select name,age from user where age=2;  # 條件欄位 age (不會走聯合索引)

5.索引下推 (mysql自動開啟)

索引下推(index condition pushdown )簡稱ICP,在Mysql5.6的版本上推出,用于優化查詢

使用最左前綴匹配原則 + 聯合查詢可以加快查詢速度, 如果我們的條件存在范圍查詢, 那么 SQL 陳述句是怎么運行的呢?

select * from user where name like "s%" and age=22; 

image-20210225180632714

如上表的記錄, "s" 開頭的記錄有兩條

  • Mysql 5.6 以前 沒有索引遞推這個優化
Innodb 會忽略 age 這個欄位, 直接通過 name 來進行查詢, 在(name,age)這個聯合索引上找到兩條結果, 然后拿到 id 為 1 和 2 進行"兩次回表查詢"
  • Mysql 5.6 及以后 添加了索引下推這個優化
Innodb 不會忽略 age 這個欄位, 而是在索引內部就判斷了 age 是否等于 22, 不等于 22 的記錄直接跳過
因此在(name,age)這個聯合索引上只匹配到一個記錄, 此時拿著這一個 id 去回表到所有的資料只需要"回表一次"

十.MySQL查詢優化 : explain

官方檔案 : https://dev.mysql.com/doc/refman/8.0/en/explain-output.html

ps : 強調 rows 是核心指標,絕大部分 rows 小的陳述句執行一定很快,所以優化陳述句基本上都是在優化rows

1.explain 是什么

explain 簡稱查看執行計劃,使用 explain 關鍵字可以模擬優化器執行SQL查詢陳述句,從而知道MySQL 是如何處理 SQL 陳述句的

2.explain 如何使用

語法 : explain + [SQL陳述句]

3.explain 的作用

  • 表的讀取順序
  • 資料讀取操作的操作型別
  • 哪些索引可以使用
  • 哪些索引實際使用
  • 表之間的參考
  • 每張表有多少行被優化器查詢

4.執行計劃表包含的欄位資訊

explain select * from t01;

image-20210225183254836

5.計劃表欄位說明

  • id 欄位
欄位 說明
id MySQL Query Optimizer 選定的執行計劃中查詢的序列號,表示查詢中執行 select 子句或操作表的順序,id值越大優先級越高,越先被執行; 若id 相同,執行順序由上至下
  • select_type 欄位
select_type 查詢型別 說明
SIMPLE 簡單的 select 查詢,不使用 union 及子查詢
PRIMARY 最外層的 select 查詢
UNION UNION 中的第二個或隨后的 select 查詢,不 依賴于外部查詢的結果集
DEPENDENT UNION UNION 中的第二個或隨后的 select 查詢,依 賴于外部查詢的結果集
SUBQUERY 子查詢中的第一個 select 查詢,不依賴于外 部查詢的結果集
DEPENDENT SUBQUERY 子查詢中的第一個 select 查詢,依賴于外部 查詢的結果集
DERIVED 用于 from 子句里有子查詢的情況, MySQL 會 遞回執行這些子查詢, 把結果放在臨時表里
UNCACHEABLE SUBQUERY 結果集不能被快取的子查詢,必須重新為外 層查詢的每一行進行評估
UNCACHEABLE UNION UNION 中的第二個或隨后的 select 查詢,屬 于不可快取的子查詢
  • table 欄位
欄位 說明
table 輸出行所參考的表
  • type 欄位

非常重要的項, 顯示連接使用的型別, 按最優到最差的型別排序

type : 連接型別 說明
system 表僅有一行(=系統表),這是 const 連接型別的一個特例
const const 用于用常數值比較 PRIMARY KEY 時,當 查詢的表僅有一行時,使用 System
eq_ref const 用于用常數值比較 PRIMARY KEY 時,當 查詢的表僅有一行時,使用 System
ref 連接不能基于關鍵字選擇單個行,可能查找 到多個符合條件的行, 叫做 ref 是因為索引要 跟某個參考值相比較,這個參考值或者是一 個常數,或者是來自一個表里的多表查詢的 結果值
ref_or_null 如同 ref, 但是 MySQL 必須在初次查找的結果 里找出 null 條目,然后進行二次查找,
index_merge 說明索引合并優化被使用了
unique_subquery 在某些 IN 查詢中使用此種型別,而不是常規的 ref:value IN (SELECT primary_key FROM single_table WHERE some_expr)
index_subquery 在 某 些 IN 查 詢 中 使 用 此 種 類 型 , 與 unique_subquery 類似,但是查詢的是非唯一 性索引: value IN (SELECT key_column FROM single_table WHERE some_expr)
range 只檢索給定范圍的行,使用一個索引來選擇 行,key 列顯示使用了哪個索引,當使用=、 <>、>、>=、<、<=、IS NULL、<=>、BETWEEN 或者 IN 運算子,用常量比較關鍵字列時,可 以使用 range
index 全表掃描,只是掃描表的時候按照索引次序 進行而不是行,主要優點就是避免了排序, 但是開銷仍然非常大
all 最壞的情況,從頭到尾全表掃描
  • possible_keys 欄位
欄位 說明
possible_keys 指出 MySQL 能在該表中使用哪些索引有助于 查詢,如果為空,說明沒有可用的索引
  • key 欄位
欄位 說明
key MySQL 實際從 possible_key 選擇使用的索引, 如果為 NULL,則沒有使用索引,很少的情況 下,MYSQL 會選擇優化不足的索引,這種情 況下,可以在 SELECT 陳述句中使用 USE INDEX (indexname)來強制使用一個索引或者用 IGNORE INDEX(indexname)來強制 MYSQL 忽略索引
  • key_len 欄位
欄位 說明
key_len 使用的索引的長度,在不損失精確性的情況 下,長度越短越好,
  • ref 欄位
欄位 說明
ref 顯示索引的哪一列被使用了
  • rows 欄位
欄位 說明
rows MYSQL 認為必須檢查的用來回傳請求資料的行數
  • Extra 欄位
extra 項 說明
Using filesort 表示 MySQL 會對結果使用一個外部索引排序,而不是從表里按索引次序讀到相關內容,可能在記憶體或者磁盤上進行排序,MySQL 中無法利用索引完成的排序操作稱為“檔案排序”
Using temporary 表示 MySQL 在對查詢結果排序時使用臨時表,常見于排序 order by 和分組查詢 group by

6.示例

explain select * from t01 where id=100000;
explain select * from t01 where id>10000 and id<20000;
explain select * from t01 where id>20000;

image-20210225185120221

十一.慢查詢優化的基本步驟

  • 先運行看看是否真的很慢,注意設定SQL_NO_CACHE
  • where條件單表查,鎖定最小回傳記錄表,這句話的意思是把查詢陳述句的where都應用到表中回傳的記錄數最小的表開始查起,單表每個欄位分別查詢,看哪個欄位的區分度最高
  • explain查看執行計劃,是否與1預期一致(從鎖定記錄較少的表開始查詢)
  • order by limit 形式的sql陳述句讓排序的表優先查
  • 了解業務方使用場景
  • 加索引時參照建索引的幾大原則
  • 觀察結果,不符合預期繼續從第一個步驟開始分析

十二.慢日志管理

慢日志管理 : https://www.cnblogs.com/songhaixing/p/14448814.html

轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/263695.html

標籤:MySQL

上一篇:直播資料分析,薇婭直播間單場爆賣7萬瓶,六年六輪融資,元氣森林憑什么“吊打”同行?

下一篇:[20210224]fetch r=0算邏輯讀嗎.txt

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • GPU虛擬機創建時間深度優化

    **?桔妹導讀:**GPU虛擬機實體創建速度慢是公有云面臨的普遍問題,由于通常情況下創建虛擬機屬于低頻操作而未引起業界的重視,實際生產中還是存在對GPU實體創建時間有苛刻要求的業務場景。本文將介紹滴滴云在解決該問題時的思路、方法、并展示最終的優化成果。 從公有云服務商那里購買過虛擬主機的資深用戶,一 ......

    uj5u.com 2020-09-10 06:09:13 more
  • 可編程網卡芯片在滴滴云網路的應用實踐

    **?桔妹導讀:**隨著云規模不斷擴大以及業務層面對延遲、帶寬的要求越來越高,采用DPDK 加速網路報文處理的方式在橫向縱向擴展都出現了局限性。可編程芯片成為業界熱點。本文主要講述了可編程網卡芯片在滴滴云網路中的應用實踐,遇到的問題、帶來的收益以及開源社區貢獻。 #1. 資料中心面臨的問題 隨著滴滴 ......

    uj5u.com 2020-09-10 06:10:21 more
  • 滴滴資料通道服務演進之路

    **?桔妹導讀:**滴滴資料通道引擎承載著全公司的資料同步,為下游實時和離線場景提供了必不可少的源資料。隨著任務量的不斷增加,資料通道的整體架構也隨之發生改變。本文介紹了滴滴資料通道的發展歷程,遇到的問題以及今后的規劃。 #1. 背景 資料,對于任何一家互聯網公司來說都是非常重要的資產,公司的大資料 ......

    uj5u.com 2020-09-10 06:11:05 more
  • 滴滴AI Labs斬獲國際機器翻譯大賽中譯英方向世界第三

    **桔妹導讀:**深耕人工智能領域,致力于探索AI讓出行更美好的滴滴AI Labs再次斬獲國際大獎,這次獲獎的專案是什么呢?一起來看看詳細報道吧! 近日,由國際計算語言學協會ACL(The Association for Computational Linguistics)舉辦的世界最具影響力的機器 ......

    uj5u.com 2020-09-10 06:11:29 more
  • MPP (Massively Parallel Processing)大規模并行處理

    1、什么是mpp? MPP (Massively Parallel Processing),即大規模并行處理,在資料庫非共享集群中,每個節點都有獨立的磁盤存盤系統和記憶體系統,業務資料根據資料庫模型和應用特點劃分到各個節點上,每臺資料節點通過專用網路或者商業通用網路互相連接,彼此協同計算,作為整體提供 ......

    uj5u.com 2020-09-10 06:11:41 more
  • 滴滴資料倉庫指標體系建設實踐

    **桔妹導讀:**指標體系是什么?如何使用OSM模型和AARRR模型搭建指標體系?如何統一流程、規范化、工具化管理指標體系?本文會對建設的方法論結合滴滴資料指標體系建設實踐進行解答分析。 #1. 什么是指標體系 ##1.1 指標體系定義 指標體系是將零散單點的具有相互聯系的指標,系統化的組織起來,通 ......

    uj5u.com 2020-09-10 06:12:52 more
  • 單表千萬行資料庫 LIKE 搜索優化手記

    我們經常在資料庫中使用 LIKE 運算子來完成對資料的模糊搜索,LIKE 運算子用于在 WHERE 子句中搜索列中的指定模式。 如果需要查找客戶表中所有姓氏是“張”的資料,可以使用下面的 SQL 陳述句: SELECT * FROM Customer WHERE Name LIKE '張%' 如果需要 ......

    uj5u.com 2020-09-10 06:13:25 more
  • 滴滴Ceph分布式存盤系統優化之鎖優化

    **桔妹導讀:**Ceph是國際知名的開源分布式存盤系統,在工業界和學術界都有著重要的影響。Ceph的架構和演算法設計發表在國際系統領域頂級會議OSDI、SOSP、SC等上。Ceph社區得到Red Hat、SUSE、Intel等大公司的大力支持。Ceph是國際云計算領域應用最廣泛的開源分布式存盤系統, ......

    uj5u.com 2020-09-10 06:14:51 more
  • es~通過ElasticsearchTemplate進行聚合~嵌套聚合

    之前寫過《es~通過ElasticsearchTemplate進行聚合操作》的文章,這一次主要寫一個嵌套的聚合,例如先對sex集合,再對desc聚合,最后再對age求和,共三層嵌套。 Aggregations的部分特性類似于SQL語言中的group by,avg,sum等函式,Aggregation ......

    uj5u.com 2020-09-10 06:14:59 more
  • 爬蟲日志監控 -- Elastc Stack(ELK)部署

    傻瓜式部署,只需替換IP與用戶 導讀: 現ELK四大組件分別為:Elasticsearch(核心)、logstash(處理)、filebeat(采集)、kibana(可視化) 下載均在https://www.elastic.co/cn/downloads/下tar包,各組件版本最好一致,配合fdm會 ......

    uj5u.com 2020-09-10 06:15:05 more
最新发布
  • day02-2-商鋪查詢快取

    功能02-商鋪查詢快取 3.商鋪詳情快取查詢 3.1什么是快取? 快取就是資料交換的緩沖區(稱作Cache),是存盤資料的臨時地方,一般讀寫性能較高。 快取的作用: 降低后端負載 提高讀寫效率,降低回應時間 快取的成本: 資料一致性成本 代碼維護成本 運維成本 3.2需求說明 如下,當我們點擊商店詳 ......

    uj5u.com 2023-04-20 08:33:24 more
  • MySQL中binlog備份腳本分享

    關于MySQL的二進制日志(binlog),我們都知道二進制日志(binlog)非常重要,尤其當你需要point to point災難恢復的時侯,所以我們要對其進行備份。關于二進制日志(binlog)的備份,可以基于flush logs方式先切換binlog,然后拷貝&壓縮到到遠程服務器或本地服務器 ......

    uj5u.com 2023-04-20 08:28:06 more
  • day02-短信登錄

    功能實作02 2.功能01-短信登錄 2.1基于Session實作登錄 2.1.1思路分析 2.1.2代碼實作 2.1.2.1發送短信驗證碼 發送短信驗證碼: 發送驗證碼的介面為:http://127.0.0.1:8080/api/user/code?phone=xxxxx<手機號> 請求方式:PO ......

    uj5u.com 2023-04-20 08:27:27 more
  • 快取與資料庫雙寫一致性幾種策略分析

    本文將對幾種快取與資料庫保證資料一致性的使用方式進行分析。為保證高并發性能,以下分析場景不考慮執行的原子性及加鎖等強一致性要求的場景,僅追求最終一致性。 ......

    uj5u.com 2023-04-20 08:26:48 more
  • sql陳述句優化

    問題查找及措施 問題查找 需要找到具體的代碼,對其進行一對一優化,而非一直把關注點放在服務器和sql平臺 降低簡化每個事務中處理的問題,盡量不要讓一個事務拖太長的時間 例如檔案上傳時,應將檔案上傳這一步放在事務外面 微軟建議 4.啟動sql定時執行計劃 怎么啟動sqlserver代理服務-百度經驗 ......

    uj5u.com 2023-04-20 08:26:35 more
  • 云時代,MySQL到ClickHouse資料同步產品對比推薦

    ClickHouse 在執行分析查詢時的速度優勢很好的彌補了MySQL的不足,但是對于很多開發者和DBA來說,如何將MySQL穩定、高效、簡單的同步到 ClickHouse 卻很困難。本文對比了 NineData、MaterializeMySQL(ClickHouse自帶)、Bifrost 三款產品... ......

    uj5u.com 2023-04-20 08:26:29 more
  • sql陳述句優化

    問題查找及措施 問題查找 需要找到具體的代碼,對其進行一對一優化,而非一直把關注點放在服務器和sql平臺 降低簡化每個事務中處理的問題,盡量不要讓一個事務拖太長的時間 例如檔案上傳時,應將檔案上傳這一步放在事務外面 微軟建議 4.啟動sql定時執行計劃 怎么啟動sqlserver代理服務-百度經驗 ......

    uj5u.com 2023-04-20 08:25:13 more
  • Redis 報”OutOfDirectMemoryError“(堆外記憶體溢位)

    Redis 報錯“OutOfDirectMemoryError(堆外記憶體溢位) ”問題如下: 一、報錯資訊: 使用 Redis 的業務介面 ,產生 OutOfDirectMemoryError(堆外記憶體溢位),如圖: 格式化后的報錯資訊: { "timestamp": "2023-04-17 22: ......

    uj5u.com 2023-04-20 08:24:54 more
  • day02-2-商鋪查詢快取

    功能02-商鋪查詢快取 3.商鋪詳情快取查詢 3.1什么是快取? 快取就是資料交換的緩沖區(稱作Cache),是存盤資料的臨時地方,一般讀寫性能較高。 快取的作用: 降低后端負載 提高讀寫效率,降低回應時間 快取的成本: 資料一致性成本 代碼維護成本 運維成本 3.2需求說明 如下,當我們點擊商店詳 ......

    uj5u.com 2023-04-20 08:24:03 more
  • day02-短信登錄

    功能實作02 2.功能01-短信登錄 2.1基于Session實作登錄 2.1.1思路分析 2.1.2代碼實作 2.1.2.1發送短信驗證碼 發送短信驗證碼: 發送驗證碼的介面為:http://127.0.0.1:8080/api/user/code?phone=xxxxx<手機號> 請求方式:PO ......

    uj5u.com 2023-04-20 08:23:11 more