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

一文系統(tǒng)梳理MySQL數(shù)據庫索引失效的七個場景

 更新時間:2026年06月25日 09:25:52   作者:花生了什么事o  
本文系統(tǒng)梳理了 MySQL 索引失效的七種常見場景,從函數(shù)運算、隱式類型轉換到優(yōu)化器主動放棄索引,給出失敗示例和原因,幫助讀者理解和避免出現(xiàn)索引失效情況

明明建了索引,為什么還是慢

在開發(fā)環(huán)境跑一條查詢,發(fā)現(xiàn)是毫秒級返回。上線之后,同樣的查詢,用戶反饋頁面轉圈要好幾秒。你打開 EXPLAIN 一看,type: ALL,全表掃描。明明在 create_time 上建了索引,為什么沒有用上?

這類問題的根源,往往不是索引壞了,而是寫法觸發(fā)了某種"索引失效"的條件。MySQL 的優(yōu)化器在選擇執(zhí)行計劃時,會判斷當前查詢能否利用索引的有序性。如果不能,它寧可走全表掃描,也不會用一個沒有用的索引。

這篇文章將把常見的失效場景做一次系統(tǒng)性的梳理,每種都給出原因和改法,讓你在遇到慢查詢時能快速定位問題。

索引失效的本質

在逐個看場景之前,先搞清楚一件事:索引為什么會失效?

索引的本質是一棵 B+ 樹,它的價值在于有序性。二分查找之所以快,是因為數(shù)據排好了序。索引失效就是:寫法破壞了 B+ 樹有序性的利用條件,MySQL 無法通過索引快速定位數(shù)據。

索引就像一本按拼音排序的字典。你可以用拼音快速找到"張"字在哪一頁。但如果你的查詢是"找所有姓名中包含’張’字的人",這本字典就幫不了你了,因為"包含張"這個條件無法利用拼音的排序規(guī)則,你只能一頁一頁翻。

索引只在能利用有序性的查詢中生效。一旦查詢條件破壞了有序性的利用方式,索引就會失效。

場景一:對索引列做函數(shù)運算

這是最常見、也最容易犯的索引失效場景。

-- 索引:idx_create_time(create_time)

-- 失效:對索引列用了 YEAR() 函數(shù)
SELECT * FROM orders WHERE YEAR(create_time) = 2025;

-- 生效:改成范圍查詢
SELECT * FROM orders WHERE create_time >= '2025-01-01' AND create_time < '2026-01-01';

第一條查詢?yōu)槭裁词??因?YEAR(create_time) 的結果是計算出來的,MySQL 需要對表中的每一行都執(zhí)行一次 YEAR() 函數(shù),然后拿結果去比較。這時候 B+ 樹里存的是 create_time 的原始值,不是 YEAR() 的計算結果,有序性對計算后的值沒有意義。

場景二:隱式類型轉換

-- 索引:idx_phone(phone),phone 列是 VARCHAR 類型

-- 失效:傳入了數(shù)字
SELECT * FROM user WHERE phone = 13800138000;

-- 生效:傳入字符串
SELECT * FROM user WHERE phone = '13800138000';

phone 是 VARCHAR,你傳了一個 INT。MySQL 的規(guī)則是:當字符串和數(shù)字比較時,MySQL 會把字符串轉成數(shù)字。 這意味著對 phone 列的每一行,MySQL 都要先把它從字符串轉成數(shù)字,再和 13800138000 比較。這等價于對索引列做了 CAST(phone AS SIGNED) 函數(shù)運算,和場景一相同,索引就會失效。

那如果反過來呢?

-- id 列是 INT 類型
-- 傳入字符串也不會失效,因為 INT 和字符串比較時,MySQL 把字符串轉成數(shù)字
-- 轉換發(fā)生在常量一側,不影響索引列
SELECT * FROM user WHERE id = '123';  -- 走索引

規(guī)則:字符串列傳數(shù)字會失效,數(shù)字列傳字符串不會失效。 因為只有當轉換發(fā)生在索引列一側時,才相當于對索引列做了函數(shù)運算。

怎么判斷是否發(fā)生了隱式類型轉換?用 EXPLAIN 看,如果 Extra 里出現(xiàn)了 Using wheretypeALL,那么大概率就是。

場景三:隱式字符編碼轉換

這個場景比類型轉換更隱蔽,很多人踩過坑但不知道原因。

-- 庫 A:字符集 utf8mb4,庫 B:字符集 utf8

SELECT * FROM db_a.user a
JOIN db_b.order b ON a.name = b.user_name
WHERE a.name = '張三';

如果兩張表的關聯(lián)列字符集不同,MySQL 在做 JOIN 比較時需要做字符集轉換。轉換發(fā)生在索引列上時,等價于對索引列做了函數(shù)運算,索引失效。原理和場景一相同,只是"變形"的方式從類型轉換變成了編碼轉換。

場景四:LIKE 左模糊匹配

