最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

MySQL索引的原理與性能優(yōu)化設計教程(圖文代碼)

 更新時間:2026年01月17日 08:43:59   作者:中環(huán)留念  
本文詳細介紹了索引的分類、功能和實現(xiàn)方式,包括主鍵索引、唯一索引、常規(guī)索引、全文索引以及聚簇索引和非聚簇索引,文章還探討了索引設計的最佳實踐,包括主鍵選擇、索引覆蓋等優(yōu)化策略,為數(shù)據(jù)庫性能優(yōu)化提供了理論基礎

一、前言

索引是一種用于快速查詢和檢索數(shù)據(jù)的數(shù)據(jù)結構,其本質(zhì)可以看成是一種排序好的數(shù)據(jù)結構。

索引的作用就相當于書的目錄。打個比方:我們在查字典的時候,如果沒有目錄,那我們就只能一頁一頁地去找我們需要查的那個字,速度很慢;如果有目錄了,我們只需要先去目錄里查找字的位置,然后直接翻到那一頁就行了。

索引底層數(shù)據(jù)結構存在很多種類型,常見的索引結構有:B 樹、 B+ 樹 和 Hash、紅黑樹。在 MySQL 中,無論是 Innodb 還是 MyISAM,都使用了 B+ 樹作為索引結構。

二、索引類型劃分

按照數(shù)據(jù)結構維度劃分:

  • BTree 索引:MySQL 里默認和最常用的索引類型。只有葉子節(jié)點存儲 value,非葉子節(jié)點只有指針和 key。存儲引擎 MyISAM 和 InnoDB 實現(xiàn) BTree 索引都是使用 B+Tree,但二者實現(xiàn)方式不一樣(前面已經(jīng)介紹了)。

  • 哈希索引:類似鍵值對的形式,一次即可定位。

  • RTree 索引:一般不會使用,僅支持 geometry 數(shù)據(jù)類型,優(yōu)勢在于范圍查找,效率較低,通常使用搜索引擎如 ElasticSearch 代替。

  • 全文索引:對文本的內(nèi)容進行分詞,進行搜索。目前只有 CHAR、VARCHARTEXT 列上可以創(chuàng)建全文索引。一般不會使用,效率較低,通常使用搜索引擎如 ElasticSearch 代替。

按數(shù)據(jù)結構維度劃分的索引類型本文不做詳細介紹,本文主要針對以下兩種分類做闡述

按“功能/約束”分類:主鍵索引、唯一索引、常規(guī)索引、全文索引

分類含義特點關鍵字
主鍵索引針對于表中主鍵創(chuàng)建的索引默認自動創(chuàng)建, 只能有一個PRIMARY
唯一索引避免同一個表中某數(shù)據(jù)列中的值重復可以有多個UNIQUE
常規(guī)索引快速定位特定數(shù)據(jù)可以有多個
全文索引全文索引查找的是文本中的關鍵詞,而不是比較索引中的值可以有多個FULLTEXT

按“存儲形式/數(shù)據(jù)組織方式”分類:聚集索引(Clustered)、二級索引(Secondary)

分類含義特點
聚集索引(Clustered Index)將數(shù)據(jù)存儲與索引放到了一塊,索引結構的葉子節(jié)點保存了行數(shù)據(jù)必須有,而且只有一個
二級索引(Secondary Index)將數(shù)據(jù)與索引分開存儲,索引結構的葉子節(jié)點關聯(lián)的是對應的主鍵可以存在多個

三、按功能/約束分類

1.主鍵索引(PRIMARY KEY)

定義

  • 表的“主鍵”對應的索引,MySQL 用它來唯一標識一行數(shù)據(jù)。

  • 一張表 只能有一個主鍵,主鍵列 不能為 NULL,并且 必須唯一。

InnoDB 特點

  • InnoDB 中 主鍵索引 = 聚集索引(后面會解釋聚集索引是什么)。

  • 也就是說:數(shù)據(jù)行本身就“存”在主鍵索引的 B+Tree 葉子節(jié)點里。

適用場景

  • 絕大多數(shù)表都應該設計主鍵:自增 id、雪花 id、UUID(不推薦隨機 UUID 做主鍵,容易導致頁分裂/碎片)。

  • 必須為表指定主鍵(如無顯式定義,InnoDB 會自動生成隱藏主鍵)。

  • 常用于 WHERE user_id = 1001 或聯(lián)表查詢。

