前面第三章,我們看了mysql的七種的join的查詢,那這次我們就看下怎麼看我們寫的sql語句有沒有使用索引?
第一個問題:索引是什麼?
索引是幫助Mysql高效擷取資料的資料結構(資料結構),可以了解為我們的字典(排好序的快速查找的資料結構)。
官網的定義:資料本身之外,資料庫還維護着一個滿足特定查找算法的資料結構,這些資料結構以某種方式指向資料,就可以在這些資料結構得基礎上面實作進階查找的算法,這種資料結構就是索引。切記查找+排序
這裡說到了查找+排序,請大家先把這個記住,後面我們在仔細說這個
我們先寫個代碼插入1000萬條資料吧,好久沒寫代碼了畢竟,不然都不好意思說自己是一個程式員了
# sql腳本
create table user
(
id int auto_increment
primary key,
name int null,
pwd int null
);
# java代碼
package com.ai.paul.mallsmanager.service;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
/**
* @ClassName : TestJD1 //類名
* @Description : //描述
* @Author : paul
* @Date: 2020/9/9 16:55
*/
public class TestJD1 {
//static int count = 0;
public static void main(String[] args) {
long start = System.currentTimeMillis();
conn();
long end = System.currentTimeMillis();
System.out.println("耗時:" + (end - start)/1000 + "秒");
}
public static void conn(){
//1.導入驅動jar包
//2.注冊驅動(mysql5之後的驅動jar包可以省略注冊驅動的步驟)
//Class.forName("com.mysql.jdbc.Driver");
//3.擷取資料庫連接配接對象
Connection conn = null;
PreparedStatement pstmt = null;
{
try {
//"&rewriteBatchedStatements=true",一次插入多條資料,隻插入一次
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/malls?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf-8" + "&rewriteBatchedStatements=true","root","root");
//4.定義sql語句
String sql = "insert into user values(default,?,?)";
//5.擷取執行sql的對象PreparedStatement
pstmt = conn.prepareStatement(sql);
//6.不斷産生sql
for (int i = 0; i < 10000000; i++) {
pstmt.setString(1,(int)(Math.random()*1000000)+"");
pstmt.setString(2,(int)(Math.random()*1000000)+"");
pstmt.addBatch();
}
//7.往資料庫插入一次資料
pstmt.executeBatch();
System.out.println("添加10000000條資訊成功!");
} catch (SQLException e) {
e.printStackTrace();
} finally {
//8.釋放資源
//避免空指針異常
if(pstmt != null) {
try {
pstmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
}
}
我們剛開始的表結構是沒有索引的,如果現在我們執行下建立索引呢?

這裡感覺自己的控制台有點少女心啊。。。O(∩_∩)O哈哈~
我們可以看到建立索引的時候花了17秒,為什麼這麼慢呢?
這裡有個問題?為什麼查詢相對增删改速度較快呢?我們插入了1000w的資料
後續的時候我們在說,現在看下查詢和更新的速度?該問題未複現出來,隻能原理來說下了囧,有知道的小夥伴可以私信說下
當我們插入/删除一條資料庫的時候:
1.将該條資料插入/删除表中->同時需要維護新的索引數,因為插入的值導緻了索引值變化了,是以需要 重新建構。需要同時維護的。因為如果不維護的話可能會導緻根據索引查詢不到值得,導緻可能報錯。(這裡建議可以的話使用邏輯删除,不要使用實體删除,因為實體删除需要再次維護索引)
2.當我們查詢某一條資料的時候,隻需要查詢,但是不會涉及索引。
2.索引的優勢和劣勢
優勢 | 劣勢 |
---|---|
提高了檢索的效率,降低了資料庫IO | 索引也是一張表,索引也是需要占用空間的 |
降低了資料排序的成本,降低了CPU的消耗 | 提高了查詢速度,但是降低了更新表速度,因為索引位置也需要改變 |
索引的類型
類型 | 建立語句 |
---|---|
單值索引 | create index indexName on tableName(col);alter tableName add index indexName on (col) |
唯一索引 | create unique index indexName on tableName(col) |
複合索引 | create index indexName on tableName(col1,col2) |
全文索引(用于全文檢索) | create fulltext index indexName on tableName(col) |
檢視索引 | show index from tableName |
4.mysql的索引結構
1.BTree索引
2.Hash索引
3.full-text全文索引
4.R-Tree索引
這裡着重介紹BTree索引
系統從磁盤讀取資料到記憶體時是以磁盤塊(block)為基本機關的,位于同一個磁盤塊中的資料會被一次性讀取出來,而不是需要什麼取什麼。
InnoDB存儲引擎中有頁(Page)的概念,頁是其磁盤管理的最小機關。InnoDB存儲引擎中預設每個頁的大小為16KB,可通過參數innodb_page_size将頁的大小設定為4K、8K、16K,在MySQL中可通過如下指令檢視頁的大小:
show variables like 'innodb_page_size';
上圖是一個BTree索引樹,那是怎麼查詢的資料的呢?(這裡以查找29為例)
首先将磁盤1讀取進記憶體,進行了【磁盤I/O操作】,在記憶體中利用二分查找,
發現29在17和35之間,然後就找到位址指針P2,然後根據P2讀取磁盤3到記憶體中,進行了【磁盤I/O操作】,
在記憶體中利用二分查找,發現29在26和30之間,然後就找到位址指針P2,
然後根據P2讀取磁盤8到記憶體中,利用二分查找找到了。
但是上面的BTree是否存在問題呢?
我們可以看到在每個磁盤都存了data,如果data非常大的話則一層也不能存儲很多的資料,當資料量較大的時候,會導緻數的層次會比較深,也會導緻磁盤的I/O會增多。這時就引入了一個炸天的B+Tree樹了。
B+Tree相對BTree樹主要是以下不同
非葉子節點隻存儲鍵值資訊。
所有葉子節點之間都有一個鍊指針。
資料記錄都存放在葉子節點中。
在說B+Tree樹之前,我們再說下下面幾種樹吧,實際心裡是不想說的,嘿嘿
二叉樹:
二叉樹具有以下性質:左子樹的鍵值小于根的鍵值,右子樹的鍵值大于根的鍵值。那這樣的二叉樹作為索引結構有啥問題呢?失衡,因為如果一直比根節點大下去則會I/O也會非常大。
那就需要引入平衡二叉樹(在符合二叉查找樹的條件下,還滿足任何節點的兩個子樹的高度最大差為1。)
如果在AVL樹中進行插入或删除節點,可能導緻AVL樹失去平衡,這種失去平衡的二叉樹可以概括為四種姿态:LL(左左)、RR(右右)、LR(左右)、RL(右左)。它們的示意圖如下:
姿态 | 原因 | 怎麼平衡 |
---|---|---|
LL(左左) | 當插入1的時候,我們從左子樹數可以看到有三層,但是右子樹隻有一層,兩者高度差為2 | 以失衡點4位中心點旋轉作為新的根節點,将4的右節點6作為原根節點8的左節點,然後作為新根節點4的右節點 |
RR(右右) | 當插入13的時候,我們從右子樹數可以看到有三層,但是左子樹隻有一層,兩者高度差為2 | 以失衡點12位中心點旋轉作為新的根節點,将12的左節點10作為原根節點8的右節點,然後作為新根節點4的左節點 |
LR(左右) | 當插入5的時候,我們從左子樹數可以看到有三層,但是右子樹隻有一層,兩者高度差為2 | 首先RR單轉在LL單轉:首先對4節點進行RR單轉,5變成4的右節點,然後4作為6的左節點,在進行LL單轉,将6作為新根節點,然後8和12連接配接 |
RL(右左) | 當插入9的時候,我們從右子樹數可以看到有三層,但是左子樹隻有一層,兩者高度差為2 | 首先LL單轉在RR單轉:将10作為新失衡點的根節點,然後将10作為新的根節點 |
那B+Tree呢?
通常在B+Tree上有兩個頭指針,一個指向根節點,另一個指向關鍵字最小的葉子節點,
而且所有葉子節點(即資料節點)之間是一種鍊式環結構。
是以可以對B+Tree進行兩種查找運算:一種是對于主鍵的範圍查找和分頁查找,另一種是從根節點開始,進行随機查找。
都講到這裡我們就在說下紅黑樹
紅黑樹是一種含有紅黑結點并能自平衡的二叉查找樹。它必須滿足下面性質:
性質1:每個節點要麼是黑色,要麼是紅色。
性質2:根節點是黑色。
性質3:每個葉子節點(NIL)是黑色。
性質4:每個紅色結點的兩個子結點一定都是黑色。
性質5:任意一結點到每個葉子結點的路徑都包含數量相同的黑結點。
這裡不懂的千萬别問樓主,因為樓主知道也不會說的,哈哈
更多内容已上傳公衆号【那條轉彎的路】