sql索引及優化

索引:是對數據庫表中一列或多列的值進行排序的一種結構,只有當經常查詢索引列中的數據時,才需要在表上創建索引。
在這裏插入圖片描述

一.索引介紹

索引是關係型數據庫中給數據庫表中一列或者多列的值排序後的儲存結構,SQL的主流索引結構有B+樹以及Hash結構,聚集索引以及非聚集索引用的是B+樹索引.

MySql索引類型有:唯一索引,主鍵(聚集)索引,非聚集索引,全文索引.

1.1:聚集索引

聚集(clustered)索引,也叫做聚簇索引.

定義:數據行的物理順序與列值(一般是主鍵的那一列)的邏輯順序相同,一個表中只能擁有一個聚集索引.

注意:聚集索引做查詢可以直接獲取對應的全部列的數據.所以聚集查詢較快.

1.2非聚集索引

定義:該索引中索引的邏輯順序與磁盤上行的物理存儲順序不同,一個表中可以擁有多個非聚集索引.

除了聚集索引以外的索引都是非聚集索引,分成普通索引,唯一索引和全文索引.

注意:非聚集索引查詢在索引沒覆蓋到對應列的時候需要進行二次查詢,索引非聚集查詢較慢.

1.3 mysql爲變量添加索引

1.添加PRIMARY KEY(主鍵索引)

ALTER TABLE `table_name` ADD PRIMARY KEY ( `column` ) 

2.添加UNIQUE(唯一索引)

ALTER TABLE `table_name` ADD UNIQUE ( `column` ) 

3.添加INDEX(普通索引)

ALTER TABLE `table_name` ADD INDEX index_name ( `column` )

4.添加FULLTEXT(全文索引)

ALTER TABLE `table_name` ADD FULLTEXT ( `column`) 

5.添加多列索引

ALTER TABLE `table_name` ADD INDEX index_name ( `column1`, `column2`, `column3` )

二.BTree樹實現索引

  • 先從MySQL的基本存儲結構說起
    MySQL的基本存儲結構是頁(記錄都存在頁裏邊):
    InnoDB頁結構示意圖
  • 各個數據頁可以組成一個雙向鏈表
  • 每個數據頁中的記錄又可以組成一個單向鏈表
    每個數據頁都會爲存儲在它裏邊兒的記錄生成一個頁面目錄, 在通過主鍵查找某條記錄的時候可以在頁目錄中使用二分法快速定位到對應的插槽,然後再遍歷該插槽對應的分組中的記錄即可快速找到指定的記錄
    以其他列(非主鍵)作爲搜索條件:只能從最小記錄開始依次遍歷單鏈表中的每條記錄。

所以說,如果我們寫select * from user where indexname ='xxx’這樣沒有進行任何優化的sql語句,替換會生成:

1.定位到記錄所在的頁:需要遍歷雙向鏈表,找到所在的頁
2.從所在的頁面內中查找相應的記錄:由於不是根據主鍵查詢,只能遍歷所在頁面的單鏈表了

很明顯,在數據量很大的情況下這樣查找會很慢!這樣的時間複雜度爲O(n)。

  • 使用索引之後
    索引就是一些什麼可以讓我們查詢速度速度呢?其實就是將無序的數據變成有序(相對):
    要找到id爲8的記錄簡要步驟:
    在這裏插入圖片描述
    很明顯的是:沒有用索引我們是需要遍歷雙向鏈表來定位對應的頁面,現在通過“目錄”就可以很快地定位到對應的頁面上了!(二分查找,時間複雜度近似爲O(logn ))

其實實質上結構就是B +樹,B +樹作爲樹的一種實現,能夠讓我們很快地尋找出對應的記錄。

三.建立索引的原則

最左基本原則

MySQL中的索引可以以一定順序引用多列,這種索引叫作聯合索引。如用戶表的名稱和城市加聯合索引就是(name,city),而最左上方原則指的是,如果查詢的時候查詢條件精確匹配索引的左邊連續一列或幾列,則此列就可以被用到。如下:

select * from user where name=xx and city=xx ; //可以命中索引
select * from user where name=xx ; // 可以命中索引
select * from user where city=xx ; // 無法命中索引 

這裏需要注意的是,查詢的時候如果兩個條件都用上了,但是順序不同,如city= xx and name =xx,那麼現在的查詢引擎會自動優化爲匹配聯合索引的順序,這樣是能夠命中索引的。
由於最左上邊的原則,在創建聯合索引時,索引分段的順序需要考慮分段值去重之後的個數,否則的放前面。ORDERBY子句也遵循此規則。

  1. 定義主鍵的數據列一定要建立索引
  2. 定義有外鍵的數據列一定要建立索引。
  3. 對於經常查詢的數據列最好建立索引。
  4. 對於需要在指定範圍內的快速或頻繁查詢的數據列。
  5. 經常出現在關鍵字order by、group by、distinct後面的字段,建立索引。如果建立的是複合索引,索引的字段順序要和這些關鍵字後面的字段順序一致,否則索引不會被使用。
  6. 對於那些查詢中很少涉及的列,重複值比較多的列不要建立索引。

四.sql索引優化面試題

題目一:
select * from student s where s.stuName in(“張三”,“李四”,“王五”)and s.age>18 and s.sex=‘男’;

思路:

1.肯定要建立二級聯合索引:index(stuName,age,sex)

2.這裏要優化一下sql語句中的in,改用union all

優化後的sql:
select * from student s where s.stuName=“張三” and s.age>18 and s.sex=‘男’ union all select * from student s where s.stuName=“李四” and s.age>18 and s.sex=‘男’ union all select * from student s where s.stuName=“王五” and s.age>18 and s.sex=‘男’ ;

題目二
sql優化(查詢9:1)
1.儘量使用列名(Oracle9i之後, *和列名一樣)
在業務密集的SQL當中儘量不採用IN操作符,用EXISTS 方案代替。

2、模糊查詢like
關鍵詞%yue%,由於yue前面用到了“%”,因此該查詢必然走全表掃描,除非必要,否則不要在關鍵詞前加%,

3 二者都能使用盡量使用where (與having比較)
where 先過濾(數據就少了)在分組

4: 理論上,儘量使用多表連接(join)查詢(避免子查詢)

相關網址:
https://snailclimb.gitee.io/javaguide/#/docs/database/MySQL%20Index
https://blog.csdn.net/qq_44590469/article/details/96473238

https://blog.csdn.net/tian31233/article/details/52052963?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章