CREATE TABLE users (
  id INT PRIMARY KEY,  -- 主鍵索引
  username VARCHAR(50)
);

2.唯一索引(UNIQUE)

定義

  • 約束某列/多列的值必須唯一。

  • 限制列值 不能重復(但大多數(shù)情況下允許 NULL,且多個 NULL 在 MySQL/InnoDB 中通常是允許的)。

  • 一張表可以有多個唯一索引。

底層實現(xiàn)

  • InnoDB 下通常也是 B+Tree。

  • 與普通索引的核心差別:寫入時會做 唯一性校驗

典型用途

  • 既是“約束”(保證不重復),也是“加速器”(加速查詢)

  • 常用于:手機號、郵箱、業(yè)務唯一編號

  • 用戶表 username、email;業(yè)務表的唯一業(yè)務號(如 order_no)。

CREATE TABLE users (
  id INT PRIMARY KEY,
  mobile VARCHAR(20) UNIQUE,  -- 唯一索引
  email VARCHAR(50) UNIQUE
);

3.常規(guī)索引(普通索引 / INDEX)

定義

  • 最基本的索引,只用于加速查詢,沒有唯一性約束。

底層實現(xiàn)

  • InnoDB:一般是 B+Tree 二級索引(后面會講“二級索引”)。

特點

  • 最常用:按條件查、排序、范圍查詢、JOIN

  • 可以是單列索引,也可以是聯(lián)合索引(復合索引)

用途

  • 頻繁作為 WHERE 條件、JOIN 條件、ORDER BYGROUP BY 的列。

  • 支持 WHERE status = 'paid' 或 ORDER BY create_time。

例子:單列索引

ALTER TABLE user ADD INDEX idx_name(name);

例子:聯(lián)合索引

ALTER TABLE user ADD INDEX idx_name_phone(name, phone);

查詢:

SELECT * FROM user WHERE name='Tom' AND phone='138...';

?? 更容易走 (name, phone) 的聯(lián)合索引。

4.全文索引(FULLTEXT)

定義

  • InnoDB 從 MySQL 5.6 開始支持 FULLTEXT(歷史上 MyISAM 更早支持)。

  • 適合:分詞 + 相關性排序

  • 用來做“文本檢索”,支持對長文本按詞(或按分詞)搜索,例如 MATCH(col) AGAINST(...)。

實現(xiàn)與特點

  • InnoDB 的 FULLTEXT 是專門的倒排索引體系(不是 B+Tree)。

  • 更適合:文章、評論、商品描述等“文本搜索”。

  • 注意:中文檢索通常需要分詞支持(MySQL 原生能力有限,很多場景會用 Elasticsearch 等專用搜索引擎)。

例子

CREATE TABLE article (
  id BIGINT PRIMARY KEY,
  title VARCHAR(200),
  content TEXT,
  FULLTEXT KEY ft_content(content)
) ENGINE=InnoDB;

查詢:

SELECT * FROM article
WHERE MATCH(content) AGAINST('mysql 索引' IN NATURAL LANGUAGE MODE);

四、按“存儲形式/數(shù)據(jù)組織方式”分類

1.聚簇索引(聚集索引)

聚簇索引:在 InnoDB 存儲引擎中,聚簇索引通常就是主鍵索引 。聚簇索引的特點是數(shù)據(jù)與索引一體化存儲,即數(shù)據(jù)行(整行,不是指針)直接存儲在索引的葉子節(jié)點中,并且數(shù)據(jù)按照主鍵的順序進行物理存儲 。這使得聚簇索引在查詢時具有極高的效率,尤其是對于主鍵查詢和范圍查詢。因為數(shù)據(jù)是按照主鍵順序存儲的,所以在進行范圍查詢(如查詢 ID 在某個范圍內(nèi)的用戶)時,可以利用索引的有序性,快速定位到滿足條件的數(shù)據(jù)。此外,聚簇索引還能利用順序檢測預取機制,提高數(shù)據(jù)讀取的效率。例如,在一個用戶表中,以用戶 ID 為主鍵創(chuàng)建聚簇索引,當查詢用戶 ID 為 100 的用戶信息時,數(shù)據(jù)庫可以直接通過聚簇索引找到對應的葉子節(jié)點,獲取用戶信息,無需進行額外的查找操作。需要注意的是,一張表只能有一個聚簇索引,因為數(shù)據(jù)的物理存儲順序只能有一種。

