MySQL索引重点问题总结(需要完整脑图的联系我)
MySQL索引
MySQL邏輯架構
連接層
MySQL連接層主要包括連接池,mysql屬于C/S架構,每次客戶端和服務端連接時,底層都會創建一個TCP連接,連階層主要負責管理這些連接,驗證用戶名密碼和權限認證
服務層
mysql的服務層主要負責sql語句的解析優化。它有基礎服務組件,SQL借口,解析器,優化器,查詢緩存(MySQL8.0之后去除了這個雞肋的設計)等組成。整個語句的執行過程是這樣的先查看查詢緩存中是否存在當前執行的語句,如果不存在則先由解析器解析,優化器指定執行計劃,調用sql接口由存儲引擎層執行真正的工作。
解析器
數據庫的解析器先對sql語句進行詞法分析,分析出哪些是關鍵字,表名,屬性,然后進行語法分析,創建出語法出語法數,進行權限認證。
優化器
優化器的主要作用是制定一個高效的執行計劃,對語句的優化分為邏輯上的優化比如說是否可以將一個子查詢改寫為一個多表連接語句(因為子查詢會創建臨時表并且不能夠使用索引)和物理上的優化比如說使用什么樣的索引可以增加查詢的速度等等。
查詢緩存
查詢緩存其實就是mysql中一個kv鍵值對的存儲空間它將對應的sql語句作為key,執行的結果作為value。如果后續執行相同的語句可以通過緩存直接得到結果。 弊端:查詢緩存中以sql語句作為key,只要輸入的語句有一點點不同即使語句的語義一致也不能夠使用上緩存。針對一些函數比如說時間函數now,會改變語句中的時間頁使用不到緩存。對數據庫的改變會刷新緩存降低命中率 Oracle中的緩存設計,使用到一個共享池的概念,它不僅僅會緩存語句還會緩存對應的執行計劃,而且它還利用一種類似函數的機制有利于批量處理數據。存儲引擎層
存儲引擎以前有個很土的名字叫做表處理器,這個名字更能夠讓我們了解其的作用。其實每個存儲引擎就是對應著不同應用場景下設計不同數據庫表的存儲方式,在不同的存儲結構上面構建具有不同作用不同性能的表處理器。
例如最經典的INNODB存儲引擎在5.0階段的存儲結構就是由.opt文件來存儲一些數據庫通用的設置,由.frm文件存儲表的結構由.ibd文件來存儲數據和索引(innodb中有一句很經典的話叫做數據即索引,索引即數據);在升級到mysql8.0之后mysql的存儲結構變成了.ibd文件一個它將數據庫配置信息,表結構信息,和索引數據都存儲在一個文件中。
再比如MYIAM存儲引擎,它底層的表存儲結構為使用.frm文件來存儲表結構,分別使用.myi,.myd文件存儲索引和數據,這也導致它在索引的設計上和innodb有一些細微的差別
查看和設置存儲引擎
對于數據庫存儲引擎的查看和設置
查看mysql所有支持的存儲引擎:
show engines
查看存儲引擎相關的信息:
show variables like “%storage_engine%”
show variables like “default_storage_engine”
對于表級別存儲引擎的設置和修改
可以在表定義的時候在后面跟上engine = “InnoDB”
可以修改表的結構來修改存儲引擎:
alter table table_name engine = “innoDB”
各種存儲引擎的介紹
InnoDB
InnoDB是在mysql5.5之后默認的存儲引擎,優點在于其支持事務,缺點在于它對比MYISAM上性能會有所偏差
MYSISAM
MYISAM存儲引擎主要適合用于處理讀比較多的業務場景。
優點在于它的性能會比較好
缺點在于它不支持事務,行級別的鎖,外鍵等,無法保證失敗回滾
CSV
CSV存引擎可以支持使用excel打開
Archive
Archive的意思是歸檔,所以說這是一個專門用于歸檔的存儲引擎,它只有增加和查詢操作。并且有很好的壓縮機制
memory
memory存儲引擎的數據表結構使用.frm文件存儲在磁盤上但是其數據存儲在內存中,適合使用在短時間內訪問的臨時數據。默認使用的索引結構是hash索引,并且對表的字段和大小都有嚴格的限制。
InnoDB和MYISAM的區別
①首先從文件系統的存儲結構上來說InnoDB在8.0之前將數據庫通用設置存儲在.opt文件中,將表機構存儲在.fem文件中,將數據和索引存儲在.ibd文件中(所以InnoDB中有一句話叫做索引即數據數據即索引,因為它們是一起存放的),在8.0之后將上述的所有信息都存儲在.ibd文件中.而對于MYISAM存儲引擎來說它將表結構存儲在.frm中,將數據存儲在.myi中,將數據存儲myd文件中。數據和索引是分開存放的這也導致MYISAM中的索引都是通過B+Tree的結構在索引文件中存放然后通過指針指向數據的所以在MYISAM中不存在聚簇索引這一說。
②由于底層存儲的結構不一樣導致緩存也不一樣,INnoDB緩存聚簇索引和數據,MYIASM只緩存數據
③由于底層結構不一致所以索引的實現上也有所不同
④InnoDB提供對事務的支持,MYIAM則沒有
⑤InnoDB提供對行鎖的支持,MYIAM沒有
⑥InnoDB支持外鍵MYIAMmy
⑦總結來說不同的存儲引擎設置不一樣的底層表存儲結構為了適應不一樣的業務場景,InnoDb側重事務性,MyIAM側重性能
物理層
物理層是真正硬件中存儲mysql中數據庫表和每一行數據的地方,為了不讓mysql大部分工作在磁盤中完成,mysql在內存中分配了一塊緩存以減少磁盤工作和IO時間大大增加mysql的提高了mysql的整體性能。
數據庫緩沖池
數據庫緩沖池其實就是在內存中開辟一塊空間用于存儲頁,減少磁盤IO的時間和磁盤的哦工作提升數據庫的整體性能。 緩沖的規則:數據庫緩沖池的緩沖規則是“位置 * 頻率”,其中位置表示的磁盤能夠快速檢索到的位置,頻率指的是數據庫頁的使用頻率。對于使用頻率較高的數據它不僅僅會緩存本頁的數據還會連帶著緩存上下頁的數據提高數據庫的整體執行效率。MYSQL索引
為什么要有索引:如果數據庫的底層不存在索引,那么我們查詢數據就需要全表掃描效率極低 什么是索引:索引是快速檢索(基于某一種數據結構組織數據,并且在該種數據結構上執行對應的檢索算法)數據的數據結構。基于不同的存儲引擎索引有著不同的實現。 索引的特點就是排序和檢索優缺點
優點:
①加快數據檢索的速度
②對于數據加上唯一索引能夠保證數據的唯一性
③使用索引對數據的排序和分組有很大的性能提升
④使用索引可以加快多表連接
缺點:
①創建索引需要一定的時間
③索引需要一定的存儲空間存放
③雖然索引有利于快速查找數據,但是對于數據的修改更新和刪除需要付出更多的成本來維護數據和索引
索引底層的數據結構
B+Tree
為什么是B+Tree
索引底層的機構剛剛開始并不是B+Tree,通過一代代的更新迭代的。
一、首先我們想到的檢索數據的結構是hash,它的優點在于插入和查詢的復雜度都是O(1)級別的。但是這種復雜度是用于檢索一條數據的,當檢索范圍數據時它逐條掃描,掃描一次IO一次效率十分低下,而且還存在著hash碰撞的情況。但是我們在查詢時還是可以使用自適應性hash的,它可以讓我們快熟定位到數據頁。
二、第二個快速檢索的數據結構就是樹形結構,在樹形結構中檢索和插入的時間復雜度能夠達到logn級別
①首當其沖的數據結構是二叉樹,二叉樹的缺點是當我們按照順序插入數據時它就會退化為一個鏈表,那么我們檢索數據無異于全表掃描。
②接著考慮書的平衡性,我們就使用平衡二叉樹(AVL數樹),但是平衡二叉樹的缺點在于,它雖然可以有效控制樹的平衡性但是數據庫所需要的樹是要盡量能夠減少磁盤IO的樹也就是說樹的高度不能夠太高所以不能夠使用AVL樹
③我們考慮使用B-Tree(多路平衡搜索樹),這樣增加每個節點的兒子節點數量,大大減小了樹的高度,有效控制磁盤IO。
④我們使用B+Tree(改進的多路平衡搜索樹),它對于B-Tree的改進在于它不在非葉子節點存儲數據,二十將所有的數據都放到葉子節點使用一個雙向鏈表的結構連接起來。
好處在于,非葉子節點現在只存儲索引不存儲真實的數據這樣能夠讓樹的分支更多有效降低了樹的高度,減少了IO的次數。底層使用雙向鏈表的結構將所有的數據按照大小的順序排列這樣有利于檢索范圍的數據,對于B樹來說如果要檢索范圍的數據則需要中序遍歷。
B+Tree索引的介紹
數據庫索引的推演過程
推演的過程:
①首先設想數據庫中不存在索引,那么一個表中的數據是散落在一個個的頁中的,各個頁之間使用雙向鏈表的結構連接起來這個數據記錄在頁首部的字段中。各個頁的內部使用向鏈表的結構來組織存儲,各個記錄之間的指針信息存儲在字段首部信息中。這樣我們要檢索一個數據就要從第一頁開始逐條搜索,然后通過指針信息跳轉到下一個頁中,接著逐條掃描,效率極其低下。
②那我們就會想使用一個數據結構給本結構做一個優化處理,于是想到在數據頁的上一層建立一層索引頁(其實也是數據頁區別在于索引頁中的記錄類型和記錄頭信息有細微的差別),這樣我們就可以先訪問索引頁找到對應的頁位置大大減小了IO的次數。
③當插入的數據過多底層產生頁分裂導致上層索引頁不夠記錄數據,索引頁頁產生了頁分裂,這樣我們就需要在索引頁上層頁再建立一層索引頁。保證整個索引的訪問結構中樹只有一個根節點(這個跟節點頁一般時存儲在內存當中的,當需要使用索引時就可以減少一次IO操作,這也是為什么數據的訪問只需要兩次或者三次IO的原因)
推演中三個需要糾正的點
①根節點的位置萬年不變,我們上述的推到過程時從下往上的推到,而現實中的B+Tree創建時從上往下的,當一個索引頁中的數據不夠存放時會產生頁分裂這個時候創建一個新的頁將本頁中的數據copy到新的頁中然后將本頁的指針指向新創建的索引頁中。
②索引中數據記錄要保證唯一性,所以創建索引時不單單要保存當前的數據記錄,為了保證每個節點的唯一性還需要保存當前表的主鍵值。
③由于我們要創建的是一個是一個樹型結構所以索引頁的分支不能少于二
B+Tree索引的文件存儲結構
mysql管理數據底層存儲的層級分為,表空間,段,區,頁,數據行
表空間
表空間是mysql中一個邏輯概念,mysql的表空間中我們需要了解的就是系統表空間和獨立表空間兩種
####### 系統表空間
系統表空間在mysql5.5之前可以用于存儲用戶表中的數據和系統表中的數據,但是在5.6之后只能用于存儲系統表中的數據。mysql系統數據庫主要有如下幾個
①information_schame:這個數據庫中存儲的主要是數據庫的一些配置參數信息比如說使用的存儲引擎信息,設置的字符集信息等
②performance—_schame:這個數據庫中存儲的主要是數據庫運行的一些狀態信息比如說我們的profile信息等。
③sys:為了更加方便查閱數據庫中的信息我們將一些經常需要查詢大的數據庫配置信息和狀態信息存儲在這個數據庫中。
####### 獨立表空間
獨立的表空間在mysql5.6之后專門用于存儲用戶自定義的數據庫中的信息,我們表中的ibd文件都存儲在獨立表空間中。
好處:
①有利于數據的遷移
②有利于表空間的回收
段
mysql中的段主要包括,數據段,索引段,系統段,事務段,undo段等等。我們將數據組織成B+Tree之后樹中有分為索引頁和數據頁為了訪問對應的數據更加純粹我們分出了段的概念。
區
為什么要有區:
這個涉及到數據頁訪問的效率,比如說我們在內存中訪問一個數據頁大概需要1ms的時間,在磁盤上使用隨機IO訪問一頁數據的時間大概是10ms(大部分的時間浪費在半圈旋轉,尋道和排隊等待上而真正用于IO的時間只有十分之一),如果在磁盤上使用順序IO呢,在大批量加載的前提下訪問一個數據頁的時間只需要0.4ms。至此我們看到了隨機IO和順序IO的效率差別還是很大的所以我們訪問數據的時候應該盡可能使用順序IO來提升數據訪問的效率。區就此誕生它將64個頁組織成一個連續的存儲空間(大小正好為1MB),方便我們在范圍這一個區的數據時時順序IO。而區和區之間再使用指針來連接做到物理上的來連續。
區的分類:
要介紹區的分類首先得引入一個概念叫做碎片區,我們設想很小的數據量情況下我們需要在數據段和索引段中各種劃分出一個區也就是2M的存儲空間來存儲比如說10kb的數據,這太浪費空間了。所以對于著一些占用很小空間的數據我們完全可以讓它們共享一個區,而這個區就叫做碎片區。所以MySQL底層在分配空間的時候,碎片區首先時隸屬于表空間的當某一個數據占有超過32個區的時候再給它分配一個專門的段。
所以區的分類就出來了:
①空閑區
②帶有剩余空間的碎片區
③不帶有空閑空間的碎片區
④隸屬于某一個段的區
頁
頁是內存和磁盤交互的基本單位(基本單位的意思是說,不管我們只需要獲取修改一個頁中的一條或者幾條數據,都需要加載完整的頁和寫入完整的頁)一個頁的大小默認是64kB。
頁的底層存儲結構是雙向鏈表結構,頁內部則是采用單向鏈表來存儲每一條數據。
####### 頁的存儲格式
頁的存儲格式主要分為七個部分我們將這七個部分分為三類來分卸:
一、:文件的頭尾
文件頭存儲的信息包括:文件屬于什么類型,頁號,頁的前后指針,校驗和以及日志文件中記錄的位置
文件尾存儲的信息:就只有校驗和和日志文件中記錄的位置
其中最重要的兩個部分就是校驗和和日志文件中存儲的位置。
首先我們看看校驗和到底是個什么東西,當一個文件很長的時候我們可以使用抽樣算法抽取出文件中的主要信息相當于形成一個文件的指紋用于標識一個文件。這個指紋就叫做校驗和。那么它的作用就是當一個頁被加載到內存中使用和修改之后會修改它的頭尾校驗和,當刷盤中出現錯誤時,就會導致首尾的校驗和不一致的問題這個時候我們就能夠識別這一種錯誤,采取回滾或者借助redo日志完成刷盤操作。
日志文件的記錄位置頁是起到這一個作用
二、頁頭和頁目錄
頁頭存儲著野種許多零零碎碎的信息,比如頁中有多少條記錄,有多少個用于頁目錄訪問的槽位以及頁中刪除鏈表的信息等。
頁目錄:
引入頁目錄的原因是為了快速查找一個頁面中的數據,他的設計是這樣的為了減少空間的使用它將數據分為一組一組最小記錄為一組其他記錄按照達到九個分裂出四個的方式分組。我們只要記錄每組中最大的記錄作為一個槽位來進行二分法查找如果,具體的查找過程由于單鏈表單向訪問的特點所以我們要查找一組中的數據的時候需要查找它的上一個分組中的最大記錄順序往下。
這個還涉及到了行格式中行頭部信息的一個用于記錄一組中有多少個記錄的一個標志位,這個標志位只會存在于一組中最大的記錄中。
三、:最大最小記錄,頁記錄,空閑空間
最大最小記錄很好理解就是一頁中最大的額和最小的它們存儲在頭部中并且記錄的編號為0和1
頁記錄:這個位置就是真正用于記錄我們每一條記錄的位置
剩余空間:就是我們這個頁還有多多少可用的空間。
數據行
####### 數據行格式
數據行的格式大體上分為四種:
compact,dynamic,compressed,redundant其中最主要需要了解的就是compact其他的格式都和它大同小異。
######## compact
compact格式大體上分為額外記錄的信息和行數據,額外記錄的信息中包括邊長字段長度列表和null值列表記錄頭信息,行行記錄信息分為隱藏列信息和真實數據。
######### 額外信息
########## 變長字段長度列表
變長字段長度列表主要用于記錄我們的表記錄中邊長字段真實使用的長度信息,它的記錄方式是從尾到頭記錄我們變長字段長度
########## null值列表
null值列表的意思是使用一個bit位來記錄我們的字段是否為null并且它也是倒序存放d
########## 記錄頭信息
記錄頭信息記錄以下幾個信息:
表中字段的類型,序號,下一條記錄的位置,以及三個屬性分別為當前的記錄是否被刪除(被刪除的記錄會標識為1并且所有已經被刪除的記錄組成一個鏈表方便后期使用),該條記錄是否是頁中一組中的最小值以及一組中數據的個數
######### 真是數據信息
########## 隱藏列數據
隱藏列主要有如下三條:
①本條記錄的rou_id:這個值用于唯一標識一條記錄,當我們的數據表中不存在主鍵和唯一字段時就是使用這個字段來作為主鍵
②事務id
③回滾指針
########## 表記錄數據
######## dynamic
######## compressed
######## redundant
基于不同存儲引擎的實現
InnoDB 底層索引
索引分類
####### 聚簇索引
聚簇索引其實就是mysql通過主鍵創建的一個索引(如果表中有主鍵直接通過表中的主鍵創建,如果沒有主鍵但是存在唯一約束字段就會通過這個字段創建,如果兩者都沒則會自動生成一個字段來代表主鍵)這個索引的底層存儲的是表中的整行記錄
優點:
①索引及數據,數據即索引,查找的速度很快
②對于排序和范圍的數據,可以做到快速查找
③減少IO
缺點:
①對于表記錄的修改操作(增,刪,改)我們為了維護現在的聚簇索引結構可能會出現頁分裂,記錄移位,記錄換位的情況
②二級索引需要借助主鍵索引才能訪問到其他列中的數據
####### 非聚簇索引(二級索引,輔助索引)
非聚簇索引(也叫二級索引或者輔助索引),就是通過非主鍵字段創建的索引它的底層存儲的是該字段的值以及主鍵字段的值。InnoDB中有個詞叫做回表,如果要查詢的字段就在這個索引底層存儲表示我們可以通過這個索引來直接的到數據這樣獲取到的數據就叫做索引覆蓋,如果在這個索引中得不到數據就需要根據主鍵的值在聚簇索引中進行一個回表操作獲得值。
####### 聯合索引
聯合索引(或者叫多列索引),就是通過多個字段共同構建的索引會根據聲明索引的順序先后按照字段排序組織索引。
MYISAM底層索引
MYISAM存儲引擎的表文件系統表存儲結構時將索引和數據分離的,所以在MYIAM中不存在聚簇索引,非聚簇索引這一說。
它的底層也是通過B+Tree實現的只不過它的葉子節點中存儲的是指向數據的指針。
MYISAM和InnoDB索引對比
①首先二者文件存儲結構不同,InnoDb將數據和索引存儲在一個文件中,MyIAM將數據和索引分別存儲
②MYISAM中的索引通過字段組織二叉樹,葉子節點存儲的是數據的地址,InnoDb存儲的是真正的數據,所以MYISAM中的索引其實都是需要回表操作的但是它的回表操作是通過地址直接獲取到數據不像InnoDB中通過主鍵索引去獲取數據效率低下
③InnoDB中的索引分為聚簇索引和非聚簇索引使用聚簇索引可以快速查找到數據不需要回表,非聚簇索引借助聚簇索引查找數據。聚簇索引要求InnoDB中必須要有主鍵,MYIAM是可以沒有主鍵的
索引的增刪改查以及MYSQL8.0中索引的新特性
索引的增刪改查
索引的創建
索引其實可以在兩個時機創建第一個時在建表的時候創建索引,第二個實在建表之后創建索引
建表的時候創建索引
####### 隱式創建
其實對于主鍵索引(也就是我們所說的聚簇索引)在聲明表的主鍵的時候就已經創建,而對表的唯一約束則時和唯一索引綁定,我們在聲明唯一約束的時候就已經創建了一個唯一索引
####### 顯式創建索引
在建表的時候顯式創建索引其實只需要在建表語句的最后和加約束一樣加上創建索引的語句就可以:
eg:
create table table_name(
id int primary key,
name char(10) unique,
index index_name(col1,col2)
);
在建表之后創建索引
在建表之后創建索引的方式有兩種:
①使用alter table 語句創建
eg:alter table add index index_name(col1,col2);
②使用create index index_name on table_name(col1,col2);
索引的刪除
索引的刪除也有兩種方式:
①通過alter table語句刪除
alter table table_name drop index
index_name;
②通過drop index… on…語句刪除
eg:drop index index_name on table_table_name;
如何查看一個表中的索引
eg:show index from table_name
MYSQL8.0中索引的新特性
隱藏索引
隱藏索引其實可以看作時間索引開啟或者關閉,用于測試有索引和沒有索引時數據庫的查詢xing’neng
降序索引
在mysql5的版本中其實就有降序索引的功能但是其底層組織索引還是使用升序索引只是在訪問時反著訪問而已,但是在mysql8.0之后真正的將索引數據降序組織
索引的分類
按照邏輯功能分類
按照邏輯功能分類索引可以分為主鍵索引,唯一索引,全文索引。普通索引
按照物理組織方式分類
按照物理組織方式對索引分類可以分為聚簇索引和非聚簇索引
按照索引的列數
按照索引的列數分類可以將索引分為單列索引和多列索引
索引創建的原則
什么情況下可以使用索引
①針對列來說
對于重復低的列(一個可參照的數據時%33),具有唯一約束的列,使用distinct的列,列的類型占用字節較小的,對于字符串類型的值需要對字符串的前綴建立索引
②針對語句來說
where語句中經常使用的列(這里的where手的時select,update和delete),group by和order by,對于連表查詢的字段建立索引前提是兩個連表查詢的字段類型要一致
③針對聯合索引來說
對于經常一起使用的字段建立索引,需要注意最左前綴pi’pei
什么情況下不可以使用索引
從表的角度來說:
對于數據量較小的表不需要建立索引,對于經常更新的表不需要建立索引
從列的角度來說:
數據上來考慮對于重復度較高(%33),無序的數據不需要建立索引對于where使用不到的字段不建立索引
不要創建過多的索引
①刪除冗余的索引
②刪除使用不到或者使用少的索引
數據庫性能分析
數據庫調優的過程
①首先得查看服務器是否存在性能忽高忽低的情況如果存在就需要加上緩存。
②開啟慢查詢日志,查看慢sql,對失去了語句使用性能分析工具驚醒分析,查看是sql執行的等待時間過長還是執行時間過長。如果是等待時間過長則需要配置服務器參數。如果是執行時間過長則查看是否是是表結構問題,索引的問題還是join語句過多導致的。
③如果性能還是不好則試著數據庫分庫分表,主從復制讀寫分離。
性能分析工具的使用
慢查詢日志
①慢查詢日志的開啟和關閉
使用“slow_query_log”參數開啟和關閉
②慢查詢日志的兩個指標一個文件和一個工具
“long_query_time”:表示最大查詢時間
“min_examing_rows_limit”:標識查詢的條數
“slow_query_log_file”指定慢查詢日志文件
使用mysqldumpslowk可以分析慢查詢日志
③如何查看慢查詢
使用:show status like "Slow_queries"查看慢查詢語句
Explain
explain分析工具用于分析一條sql語句的執行計劃,一條查詢語句再復雜最終也得對每一個表進行訪問,所以explain的每一條記錄代表著一個表的訪問方式,每一個id代表著一條查詢語句的執行。它可以使用explain或者describe關鍵字來查看
使用explain的注意點
在sql5.6之前explain只能對select語句使用explain在5.6的后續版本中就可以使用explain查看delete,insert和update
在5.7版本explain中的patitions和filtered需要使用系統表查看,在后續版本中直接可以在explain查看
四種查看方式
它的查看方式分為comand窗口查看,可視化工具查看或者使用json和Tree的形式查看
各列的信息
由于explain是針對表的訪問方法確定的所以有一下分類:
①id和select_type為一類表示查詢語句的編號和查詢類型
②涉及到表的分別有table,type,patitions為一類標表示表名稱和表的訪問類型,表分區的具體信息
③possible_keys,key,key_len和ref分為一類表示可能使用的索引,使用的索引,索引的長度和等職比較的具體信息
④rows,filter分為一類用于表示是否為范圍一共訪問到的記錄條數和過濾的百分比
⑤extra單獨為一類表示額外的信息
####### 查詢的信息
?
######## id
一個id用于表示一條查詢語句,id的訪問優先級從大到小1,如果優先級相同則從上到下
######## select_type
select_type用于表示本查詢在總體查詢中是什么樣的地位:
simple:簡單查詢
primary:
union:聯合結果
union_result:聯合結果產生去重的臨時表
dependent_union:使用in和exist會產生相關的聯合
subquery:子查詢
dependent_subquery:相關子查詢
####### 表的信息
######## table:
這條記錄中被發訪問的表名
######## type:
表的訪問方式,主要分為一下幾種:
system:表中只有一條記錄,并且所使用的存儲引擎提供的數據是精確的
const:采用主鍵索引或者唯一索引匹配一個常量
eq_ref:使用主鍵索引或者唯一索引聯表查詢
ref:使用普通索引進行常量查詢
unique_subquery:使用唯一索引或者主鍵索引子查詢
range:使用索引匹配方范圍數據
index:使用全索引掃描
all:全表掃描
######## patitions
所使用的表是否是分區表,分區表的具體信息
####### 索引的信息
######## possible_keys
這個查詢中可能使用到的索引,這個索引數量越多越不好因為查詢優化器需要諸葛排除選出最好索引,可以使用的索引太多了導致判斷的時間過長
######## key
真正使用到的索引
######## key_len
使用到的索引的長度,這個長度的計算首先根據不同的字符集確定初始長度,再加上兩個字節代表邊長字段長度列表再叫上一個字節代表null值列表
######## ref
這個用于判斷等職匹配的的值的基本信息可以和查詢的類型一起判斷
####### 訪問條數
######## rows
篩選出來訪問到的記錄數量
######## filtered
過濾率
####### 額外的信息
?
######## extra
這個用于記錄整個sql語句中執行的額外信息蕾仕于一句提示,十分重要。
①普通的比如說from中沒有東西那么就不提示信息,如果使用到where直接查詢沒有使用到索引或者回表的就會提示using where,如果條件不成立就會使用impossible where
②關于索引
using index:使用到覆蓋索引
using index condition:使用到索引條件嚇退
③幾種不好的情況:
using buffer:表連接沒有使用到索引創建了緩沖
file sort:排序沒有使用到索引
using temporary:使用到臨時表,使用distinct,gruop by,union可能會使用lin’shi’biao
ProFile
ProFile用于查看sql語句的執行成本
①開啟和關閉ProFile
設置profiling開啟關閉profile
②查看sql執行成本
show profiles
show profile
show profile for query index
trace
trace用于查看sql執行的全過程包括優化器優化的過程
last_query_cost
用于查看最后一條查詢語句的成本
數據庫調優策略
數據庫的優化策略中有一個三角形,分為四個層次上的優化,優化成本越低起的作用反而越好。這四個層次分別是sql以及索引優化,表結構優化,數據庫系統參數配置和硬件優化
查詢優化和索引優化
查詢優化
關聯查詢優化
####### 外連接優化
外查詢優化語句我們應該在被驅動表上添加索引,這樣可以將被驅動被的數據表訪問類型變成ref提升整體的連接查詢效率
####### 內連接優化
①如果連接的表都沒有或者都有索引,那么內連接遵循小表驅動大表的原則。
②如果有一個表的連接字段上有索引那么該表就會被當作是被驅動biao
####### 關聯查詢的底層原理
關聯查詢的底層原理是Nested Loop Join(嵌套循環連接)這個優點i像我們學習編程中的循環語句。
NLJ分為如下幾種:
①SNLJ(Simple Nested Loop Join)
簡單的嵌套循環連接就像編程語言中的嵌套循環一樣先從外層循環找一條記錄,然后取出連接字段,到內層表當中逐個匹配如果匹配上了就當作是一條記錄。
②BNLJ(Bolck Nested Loop Join)
簡單的嵌套循環連接每次取出外層的一條記錄對比內層記錄之后就會釋放內存數據等到下一次接著加載內層循環的數據,塊嵌套循環連接其實在其基礎上做了優化,在內存中多了一個join buffer,使得外層循環中多條記錄重用內層循環的數據,不用每次都加載,一定程度上提升了性能
③INLJ(Index Nested Loop Join)
索引嵌套循環優化其實可以看組是內層連接使用到了索引復雜度降低到了logn
④在MySQL8.0.20之后的版本中表連接使用Hash Join的方式進行
子查詢優化
子查詢其實就是一條查詢語句能夠做到平常多條查詢語句的查詢效果,也就是內查詢的結果是外查詢提供給外查詢使用,這樣可以有效減少數據庫交互的次數。但是內查詢在使用上也存在很多缺點:
①內查詢會生成臨時表
②內查詢生成的臨時表沒辦法使用索引
優化建議:盡量少寫子查詢,要使用子查詢的地方盡量使用連接查詢來優化
order by,group by和limit優化
o
####### Order by
①order by上其實是可以使用索引的,當排序和過濾的字段一致使用單列索引,當不同時使用多列索引需要注意最左前綴匹配原則
②當沒有辦法使用到索引時只能使用filesort那么我們就該調節對應的數據庫調優參數將filesort的空間增大
####### Group By
①gruop by語句其實也是可以使用索引的,當我們分組和過濾的列一致時使用但開裂索引,當不一致時使用多列索引需要注意最所前綴匹配原則
②當無法使用索引時也需要設置對飲的數據庫調優參數
③只有包含分組函數時使用having否則一律使用where
####### Limit
使用到Limit時我們不應該直接使用類似于
select * from employees limit 1000,2
對應的優化策略有兩條
①當所查詢的列能夠直接使用索引時可以使用索引定位
select id from employees limit 10000,1
②當對應的列使用不到索引時我應該直接定位
select * from employees where id > 20000 limit 2
索引優化
索引失效的案例
####### 涉及到表的
①表中的字符集應該和數據庫的字符集保持一致不然使用時十分容易出現亂碼導致索引失效
②主鍵插入的時候應該保持遞增排序,如果老是從中間插入主鍵,那么聚簇索引底層不斷出現頁分裂不斷調整數據也和索引頁的數據這樣性能很差
####### 涉及到計算,類型轉換,函數的
①過濾條件中使用計算函數類型轉換都會時索引失效
②當使用不等于時索引失效,比如說<>,!=,NOT NUll等等
③使用like “%abc”索引失效
③使用OR連接條件時條件中只要有一個使用不到索引那么其他列都使用不索引
####### 涉及到多列索引
①全職匹配可以直接使用到索引覆蓋,不用回表
②最左前綴原則:索引都是逐級排序的,當使用不到前一段索引后一段頁使用不到。
③碰到范圍列時索引當前列可以使用后面的列失效
覆蓋索引
在InnoDB的索引從物理實現上細分為聚簇索引,非聚簇索引兩種。聚簇索引是通過主鍵(如果沒有主鍵就找唯一字段,如果沒有唯一字段就找數據行隱藏列中的row_id)排序形成的一個索引,其底層存放的時所有的數據記錄,非聚簇索引(頁叫做輔助索引或者二級索引)底層存放的時主鍵值和本列的值,如果時多列索引(也叫聯合索引)底層存放的就是聲明索引的多列值和主鍵值。而我們所提及的覆蓋索引的意思就是我們使用二級索引并且訪問到的字段就是用于組織索引的字段,不需要通過主鍵再回表查詢。
索引下推
索引條件嚇退發生在二級索引,多發生在多列索引當中,當使用道二級索引并且需要回表,我們就可以使用到索引底層那些我們不查詢的數據來過濾數據達到回表時查詢數據盡量少的目的提升語句的性能
給字符串添加索引
再阿里巴巴開發規范里頭指出如果給字符串字段添加索引必須要指明索引前綴的長度,也就是說我們不是給整個字符串添加上索引給字符串的前多少個字符加上前綴(至于是多少個前綴我們判斷規則如下如果加多了浪費空間如果加少了達不到索引的效果所以我們應該再選取前綴盡量少區分度盡量高的一個維度上選擇)
唯一索引和普通索引的區別
①在查找數據上的區別
在查找數據上唯一索引和普通索引的區別就是唯一索引找到一個數據直接返回,普通索引找到一個數據之后還需要進行重復值的判斷,不過這點對數據庫的性能損耗來說可以忽略不記
②在修改數據上的區別
在數據庫修改上最大的區別就在于普通索引可以使用change buffer而唯一索引不可以使用change buffer。change buffer是一塊緩存空間如果我們修改的數據頁存在數據庫緩存當中,直接修改數據頁,如果不存在則記錄這個修改操作當修改的頁被加載到緩存當中是由一個merge線程完成修改的操作,在數據庫服務器關閉的時候merge線程也完成未完成的更新操作。
基于以上這個性能差距我們應該在確定了數據唯一性的場景中使用普通索引,當業務需要數據庫來保證數據唯一性的情況下使用唯一索引
其他瑣碎的優化點
select *
我們應該減少select *的使用,理由有如下兩點:
①數據庫在執行select 語句是需要將“”轉化為各個字段
②使用select * 意味著無論如何操作我們都需要回表除非在數據表的所有字段上建立一個聯合索引但是這顯然不是很現實
count(*) count(1) count(字段)
①count(*)和count(1):這兩者的性能基本無差別,但是基于不同的存儲引擎還是存在差別的,比如收使用MYISAM存儲引擎時底層會使用一個字段來記當前表中的記錄數,查詢時只需要查詢這個字段的值就行其時間復雜度時O(1),但是使用InnoDB的時候每一次執行count
操作都會真真切切的去數據庫中去找遍歷一遍所以時間復雜度時O(n)
②count(具體字段):在執行這個操作的時候我們必須要去表中尋找一遍了查找到底有多少個記錄,查詢優化器會選擇成本最少的索引去查詢
Exist和In
Exist和In適合使用的場景,需要區分表的大小來定,如果內表大于外表應該使用Exist,如果內表小于小標則可以用將內表當作一個集合來處理,使用In
多使用Commit
如果沒有開啟數據庫事務自動提交功能,我們在完成一個事務操作的時候應該及時使用commit釋放資源,比如說事務底層需要使用的鎖,redo,undo,和回滾段
數據庫表結構設計和優化
數據表設計原則
范式
####### 鍵和屬性
各種建:
超鍵:可以唯一識別一個數據行都可以稱之為時超鍵
候選鍵:候選鍵是烈屬最少地超鍵
主鍵:可以在候選鍵當中挑選出一個字段座位表的主鍵
外鍵:A表中的一個字段不是A的主鍵但卻是B表的主鍵
屬性:
主屬性:主鍵字段
非主屬性:非主鍵字段
####### 數據庫表設計的六大范式
范式是什么:數據庫庫表涉及的原則,范式向下兼容,并且遵從的范式越高數據庫比表的冗余度越低
######## 第一范式
第一范式規定數據庫表的所有字段都是原子的不可再分的
######## 第二范式
第二范式在第一范式的基礎上規定數據庫表必須有一個主鍵用于唯一標識一個數行,并且所有的非主鍵字段都必須完全依賴于主鍵
######## 第三范式
第三范式規定所有非主屬性字段都必須直接依賴于主鍵字段而不能傳遞依賴于主鍵
######## BC(巴斯歌德范式)
候選鍵只有一個或者存在多個候選鍵但是這個多個候選鍵都是單屬性的
######## 第四范式
要明白第四范式首先得提出一個概念叫做多值依賴,多值依賴分為平凡的多值依賴和非平方的多值依賴,平凡的多值依賴指的是一個字段和另一個字段有1對多的關系,非平凡的多值依賴指的是存在字段A,B,CA和B,C都存在一對多的關系。第四范式中不能存在非平凡多值依賴
######## 第五范式(完美范式)
所有的 連接依賴都由候選鍵發出
####### 反范式化
我們設計數據庫表應該以業務優先的原則設計,不能夠單單考慮數據的冗余度。所以我們在設計數據庫表的時候還要反范式化設計這樣增加冗余字段可以增加數據庫的性能。
但是冗余字段頁存在一定的問題:
一個字段更新了它的冗余字段也要更新,這樣難以維護并且還會有一定的性能損耗,還會占用一定的空間。所以設計數據庫冗余的時候我們應該遵頊冗余字段對是我們真實需要的并且不經常更新的。
E-R圖的使用
####### 三要素
當數據庫表設計比較復雜的時候我們可以借助E-R圖作為工具設計出表各個實體屬性以及關系,觀察我們設計中存在的邏輯問題,再將它轉化為數據表。E-R圖的三要素包括實體,屬性和關系
######## 實體
實體的特點就是可以獨立存在。尸體可以強實體和若實體,強實體就是不依賴于其他實體單獨存在。弱實體就是需要依賴于存在。用正方形標識
######## 屬性
一個實體上不可以再分的特性可以抽象為一個屬性。用橢圓形標識
######## 關系
關系就是各個實體之間的關系,可以分為一對一的關系,一對多的關系,多對多的關系。菱形來標識
####### PowerDesigner
####### E-R圖轉化為數據表
首先看轉換關系:
一個實體或者一個多對多的關系轉換為一張表,屬性轉化為字段,有一對一和一對多的關系可以轉化為i外連接和外鍵
數據表主鍵的設計
①設計的原則
主鍵的式設計原則是唯一并且遞增排序
②不推薦使用:
自增主鍵:
自增主鍵存在很多問題,比如說可靠性底(在8.0之前存在主鍵回溯),安全性(可以通過怕從手段輕易的得到判斷數據信息),性能差(需要數據庫生成主鍵降低數據庫的性能),交互多(數據庫生成主角按之后要給客戶端客戶端確立之后存入數據庫),局部唯一性(比如說連鎖店各個店都有自己的自增主鍵但是等到整合所有連鎖店的數據時就會存在主鍵重復的問題)
UUID
UUID其實是一個時間+始終序列+MAC地址的一個組合所以很好的實現了唯一性但是它并沒有遞增排序這樣插入很容易引起底層頁分裂性能很差
業務字段
如果直接使用業務字段來構建主鍵,我們很難保證業務字段是否存在,是否改變后期很難調整
③推薦使用
例如淘寶使用的主鍵設計:時間 + 去重 + 用戶id的一個片段這樣很好保證唯一性和自增
變化后的UUID,UUID的時間時倒著存放的我們可以調整它變為時間正序這樣很好保證自增
如果使用的不是MYSQL8.0版本的話我們可以使用時間 + 用戶ID的形式作為主鍵局部在申請主鍵先到主庫中查詢當前ID分配到哪然后根據這個值生成
數據庫參數配置
硬件優化
分庫分表
當數據量大的時候一個數據庫的性能達到瓶頸我們就想著對數據庫分庫分表。
分庫:
根據不同的業務將不同的數據庫表分到不同的數據庫中,降低單庫的壓力
分表:
水平分表:
將表中的記錄拆分成不同的范圍放到不同表中,存在的問題就是有的時候涉及到兩張表的數據很難搞定
垂直分表:
將表字段拆分,這樣做的壞處就是查詢的字段過多的時候會有很多的表連接所以在拆分時應該講究點
主從復制,讀寫分離
總結
以上是生活随笔為你收集整理的MySQL索引重点问题总结(需要完整脑图的联系我)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 系统分析师真题__专项:计算机系统与配置
- 下一篇: SQLSERVER 查询分析器快捷键