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

MySQL索引用法實(shí)戰(zhàn)指南

 更新時(shí)間:2026年03月07日 14:48:42   作者:0xDevNull  
本文詳細(xì)介紹了MySQL索引的使用方法,包括索引的原理、類型、設(shè)計(jì)原則、優(yōu)化技巧以及常見問題,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧

一、為什么要用索引?—— 先講個(gè)血淚故事

想象你去圖書館找一本《MySQL從入門到入土》:

沒有索引的情況(全表掃描):

你從第一排書架開始,一本一本翻,看到《西游記》...《三體》...《Java編程思想》... 翻了3個(gè)小時(shí),終于在第5000本書里找到了。這時(shí)候你已經(jīng)想"從入門到放棄"了。

有索引的情況

你去電腦查一下,系統(tǒng)告訴你"在第3區(qū)第5架第2層",你2分鐘就拿到的書,還能順便借本《Redis深度歷險(xiǎn)》。

數(shù)據(jù)庫也是這個(gè)道理。 沒有索引,MySQL就要一行一行地"翻書";有了索引,直接"導(dǎo)航定位"。

真實(shí)數(shù)據(jù)說話: 假設(shè)你有100萬條用戶數(shù)據(jù),查 WHERE phone = '13800138000'

情況耗時(shí)磁盤IO
無索引幾秒~幾十秒掃描100萬行
有索引幾毫秒可能只需3-5次IO

索引的本質(zhì):用空間換時(shí)間,用寫性能換讀性能。

Tip: 在數(shù)據(jù)量小的時(shí)候,盡量不要使用索引

二、索引的原理——B+樹到底是個(gè)啥?

別被"B+樹"這個(gè)名字嚇到,它其實(shí)就是個(gè) "很會(huì)做排序的多叉樹"

2.1 為什么不用其他結(jié)構(gòu)?

結(jié)構(gòu)為什么MySQL不用缺點(diǎn)
哈希表Hash索引只能精確匹配,不能范圍查詢(> < BETWEEN),不能排序
二叉樹高度太高100萬數(shù)據(jù),樹高20層,查一次要20次磁盤IO,慢死
B樹B+樹的哥哥數(shù)據(jù)存在非葉子節(jié)點(diǎn),浪費(fèi)空間,范圍查詢麻煩

2.2 B+樹長什么樣?(簡化版)

                  [10 | 30 | 50]          ← 根節(jié)點(diǎn)(只存鍵值,不存數(shù)據(jù))
                   /    |    \
            [5|10]  [20|30]  [40|50|60]    ← 非葉子節(jié)點(diǎn)(還是只存鍵值)
            /   \    /   \    /   \   \
    [1,2,3,4,5] [10,11] [20,25] [30,35] [40,45] [50,55] [60,65]  ← 葉子節(jié)點(diǎn)(存真實(shí)數(shù)據(jù)/指針)
    所有葉子節(jié)點(diǎn)用鏈表相連:1→2→3→4→5→10→11→20→25→30→35...

B+樹的三大殺手锏:

  1. 矮胖設(shè)計(jì):一個(gè)節(jié)點(diǎn)存很多鍵(InnoDB默認(rèn)16KB一頁),1000萬數(shù)據(jù)可能只有3-4層,查一次最多3-4次IO
  2. 數(shù)據(jù)都在葉子節(jié)點(diǎn):非葉子節(jié)點(diǎn)只存"導(dǎo)航信息",一頁能存更多鍵,樹更矮
  3. 葉子節(jié)點(diǎn)鏈表連接:范圍查詢(BETWEEN>、<)直接順著鏈表走,不用回樹上層

2.3 聚簇索引 vs 非聚簇索引(重點(diǎn)?。?/h3>

聚簇索引(Clustered Index)—— 數(shù)據(jù)本身:

  • 葉子節(jié)點(diǎn)存的就是完整的行數(shù)據(jù)
  • InnoDB表必須有,且只有一個(gè)
  • 默認(rèn)主鍵就是聚簇索引;沒主鍵就用第一個(gè)唯一索引;再?zèng)]有就隱式生成6字節(jié)的row_id