概括:用主鍵查 = 直接定位到葉子節(jié)點 = 一次 B+Tree 查找拿到整行

為什么叫“聚集”

  • 因為數(shù)據(jù)行與索引鍵“聚在一起”,數(shù)據(jù)就是索引的一部分。

聚集索引選取規(guī)則:

  • 如果存在主鍵,主鍵索引就是聚集索引。

  • 如果不存在主鍵,將使用第一個唯一(UNIQUE)索引作為聚集索引。

  • 如果表沒有主鍵,或沒有合適的唯一索引,則InnoDB會自動生成一個rowid作為隱藏的聚集索引。

聚簇索引的優(yōu)缺點:

優(yōu)點

  • 查詢速度非???/strong>:聚簇索引的查詢速度非常的快,因為整個 B+ 樹本身就是一顆多叉平衡樹,葉子節(jié)點也都是有序的,定位到索引的節(jié)點,就相當于定位到了數(shù)據(jù)。相比于非聚簇索引, 聚簇索引少了一次讀取數(shù)據(jù)的 IO 操作。

  • 對排序查找和范圍查找優(yōu)化:聚簇索引對于主鍵的排序查找和范圍查找速度非???。

缺點

  • 依賴于有序的數(shù)據(jù):因為 B+ 樹是多路平衡樹,如果索引的數(shù)據(jù)不是有序的,那么就需要在插入時排序,如果數(shù)據(jù)是整型還好,否則類似于字符串或 UUID 這種又長又難比較的數(shù)據(jù),插入或查找的速度肯定比較慢。

  • 更新代價大:如果對索引列的數(shù)據(jù)被修改時,那么對應的索引也將會被修改,而且聚簇索引的葉子節(jié)點還存放著數(shù)據(jù),修改代價肯定是較大的,所以對于主鍵索引來說,主鍵一般都是不可被修改的。

2.非聚簇索引

也稱為二級索引,其索引存儲的是主鍵值,而不是實際的數(shù)據(jù)行 。當使用非聚簇索引進行查詢時,首先會根據(jù)索引找到對應的主鍵值,然后再通過主鍵值在聚簇索引中查找實際的數(shù)據(jù)行(整行),這個過程稱為回表查詢 。非聚簇索引支持多列組合索引,適用于多個字段聯(lián)合查詢的場景。例如,在一個訂單表中,經(jīng)常需要根據(jù)客戶 ID 和訂單日期進行查詢,可以為客戶 ID 和訂單日期創(chuàng)建組合非聚簇索引。雖然非聚簇索引需要回表查詢,查詢效率相對聚簇索引略低,但在某些情況下,它可以提供更靈活的查詢方式。比如,在查詢訂單表中某個客戶在特定日期之后的訂單時,通過組合非聚簇索引可以快速定位到滿足條件的主鍵值,然后再通過回表查詢獲取完整的訂單信息。

概括:二級索引的葉子節(jié)點存的不是整行,而是“索引列 + 主鍵值”。

覆蓋索引(避免回表)

  • 如果查詢需要的列 都在二級索引里(或索引里包含它們),那就不需要回表,這叫 覆蓋索引。

  • 例如:select name from user where age=20;

    • 若建了 (age, name) 聯(lián)合索引,就可能直接從索引葉子拿到 name,無需回表。

非聚簇索引的優(yōu)缺點:

優(yōu)點

更新代價比聚簇索引要小。非聚簇索引的更新代價就沒有聚簇索引那么大了,非聚簇索引的葉子節(jié)點是不存放數(shù)據(jù)的。

缺點

  • 依賴于有序的數(shù)據(jù):跟聚簇索引一樣,非聚簇索引也依賴于有序的數(shù)據(jù)。

  • 可能會二次查詢(回表):這應該是非聚簇索引最大的缺點了。當查到索引對應的指針或主鍵后,可能還需要根據(jù)指針或主鍵再到數(shù)據(jù)文件或表中查詢。

五、圖解