-- 索引:idx_name(name)

-- 走索引:右模糊
SELECT * FROM user WHERE name LIKE '張%';

-- 不走索引:左模糊
SELECT * FROM user WHERE name LIKE '%三';

-- 不走索引:全模糊
SELECT * FROM user WHERE name LIKE '%三%';

回到字典的類比。字典按拼音排序,你可以快速找到"zhang"開頭的所有字。但如果要求找"名字里包含’三’的字",拼音排序就幫不了你了,因為"三"可能出現(xiàn)在名字的任何位置,它的拼音分布在字典的各個角落。

LIKE '張%' 能走索引,是因為前綴確定時,這些值在 B+ 樹中是連續(xù)的,可以范圍掃描。LIKE '%三' 不行,是因為前綴不確定,值在樹中是分散的,只能逐行檢查。

場景五:OR 連接不同索引列

-- 索引:idx_a(a),idx_b(b)

-- 失效:OR 連接了不同索引的列
SELECT * FROM t WHERE a = 1 OR b = 2;

a = 1 可以走 idx_a,b = 2 可以走 idx_b,但兩條路徑的結果要合并去重。MySQL 在大多數(shù)情況下只能選一個索引或者直接全表掃描。MySQL 8.0 引入了 Index Merge 優(yōu)化,某些 OR 場景下可以同時使用多個索引,但優(yōu)化器也可能認為全表掃描更快而放棄,不是萬能的。

場景六:違反最左前綴原則

聯(lián)合索引 (a, b, c) 的排序規(guī)則是先按 a 排,a 相同再按 b 排,b 相同再按 c 排。這個話題在我的另一篇文章《MySQL 最左前綴法則:為什么你的聯(lián)合索引總是不生效》里詳細展開過,這里只列核心規(guī)則,不做重復展開。

-- 索引:idx_abc(a, b, c)

WHERE b = 2;                  -- 跳過了 a,不走索引
WHERE b = 2 AND c = 3;        -- 跳過了 a,不走索引
WHERE a = 1 AND c = 3;        -- 跳過了 b,只用到 a
WHERE a = 1 AND b > 5 AND c = 3;  -- b 范圍之后 c 無序,c 失效

原因和前面的場景一樣:跳過最左列后,后續(xù)列在 B+ 樹中是分散的,無法利用有序性。

場景七:數(shù)據量太小,優(yōu)化器主動放棄

這個場景經常讓人困惑:明明寫法沒問題,索引也建了,為什么 EXPLAIN 顯示全表掃描?

-- 表里只有 100 條數(shù)據
EXPLAIN SELECT * FROM user WHERE age > 20;
-- type: ALL,沒走索引

MySQL 的優(yōu)化器是基于成本做決策的。走索引不是免費的,需要從 B+ 樹根節(jié)點遍歷到葉子節(jié)點,再通過主鍵回表取完整行數(shù)據。當表的數(shù)據量很小時,全表掃描可能只需要讀一兩個數(shù)據頁,走索引反而需要更多 I/O。優(yōu)化器經過成本估算,發(fā)現(xiàn)全表掃描更快,就會主動放棄索引。

同樣的道理,當索引列的區(qū)分度太低時(比如 gender 只有 ‘M’ 和 ‘F’),走索引要回表的行數(shù)接近全表行數(shù),順序 I/O 比隨機 I/O 快得多,優(yōu)化器也會選擇全表掃描。

這不是 bug,而是合理的優(yōu)化。 可以用 FORCE INDEX 強制走索引來驗證:如果強制走索引反而更慢,說明優(yōu)化器的選擇是對的。

一個公式:索引為什么會失效

看完七個場景,你會發(fā)現(xiàn)它們背后有一個共同的邏輯:

當 MySQL 無法利用 B+ 樹的有序性來減少掃描行數(shù)時,索引就會失效。

拆開來看,有三種情況會導致有序性無法被利用:

情況本質對應場景
索引列被"變形"了原始值的有序性對變形后的值無意義函數(shù)運算、類型轉換、字符集轉換
查詢條件無法利用排序模糊匹配無法定位到連續(xù)區(qū)間LIKE 左模糊、OR 跨索引
走索引的成本太高優(yōu)化器認為全表掃描更劃算數(shù)據量小、區(qū)分度低

遇到索引失效的問題,先用 EXPLAIN 確認是否走了索引,再對照這個表格判斷屬于哪種情況。大多數(shù)時候,我們的改法都是圍繞一個原則:讓索引列保持"原樣",讓查詢條件能利用 B+ 樹的有序性。

小結

索引失效不是 MySQL 出了問題,而是 B+ 樹有序性的自然推論。索引之所以快,是因為數(shù)據排好了序,可以二分查找。一旦你的查詢寫法讓 MySQL 沒法利用這個排序,索引就等于沒有用處了。

七個場景中,最值得記住的是兩個:對索引列做函數(shù)/運算隱式類型轉換。這兩個在實際開發(fā)中出現(xiàn)頻率最高,常容易被忽略。