聚簇索引查找:
[找主鍵10] → 直接定位到葉子節(jié)點(diǎn) → 拿到完整數(shù)據(jù)(id=10, name='張三', age=20...)

非聚簇索引(Secondary Index)—— 數(shù)據(jù)的"快遞單號(hào)":

  • 葉子節(jié)點(diǎn)存的是索引列 + 主鍵值
  • 查到后還要拿主鍵去聚簇索引查一次完整數(shù)據(jù)(叫"回表")
非聚簇索引查找:
[找name='張三'] → 葉子節(jié)點(diǎn)拿到(id=10) → 再去聚簇索引查id=10的完整數(shù)據(jù)

對(duì)比:

聚簇索引(主鍵id)          非聚簇索引(name列)
    [1]                    ['Alice'] → id=1
   /   \                   ['Bob']   → id=2
 [1]   [2]                 ['Carol'] → id=3
 /       \                 
數(shù)據(jù)行1  數(shù)據(jù)行2            查到'Bob'后,拿id=2去聚簇索引找完整數(shù)據(jù)(回表)

三、索引的用法——實(shí)戰(zhàn)指南

3.1 索引類型全家福

-- 1. 主鍵索引(自動(dòng)創(chuàng)建,聚簇索引)
CREATE TABLE user (
    id INT PRIMARY KEY AUTO_INCREMENT,  -- 這就是主鍵索引
    name VARCHAR(50),
    phone VARCHAR(20)
);
-- 2. 唯一索引(值不能重復(fù),允許NULL)
CREATE UNIQUE INDEX uk_phone ON user(phone);
-- 3. 普通索引(最常用)
CREATE INDEX idx_name ON user(name);
-- 4. 組合索引(多列聯(lián)合,最左前綴原則!)
CREATE INDEX idx_name_age ON user(name, age);
-- 5. 全文索引(MySQL 5.6+,用于文本搜索)
CREATE FULLTEXT INDEX idx_content ON article(content);
-- 6. 前綴索引(省空間,用于長字符串)
CREATE INDEX idx_email ON user(email(10));  -- 只索引前10個(gè)字符

3.2 組合索引的最左前綴原則(面試必問?。?/h3>

創(chuàng)建 INDEX idx_a_b_c (a, b, c),相當(dāng)于建了3個(gè)索引:

  • (a)
  • (a, b)
  • (a, b, c)

能用上索引的查詢:

WHERE a = 1              -- ? 用到了idx_a_b_c的a部分
WHERE a = 1 AND b = 2    -- ? 用到了a和b
WHERE a = 1 AND b = 2 AND c = 3  -- ? 完美,全用上
WHERE a = 1 AND c = 3    -- ? 只用到了a(c跳過了b,斷了)

用不上索引的查詢(踩坑預(yù)警):

WHERE b = 2              -- ? 沒a,最左缺失
WHERE b = 2 AND c = 3    -- ? 沒a
WHERE a = 1 OR b = 2     -- ? OR導(dǎo)致索引失效(除非兩邊都有索引)
WHERE a LIKE '%xxx'      -- ? 前導(dǎo)模糊,索引失效

記憶口訣:最左優(yōu)先,中間不斷,范圍停步。

3.3 索引下推(Index Condition Pushdown, ICP)

MySQL 5.6+的優(yōu)化,在存儲(chǔ)引擎層就過濾數(shù)據(jù),減少回表。

-- 有索引 idx_name_age(name, age)
SELECT * FROM user WHERE name LIKE '張%' AND age = 20;
-- 老版本:先找到所有姓張的,回表查age,再過濾
-- 5.6+:在索引里就直接判斷age=20,只回表符合條件的數(shù)據(jù)

3.4 覆蓋索引(Covering Index)—— 不回表的神技

如果查詢的列都在索引里,直接返回,不用回表查聚簇索引。

-- 有索引 idx_name_age(name, age)
SELECT name, age FROM user WHERE name = '張三';
-- ? 覆蓋索引!索引里就有name和age,直接返回,速度飛起
SELECT * FROM user WHERE name = '張三';
-- ? 需要回表,因?yàn)樗饕餂]有其他列(如phone、address等)