1.示例表結構

CREATE TABLE account_example (
  id INT PRIMARY KEY AUTO_INCREMENT COMMENT '賬戶ID',
  name VARCHAR(20) COMMENT '姓名',
  money DOUBLE(10,2) COMMENT '余額',
  INDEX idx_name (name),
  INDEX idx_name_money (name, money)
) ENGINE=InnoDB;
?
-- 插入數(shù)據(jù)
insert into account_example(id, name , money)
values
(1, '張三', 100.00),
(3, '李四', 200.00),
(7, '王五', 300.00);

id主鍵索引(聚簇索引)

idx_name(name)普通二級索引

idx_name_money(name, money)→ 聯(lián)合索引

2.聚簇索引(id)B+Tree 示意圖:

聚簇索引的B+Tree 的葉子節(jié)點存放的是整行數(shù)據(jù)。

特點總結

  • 一張表 只能有一個聚集索引

  • 數(shù)據(jù)行 按主鍵順序物理存儲

  • 使用主鍵查詢:

SELECT * FROM account WHERE id = 3;

?? 一次 B+Tree 查找即可拿到整行數(shù)據(jù),不存在回表

3.非聚簇索引(idx_name)的 B+Tree 示意圖:

非聚簇索引的葉子節(jié)點中:不存整行數(shù)據(jù),只存「索引列值 + 主鍵值」

二級索引的葉子節(jié)點下掛的是該字段值對應的主鍵值。

4.為什么會發(fā)生回表

示例 SQL(會回表)

SELECT * FROM account WHERE name = '李四';

執(zhí)行過程拆解

Step 1:通過二級索引 idx_name 查找

name='李四'
   ↓
在 idx_name B+Tree 中定位
   ↓
得到主鍵 id = 3

Step 2:根據(jù)主鍵回到聚集索引

id=3
   ↓
在 PRIMARY KEY B+Tree 中查找
   ↓
獲取完整行數(shù)據(jù)

?? 這一步稱為:回表

本質(zhì)原因:二級索引不存完整數(shù)據(jù)

5.聯(lián)合索引 idx(name, money) 的存儲結構

聯(lián)合索引葉子節(jié)點存:(name, money) + id

idx_name_money(name, money) B+Tree 示意圖:

6.覆蓋索引 vs 回表

? 示例 1:需要回表

SELECT * FROM account
WHERE name = '李四';
  • 使用 idx_name

  • money 不在索引中

  • 必須回表

? 示例 2:覆蓋索引(不回表)

SELECT name, money
FROM account
WHERE name = '李四';
  • 使用 idx_name_money

  • 查詢字段 全部存在索引葉子節(jié)點

  • 無需回表

?? 這就叫:覆蓋索引(Covering Index)

7.總結

場景是否回表原因
where id = ??聚集索引葉子節(jié)點存整行
普通二級索引查 *?二級索引不存完整數(shù)據(jù)
聯(lián)合索引覆蓋查詢字段?查詢字段都在索引中
SELECT *幾乎一定字段太多,無法覆蓋

六、關聯(lián)

功能分類在 InnoDB 的存儲形式
主鍵索引聚集索引(葉子存整行)
唯一索引通常是 二級索引(除非它被選為聚集索引鍵)
常規(guī)索引二級索引
全文索引倒排索引體系(不按聚集/二級的 B+Tree 邏輯走)

七、問題

主鍵為什么不要用隨機值(如隨機 UUID)?

  • 聚集索引決定了數(shù)據(jù)行的物理組織順序

  • 隨機插入會導致頻繁頁分裂、碎片、寫放大,性能更差 (自增/有序主鍵插入更“順滑”)

二級索引為什么存主鍵值,而不是物理地址?

  • 因為 InnoDB 的數(shù)據(jù)行會移動/頁會分裂,存物理地址維護成本高

  • 存主鍵值更穩(wěn)定,代價是可能需要回表

建索引的常見收益點

  • 加速 WHEREJOIN、ORDER BY、GROUP BY

  • 利用覆蓋索引減少回表、減少 IO

八、總結

  • InnoDB 中,主鍵索引就是聚集索引,數(shù)據(jù)行存放在主鍵 B+Tree 的葉子節(jié)點;

  • 二級索引的葉子節(jié)點只保存索引列和主鍵值,因此在查詢非索引字段時需要回表;

  • 當查詢字段完全被索引覆蓋時,可以避免回表,從而顯著提升查詢性能。