排查索引失效時,EXPLAIN 是第一工具???type 是不是 ALL,看 key 是不是 NULL,看 Extra 里有沒有 Using where。確認失效之后,對照本文提到的七個場景逐一排查,基本就能找到具體原因。

以上就是一文系統(tǒng)梳理MySQL數(shù)據庫索引失效的七個場景的詳細內容,更多關于MySQL索引失效常見場景的資料請關注腳本之家其它相關文章!

相關文章

  • 如何清除mysql注冊表

    如何清除mysql注冊表

    在本篇文章里小編給大家整理的是關于如何清除mysql注冊表的相關知識點內容,有需要的朋友們可以參考下。
    2020-08-08
  • MySQL 游標的作用與使用相關

    MySQL 游標的作用與使用相關

    這篇文章主要介紹了MySQL游標的相關資料,幫助大家更好的理解和使用MySQL數(shù)據庫,感興趣的朋友可以了解下
    2021-01-01
  • MySQL的中文UTF8亂碼問題

    MySQL的中文UTF8亂碼問題

    MySQL從4.x版本開始支持Unicode,3.x只有l(wèi)atin1編碼。剛工作的時候就開始用MySQL了,用的php存取,網頁xxx.php是gb2312的編碼,存進去的數(shù)據用php取出來是中文,用phpMyAdmin執(zhí)行select、update、dump都是中文,沒有亂碼問題。
    2010-05-05
  • MySql數(shù)據庫基礎知識點總結

    MySql數(shù)據庫基礎知識點總結

    這篇文章主要介紹了MySql數(shù)據庫基礎知識點,總結整理了mysql數(shù)據庫基本創(chuàng)建、查看、選擇、刪除以及數(shù)據類型相關操作技巧,需要的朋友可以參考下
    2020-06-06
  • MySql使用create?index創(chuàng)建索引方式

    MySql使用create?index創(chuàng)建索引方式

    本文詳細介紹了在MySQL中創(chuàng)建不同類型的索引的方法,包括普通索引、唯一索引、全文索引、空間索引以及復合索引的創(chuàng)建語法
    2026-06-06
  • SQL實現(xiàn)LeetCode(178.分數(shù)排行)

    SQL實現(xiàn)LeetCode(178.分數(shù)排行)

    這篇文章主要介紹了SQL實現(xiàn)LeetCode(178.分數(shù)排行),本篇文章通過簡要的案例,講解了該項技術的了解與使用,以下就是詳細內容,需要的朋友可以參考下
    2021-08-08
  • CentOS Linux更改MySQL數(shù)據庫目錄位置具體操作

    CentOS Linux更改MySQL數(shù)據庫目錄位置具體操作

    由于MySQL的數(shù)據庫太大,默認安裝的/var盤已經再也無法容納新增加的數(shù)據,沒有辦法,只能想辦法轉移數(shù)據的目錄,本文整理了一些MySQL從/var/lib/mysql目錄下面轉移到/home/mysql_data/mysql目錄的具體操作,感興趣的你可不要走開啊
    2013-01-01
  • MySQL 5.0.16亂碼問題的解決方法

    MySQL 5.0.16亂碼問題的解決方法

    這篇文章主要介紹了MySQL 5.0.16亂碼問題的解決方法,需要的朋友可以參考下
    2015-10-10
  • MySQL開啟配置binlog及通過binlog恢復數(shù)據步驟詳析

    MySQL開啟配置binlog及通過binlog恢復數(shù)據步驟詳析

    這篇文章主要給大家介紹了關于MySQL開啟配置binlog及通過binlog恢復數(shù)據的相關資料,binlog是MySQL最重要的日志,binlog是二進制日志,它記錄了所有的DDL和DML語句,除了查詢語句select、show等,需要的朋友可以參考下
    2024-06-06
  • 一文學會Mysql數(shù)據庫備份與恢復

    一文學會Mysql數(shù)據庫備份與恢復

    數(shù)據庫備份是在數(shù)據丟失的情況下能及時恢復重要數(shù)據,防止數(shù)據丟失的一種重要手段,下面這篇文章主要給大家介紹了關于Mysql數(shù)據庫備份與恢復的相關資料,需要的朋友可以參考下
    2022-05-05

最新評論

高要市| 山东省| 沂水县| 隆安县| 石河子市| 镇远县| 错那县| 洛阳市| 乌兰察布市| 易门县| 九寨沟县| 湟中县| 修水县| 永昌县| 屯门区| 山丹县| 怀化市| 青神县| 曲水县| 响水县| 永登县| 襄城县| 进贤县| 玉山县| 富阳市| 临邑县| 遂平县| 麻城市| 佳木斯市| 双牌县| 华蓥市| 高邑县| 措勤县| 太湖县| 陵川县| 兴业县| 南召县| 阿克陶县| 陆河县| 长兴县| 内江市|