設(shè)計(jì)技巧: 經(jīng)常一起查的字段,考慮建組合索引或加入索引。

四、提升效率——索引優(yōu)化實(shí)戰(zhàn)

4.1 EXPLAIN命令——索引優(yōu)化的"體檢報(bào)告"

EXPLAIN SELECT * FROM user WHERE phone = '13800138000';

關(guān)鍵字段解讀:

字段含義優(yōu)化目標(biāo)
type訪問類型至少range,最好refconst,避免ALL(全表掃描)
possible_keys可能用的索引看有沒有合適的索引
key實(shí)際用的索引NULL就是沒用索引,悲劇
rows估計(jì)掃描行數(shù)越小越好
Extra額外信息Using index(覆蓋索引,好)Using filesort(需要排序,壞)Using temporary(用了臨時(shí)表,壞)

type性能排序(從好到壞):

system > const > eq_ref > ref > range > index > ALL
  ↓       ↓        ↓       ↓      ↓       ↓     ↓
最快   主鍵/唯一  聯(lián)表主鍵  普通索引 范圍掃描  索引掃描 全表掃描

4.2 索引設(shè)計(jì)的"三要三不要"

三要:

1.要建在WHERE、JOIN、ORDER BY、GROUP BY的列上

-- 經(jīng)常這樣查?
SELECT * FROM order WHERE user_id = 100 AND status = 1 ORDER BY create_time;
-- 考慮:INDEX idx_user_status_time(user_id, status, create_time)

2.要高選擇性的列放前面

-- 性別(只有男女)選擇性低,放后面
-- 手機(jī)號(hào)(幾乎唯一)選擇性高,放前面
CREATE INDEX idx_phone_gender ON user(phone, gender);  -- ? 好
CREATE INDEX idx_gender_phone ON user(gender, phone);  -- ? 差,gender區(qū)分度太低

3.要利用覆蓋索引減少回表

-- 如果經(jīng)常只查name和email
CREATE INDEX idx_name_email ON user(name, email);
SELECT name, email FROM user WHERE name = 'xxx';  -- 覆蓋索引,不回表

三不要:

1.不要在低選擇性列上建單列索引

-- 性別字段只有0和1,建索引后MySQL可能直接全表掃描
SELECT * FROM user WHERE gender = 1;  -- 可能走可能不走,看數(shù)據(jù)分布

2.不要對(duì)索引列做函數(shù)或運(yùn)算

WHERE YEAR(create_time) = 2023   -- ? 函數(shù)導(dǎo)致索引失效
WHERE create_time >= '2023-01-01' AND create_time < '2024-01-01'  -- ? 范圍查詢
WHERE id + 1 = 100  -- ? 運(yùn)算導(dǎo)致失效
WHERE id = 99       -- ? 直接比較

3.不要建太多索引(寫操作會(huì)哭)

    • 每個(gè)索引都是一棵B+樹,插入/更新/刪除時(shí)要維護(hù)所有索引
    • 建議:單表索引不超過5個(gè),組合索引列不超過5個(gè)

4.3 索引失效的常見坑(排雷手冊(cè))