到此這篇關于MySQL索引的原理與性能優(yōu)化教程的文章就介紹到這了,更多相關索引設計優(yōu)化內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • MySQL的字符集操作命令總結

    MySQL的字符集操作命令總結

    這篇文章主要介紹了MySQL的字符集操作命令總結,包括各種查看數(shù)據(jù)庫、數(shù)據(jù)表等查詢命令,需要的朋友可以參考下
    2014-04-04
  • MySQL事務的四種特性總結

    MySQL事務的四種特性總結

    事務就是一組DML語句組成,這些語句在邏輯上存在相關性,這一組DML語句要么全部成功,要么全部失敗,是一個整體,一個 MySQL 數(shù)據(jù)庫,可不止你一個事務在運行,所以一個完整的事務,絕對不是簡單的 sql 集合,本文就給大家總結一下MySQL事務的四種特性
    2023-08-08
  • MySQL中的臟讀與幻讀使用及說明

    MySQL中的臟讀與幻讀使用及說明

    MySQL通過事務隔離級別(如REPEATABLEREAD)和鎖機制(共享/排他鎖)解決臟讀與幻讀問題,結合MVCC與Next-KeyLocks優(yōu)化并發(fā)一致性,合理配置可平衡性能與數(shù)據(jù)可靠性
    2025-08-08
  • MySQL之修改數(shù)據(jù)表存儲引擎的三種方式

    MySQL之修改數(shù)據(jù)表存儲引擎的三種方式

    這篇文章主要介紹了MySQL之修改數(shù)據(jù)表存儲引擎的三種方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-11-11
  • 更改Mysql root用戶密碼

    更改Mysql root用戶密碼

    這篇文章主要介紹了更改Mysql root用戶密碼的相關資料,需要的朋友可以參考下
    2016-03-03
  • MySQL查詢?nèi)哂嗨饕臀词褂眠^的索引操作

    MySQL查詢?nèi)哂嗨饕臀词褂眠^的索引操作

    這篇文章主要介紹了MySQL查詢?nèi)哂嗨饕臀词褂眠^的索引操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-03-03
  • Mysql?for?update導致大量行鎖的問題

    Mysql?for?update導致大量行鎖的問題

    這篇文章主要介紹了Mysql?for?update?導致大量行鎖的問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-08-08
  • MySQL?半同步復制的實現(xiàn)

    MySQL?半同步復制的實現(xiàn)

    半同步復制是MySQL復制的一種形式,它結合了異步復制和同步復制的特性,本文主要介紹了?MySQL?半同步復制的實現(xiàn),具有一定的參考價值,感興趣的可以了解一下
    2024-09-09
  • 解析SQL Server 視圖、數(shù)據(jù)庫快照

    解析SQL Server 視圖、數(shù)據(jù)庫快照

    在程序開發(fā)過程中,任何一個項目都離不開數(shù)據(jù)庫,這篇文章給大家詳細介紹SQL Server 視圖、數(shù)據(jù)庫快照相關內(nèi)容,需要的朋友可以參考下
    2015-08-08
  • 如何使用mysql查詢24小時數(shù)據(jù)

    如何使用mysql查詢24小時數(shù)據(jù)

    在進行實時數(shù)據(jù)處理時,我們常常需要查詢最近24小時的數(shù)據(jù)來進行分析和處理,下面我們將介紹如何使用MySQL查詢最近24小時的數(shù)據(jù),需要的朋友可以參考下
    2023-07-07

最新評論

万荣县| 津南区| 中山市| 辽宁省| 蕉岭县| 双流县| 巍山| 松江区| 闽清县| 赫章县| 长寿区| 东安县| 莱阳市| 越西县| 喜德县| 黎川县| 苍梧县| 吉首市| 池州市| 伊春市| 襄垣县| 香港| 永春县| 枝江市| 阜城县| 松潘县| 汉寿县| 通榆县| 陇川县| 喀喇| 益阳市| 壶关县| 西林县| 灌南县| 棋牌| 敦煌市| 沅陵县| 高雄县| 岳阳县| 贵南县| 孟津县|