-- 1. 前導(dǎo)模糊查詢
WHERE name LIKE '%張%'   -- ? 失效
WHERE name LIKE '張%'    -- ? 有效(用到索引的name部分)
-- 2. 隱式類型轉(zhuǎn)換
WHERE phone = 13800138000  -- ? phone是字符串,數(shù)字會(huì)轉(zhuǎn)換,索引失效
WHERE phone = '13800138000' -- ? 正確
-- 3. 不等于、NOT IN(可能失效,看數(shù)據(jù)分布)
WHERE status != 0   -- 數(shù)據(jù)量大時(shí)可能全表掃描
-- 4. IS NULL vs IS NOT NULL(看列是否允許NULL)
-- 如果列NOT NULL,IS NULL直接返回空,很快
-- 如果列允許NULL,IS NOT NULL可能掃描大量數(shù)據(jù)
-- 5. OR條件(兩邊都要有索引)
WHERE id = 1 OR name = '張三'  
-- 如果只有id有索引,name沒索引,可能全表掃描
-- 解決:分別查詢UNION,或給name也建索引

4.4 大表優(yōu)化策略

場景:千萬級(jí)用戶表,查詢慢

  1. 分頁優(yōu)化(深分頁問題)
-- 慢:OFFSET越大越慢,需要排序后跳過前面1000000條
SELECT * FROM user ORDER BY id LIMIT 1000000, 10;
-- 快:先查id,再JOIN(利用覆蓋索引)
SELECT * FROM user u
JOIN (SELECT id FROM user ORDER BY id LIMIT 1000000, 10) tmp ON u.id = tmp.id;
-- 更快:記錄上次位置(游標(biāo)分頁)
SELECT * FROM user WHERE id > 上次最大id ORDER BY id LIMIT 10;
  1. 分區(qū)表(Partition)
-- 按時(shí)間分區(qū),查詢只掃相關(guān)分區(qū)
CREATE TABLE log (
    id INT,
    create_time DATETIME
) PARTITION BY RANGE (YEAR(create_time)) (
    PARTITION p2022 VALUES LESS THAN (2023),
    PARTITION p2023 VALUES LESS THAN (2024),
    PARTITION p2024 VALUES LESS THAN MAXVALUE
);
  1. 讀寫分離 + 歸檔
    • 熱數(shù)據(jù)(最近3個(gè)月)放主庫,有索引,快速查詢
    • 冷數(shù)據(jù)歸檔到歷史庫,甚至可以去掉部分索引省空間

五、總結(jié):索引使用 checklist

□ 查詢是否用了索引?(EXPLAIN看key字段)
□ 是否避免了全表掃描?(type不是ALL)
□ 組合索引是否遵循最左前綴?
□ 是否利用了覆蓋索引減少回表?
□ 索引列是否做了函數(shù)/運(yùn)算/隱式轉(zhuǎn)換?
□ 前導(dǎo)模糊查詢是否必須?能否用全文索引?
□ 分頁是否太深?是否需要優(yōu)化?
□ 寫性能是否可接受?(索引別太多)

最后一句忠告: 索引不是銀彈,它是讀性能的加速器,寫性能的減速帶。設(shè)計(jì)時(shí)平衡讀寫比例,監(jiān)控慢查詢?nèi)罩?,定期?code>OPTIMIZE TABLE整理碎片,才能讓MySQL跑得又快又穩(wěn)。

到此這篇關(guān)于MySQL索引用法實(shí)戰(zhàn)指南的文章就介紹到這了,更多相關(guān)mysql索引用法內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 一鍵搭建MYSQL主從,輕松應(yīng)對(duì)數(shù)據(jù)備份與恢復(fù)

    一鍵搭建MYSQL主從,輕松應(yīng)對(duì)數(shù)據(jù)備份與恢復(fù)

    MYSQL主從是一種常見的數(shù)據(jù)庫架構(gòu),它可以提高數(shù)據(jù)庫的可用性和性能,在主從架構(gòu)中,主數(shù)據(jù)庫負(fù)責(zé)處理寫操作,而從數(shù)據(jù)庫負(fù)責(zé)處理讀操作,當(dāng)主數(shù)據(jù)庫發(fā)生故障時(shí),從數(shù)據(jù)庫可以接管并繼續(xù)提供服務(wù),從而實(shí)現(xiàn)高可用性,需要的朋友可以參考下
    2023-10-10
  • MySQL對(duì)數(shù)據(jù)庫操作(創(chuàng)建、選擇、刪除)

    MySQL對(duì)數(shù)據(jù)庫操作(創(chuàng)建、選擇、刪除)

    這篇文章主要介紹了MySQL如何對(duì)數(shù)據(jù)庫操作,文中講解非常詳細(xì),代碼幫助大家更好的理解和學(xué)習(xí),感興趣的朋友可以了解下
    2020-07-07
  • mysql的case when字段為空,null的問題

    mysql的case when字段為空,null的問題

    這篇文章主要介紹了mysql的case when字段為空,null的問題。具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-12-12
  • 安裝并配置MySQL全過程

    安裝并配置MySQL全過程

    本文介紹了在不同操作系統(tǒng)上安裝和配置MySQL的方法,提供了Ubuntu、Windows和macOS的具體安裝步驟,并強(qiáng)調(diào)安裝后需要設(shè)置root用戶密碼并運(yùn)行安全腳本以增加安全性,文章還討論了配置MySQL、創(chuàng)建新用戶、數(shù)據(jù)庫備份與恢復(fù)等方面
    2026-04-04
  • 分享15個(gè)Mysql索引失效的場景

    分享15個(gè)Mysql索引失效的場景

    這篇文章主要介紹了分享15個(gè)Mysql索引失效的場景,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下
    2022-05-05
  • Mysql中SUM()函數(shù)使用方法

    Mysql中SUM()函數(shù)使用方法

    這篇文章主要給大家介紹了關(guān)于Mysql中SUM()函數(shù)使用的相關(guān)資料,MySQL 的 SUM 函數(shù)可以用來對(duì)某個(gè)列進(jìn)行求和,但是如果你想要按照某個(gè)條件進(jìn)行求和,可以使用帶有WHERE子句的SUM函數(shù),需要的朋友可以參考下
    2023-08-08
  • win10 mysql 5.6.35 winx64免安裝版配置教程

    win10 mysql 5.6.35 winx64免安裝版配置教程

    這篇文章主要為大家詳細(xì)介紹了win10 mysql 5.6.35 winx64免安裝版配置教程,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-05-05
  • MySQL中的樂觀鎖和悲觀鎖的區(qū)別及說明

    MySQL中的樂觀鎖和悲觀鎖的區(qū)別及說明

    這篇文章主要介紹了MySQL中的樂觀鎖和悲觀鎖的區(qū)別及說明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2025-05-05
  • MySQL和Oracle的元數(shù)據(jù)抽取實(shí)例分析

    MySQL和Oracle的元數(shù)據(jù)抽取實(shí)例分析

    MySQL和Oracle雖然在架構(gòu)上有很大的不同,但是如果從某些方面比較起來,它們有些方面也是相通的,下面這篇文章主要給大家介紹了關(guān)于MySQL和Oracle元數(shù)據(jù)抽取的相關(guān)資料,需要的朋友可以參考下
    2021-12-12
  • mysql中over partition by的具體使用

    mysql中over partition by的具體使用

    在數(shù)據(jù)庫中,我們經(jīng)常需要對(duì)數(shù)據(jù)進(jìn)行分組排序等操作,MySQL的over partition by可以幫助我們更方便地進(jìn)行這些操作,本文主要介紹了mysql中over partition by的具體使用,感興趣的可以了解一下
    2024-02-02

最新評(píng)論

那坡县| 开江县| 秦安县| 漯河市| 霞浦县| 柳江县| 台前县| 聂拉木县| 沭阳县| 新民市| 绥德县| 桐柏县| 遂川县| 白城市| 辛集市| 惠州市| 鄂温| 信阳市| 壶关县| 余江县| 冕宁县| 布拖县| 德惠市| 清水河县| 柘城县| 洛扎县| 浪卡子县| 高阳县| 平陆县| 阿城市| 榆林市| 岫岩| 石柱| 青神县| 青田县| 长宁区| 吴桥县| 大邑县| 翁牛特旗| 沙坪坝区| 湘乡市|