Mysql 索引從入門到精通(從原理到實(shí)踐)
MySQL 索引深度解析:從原理到實(shí)踐

1. 索引基礎(chǔ)概念
1.1 什么是索引
索引(Index)是數(shù)據(jù)庫管理系統(tǒng)中一種重要的數(shù)據(jù)結(jié)構(gòu),它為表中的數(shù)據(jù)創(chuàng)建了一個(gè)有序的引用結(jié)構(gòu),類似于書籍的目錄。通過索引,數(shù)據(jù)庫可以快速定位到特定的數(shù)據(jù)行,而不需要掃描整個(gè)表。
-- 創(chuàng)建一個(gè)示例表
CREATE TABLE users (
id INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(50) NOT NULL,
email VARCHAR(100) UNIQUE,
age INT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
INDEX idx_username (username),
INDEX idx_age_created (age, created_at)
);
1.2 索引的作用和重要性
索引在數(shù)據(jù)庫性能優(yōu)化中扮演著至關(guān)重要的角色:
- 加速查詢:將 O(n) 的線性查找優(yōu)化為 O(log n) 的樹形查找
- 排序優(yōu)化:利用索引的有序性避免額外的排序操作
- 分組優(yōu)化:提高 GROUP BY 操作的效率
- 連接優(yōu)化:加速表之間的 JOIN 操作
-- 沒有索引的查詢(全表掃描) SELECT * FROM users WHERE username = 'john_doe'; -- 有索引的查詢(索引查找) -- 執(zhí)行計(jì)劃會(huì)顯示使用 idx_username 索引 EXPLAIN SELECT * FROM users WHERE username = 'john_doe';

1.3 索引的優(yōu)缺點(diǎn)
優(yōu)點(diǎn):
- 大幅提升查詢速度
- 加速排序和分組操作
- 提高多表連接效率
- 保證數(shù)據(jù)唯一性(唯一索引)
缺點(diǎn):
- 占用額外存儲(chǔ)空間
- 降低寫操作性能(INSERT、UPDATE、DELETE)
- 維護(hù)成本增加
2. MySQL 索引類型詳解
2.1 主鍵索引(Primary Key Index)
主鍵索引是表中最重要的索引,每個(gè)表只能有一個(gè)主鍵索引,它具有唯一性且不能為空。
-- 創(chuàng)建表時(shí)定義主鍵
CREATE TABLE products (
product_id INT PRIMARY KEY AUTO_INCREMENT,
product_name VARCHAR(100) NOT NULL,
price DECIMAL(10,2)
);
-- 為已存在的表添加主鍵
ALTER TABLE products ADD PRIMARY KEY (product_id);2.2 唯一索引(Unique Index)
唯一索引確保索引列的值在表中是唯一的,但允許 NULL 值。
-- 創(chuàng)建唯一索引
CREATE UNIQUE INDEX idx_email ON users (email);
-- 或者在創(chuàng)建表時(shí)定義
CREATE TABLE users (
id INT PRIMARY KEY,
email VARCHAR(100) UNIQUE
);2.3 普通索引(Normal Index)
普通索引是最基本的索引類型,沒有唯一性限制。
-- 創(chuàng)建普通索引 CREATE INDEX idx_username ON users (username); CREATE INDEX idx_age ON users (age); -- 查看索引使用情況 EXPLAIN SELECT * FROM users WHERE username = 'alice' AND age > 25;
2.4 復(fù)合索引(Composite Index)
復(fù)合索引包含多個(gè)列,遵循最左前綴原則。
-- 創(chuàng)建復(fù)合索引 CREATE INDEX idx_name_age_city ON users (username, age, city); -- 以下查詢可以使用該索引 SELECT * FROM users WHERE username = 'bob'; SELECT * FROM users WHERE username = 'bob' AND age = 30; SELECT * FROM users WHERE username = 'bob' AND age = 30 AND city = 'Beijing'; -- 以下查詢無法使用該索引 SELECT * FROM users WHERE age = 30; -- 跳過了最左列 SELECT * FROM users WHERE city = 'Beijing'; -- 跳過了最左列
2.5 全文索引(Full-text Index)
全文索引用于文本搜索,支持自然語言搜索和布爾搜索。
-- 創(chuàng)建全文索引
CREATE TABLE articles (
id INT PRIMARY KEY AUTO_INCREMENT,
title VARCHAR(200),
content TEXT,
FULLTEXT(title, content)
);
-- 使用全文搜索
SELECT * FROM articles
WHERE MATCH(title, content) AGAINST('MySQL 索引優(yōu)化' IN NATURAL LANGUAGE MODE);3. 索引底層原理
3.1 B+ 樹數(shù)據(jù)結(jié)構(gòu)
MySQL 的 InnoDB 存儲(chǔ)引擎使用 B+ 樹作為索引的數(shù)據(jù)結(jié)構(gòu)。B+ 樹具有以下特點(diǎn):
- 所有葉子節(jié)點(diǎn)在同一層
- 非葉子節(jié)點(diǎn)只存儲(chǔ)鍵值,不存儲(chǔ)數(shù)據(jù)
- 葉子節(jié)點(diǎn)存儲(chǔ)完整的數(shù)據(jù)記錄
- 葉子節(jié)點(diǎn)之間通過指針連接,支持范圍查詢
-- 演示 B+ 樹索引的范圍查詢優(yōu)勢 SELECT * FROM users WHERE age BETWEEN 25 AND 35 ORDER BY age; -- 由于 B+ 樹的有序性,這個(gè)查詢非常高效

3.2 聚簇索引與非聚簇索引
聚簇索引(Clustered Index):
- InnoDB 表的主鍵索引就是聚簇索引
- 數(shù)據(jù)行按照主鍵順序物理存儲(chǔ)
- 每個(gè)表只能有一個(gè)聚簇索引
非聚簇索引(Non-clustered Index):
- 除主鍵外的其他索引都是非聚簇索引
- 葉子節(jié)點(diǎn)存儲(chǔ)主鍵值,需要回表查詢完整數(shù)據(jù)
-- 創(chuàng)建測試表演示聚簇索引和非聚簇索引
CREATE TABLE orders (
order_id INT PRIMARY KEY, -- 聚簇索引
customer_id INT,
order_date DATE,
total_amount DECIMAL(10,2),
INDEX idx_customer (customer_id), -- 非聚簇索引
INDEX idx_date (order_date) -- 非聚簇索引
);
-- 通過主鍵查詢(使用聚簇索引)
SELECT * FROM orders WHERE order_id = 1001;
-- 通過非聚簇索引查詢(需要回表)
SELECT * FROM orders WHERE customer_id = 123;3.3 索引存儲(chǔ)機(jī)制
-- 查看表的索引信息
SHOW INDEX FROM users;
-- 查看索引的存儲(chǔ)統(tǒng)計(jì)信息
SELECT
table_name,
index_name,
stat_name,
stat_value
FROM mysql.innodb_index_stats
WHERE table_name = 'users';4. 索引的創(chuàng)建與管理
4.1 創(chuàng)建索引的語法
-- 基本語法 CREATE [UNIQUE|FULLTEXT] INDEX index_name ON table_name (column1, column2, ...); -- 實(shí)際示例 CREATE INDEX idx_user_status ON users (status); CREATE UNIQUE INDEX idx_user_phone ON users (phone_number); CREATE INDEX idx_order_date_status ON orders (order_date, status); -- 使用 ALTER TABLE 創(chuàng)建索引 ALTER TABLE users ADD INDEX idx_created_at (created_at); ALTER TABLE users ADD UNIQUE INDEX idx_username_email (username, email);
4.2 查看索引信息
-- 查看表的所有索引
SHOW INDEX FROM users;
-- 查看索引使用統(tǒng)計(jì)
SELECT
object_schema,
object_name,
index_name,
count_read,
count_write,
count_fetch,
count_insert,
count_update,
count_delete
FROM performance_schema.table_io_waits_summary_by_index_usage
WHERE object_schema = 'your_database' AND object_name = 'users';4.3 刪除索引
-- 刪除索引 DROP INDEX idx_username ON users; -- 使用 ALTER TABLE 刪除索引 ALTER TABLE users DROP INDEX idx_age; -- 刪除主鍵(需要先刪除 AUTO_INCREMENT 屬性) ALTER TABLE users MODIFY id INT; ALTER TABLE users DROP PRIMARY KEY;
4.4 修改索引
-- MySQL 不支持直接修改索引,需要先刪除再創(chuàng)建 DROP INDEX idx_old_name ON users; CREATE INDEX idx_new_name ON users (username, email); -- 或者使用 ALTER TABLE ALTER TABLE users DROP INDEX idx_old_name, ADD INDEX idx_new_name (username, email);
5. 索引性能優(yōu)化策略
5.1 索引選擇性分析
索引選擇性是指索引列中不同值的數(shù)量與表中記錄總數(shù)的比值。選擇性越高,索引效果越好。
-- 計(jì)算列的選擇性
SELECT
COUNT(DISTINCT username) / COUNT(*) as username_selectivity,
COUNT(DISTINCT email) / COUNT(*) as email_selectivity,
COUNT(DISTINCT age) / COUNT(*) as age_selectivity
FROM users;
-- 分析最適合創(chuàng)建索引的列
SELECT
column_name,
cardinality,
cardinality / table_rows as selectivity
FROM information_schema.statistics s
JOIN information_schema.tables t ON s.table_name = t.table_name
WHERE s.table_schema = 'your_database' AND s.table_name = 'users';5.2 查詢執(zhí)行計(jì)劃分析
使用 EXPLAIN 分析查詢的執(zhí)行計(jì)劃,優(yōu)化索引使用。
-- 分析查詢執(zhí)行計(jì)劃 EXPLAIN SELECT * FROM users WHERE username = 'john' AND age > 25; -- 詳細(xì)的執(zhí)行計(jì)劃分析 EXPLAIN FORMAT=JSON SELECT * FROM users WHERE username = 'john' AND age > 25; -- 實(shí)際執(zhí)行統(tǒng)計(jì) EXPLAIN ANALYZE SELECT * FROM users WHERE username = 'john' AND age > 25;
5.3 索引覆蓋優(yōu)化
索引覆蓋是指查詢所需的所有列都包含在索引中,避免回表操作。
-- 創(chuàng)建覆蓋索引 CREATE INDEX idx_user_cover ON users (username, email, age); -- 以下查詢可以使用覆蓋索引,避免回表 SELECT username, email, age FROM users WHERE username = 'alice'; -- 查看是否使用了覆蓋索引 EXPLAIN SELECT username, email, age FROM users WHERE username = 'alice'; -- Extra 列會(huì)顯示 "Using index"
5.4 避免索引失效
-- 索引失效的常見情況 -- 1. 使用函數(shù)或表達(dá)式 -- 錯(cuò)誤:索引失效 SELECT * FROM users WHERE UPPER(username) = 'JOHN'; -- 正確:使用索引 SELECT * FROM users WHERE username = 'john'; -- 2. 使用 LIKE 以通配符開頭 -- 錯(cuò)誤:索引失效 SELECT * FROM users WHERE username LIKE '%john%'; -- 正確:使用索引 SELECT * FROM users WHERE username LIKE 'john%'; -- 3. 使用 OR 連接不同列 -- 錯(cuò)誤:可能索引失效 SELECT * FROM users WHERE username = 'john' OR age = 25; -- 正確:使用 UNION SELECT * FROM users WHERE username = 'john' UNION SELECT * FROM users WHERE age = 25; -- 4. 數(shù)據(jù)類型不匹配 -- 錯(cuò)誤:索引失效 SELECT * FROM users WHERE age = '25'; -- age 是 INT 類型 -- 正確:使用索引 SELECT * FROM users WHERE age = 25;
6. 索引最佳實(shí)踐

6.1 索引設(shè)計(jì)原則
- 選擇性原則:為選擇性高的列創(chuàng)建索引
- 最左前綴原則:復(fù)合索引要考慮查詢模式
- 覆蓋索引原則:盡量使用覆蓋索引避免回表
- 適度原則:避免過多索引影響寫性能
-- 好的索引設(shè)計(jì)示例
CREATE TABLE user_orders (
id INT PRIMARY KEY AUTO_INCREMENT,
user_id INT NOT NULL,
order_status ENUM('pending', 'paid', 'shipped', 'delivered', 'cancelled'),
order_date DATE NOT NULL,
total_amount DECIMAL(10,2),
-- 基于查詢模式設(shè)計(jì)的復(fù)合索引
INDEX idx_user_status_date (user_id, order_status, order_date),
-- 覆蓋索引,避免回表
INDEX idx_status_date_amount (order_status, order_date, total_amount)
);6.2 常見索引陷阱
-- 陷阱1:過多的單列索引
-- 錯(cuò)誤做法
CREATE INDEX idx_user_id ON orders (user_id);
CREATE INDEX idx_status ON orders (order_status);
CREATE INDEX idx_date ON orders (order_date);
-- 正確做法:根據(jù)查詢模式創(chuàng)建復(fù)合索引
CREATE INDEX idx_user_status_date ON orders (user_id, order_status, order_date);
-- 陷阱2:重復(fù)索引
-- 錯(cuò)誤:創(chuàng)建了重復(fù)的索引
CREATE INDEX idx_username ON users (username);
CREATE INDEX idx_username_duplicate ON users (username); -- 重復(fù)索引
-- 陷阱3:無用的索引
-- 檢查從未使用的索引
SELECT
object_schema,
object_name,
index_name
FROM performance_schema.table_io_waits_summary_by_index_usage
WHERE count_read = 0 AND count_write = 0 AND count_fetch = 0;6.3 索引維護(hù)策略
-- 定期分析表和索引統(tǒng)計(jì)信息
ANALYZE TABLE users;
-- 檢查索引碎片
SELECT
table_schema,
table_name,
data_length,
index_length,
data_free,
(data_free / (data_length + index_length)) * 100 as fragmentation_pct
FROM information_schema.tables
WHERE table_schema = 'your_database';
-- 重建索引(減少碎片)
ALTER TABLE users ENGINE=InnoDB;
-- 監(jiān)控索引使用情況
SELECT
object_name,
index_name,
count_read,
count_write,
count_fetch / count_read as fetch_ratio
FROM performance_schema.table_io_waits_summary_by_index_usage
WHERE object_schema = 'your_database'
ORDER BY count_read DESC;7. 總結(jié)與展望
7.1 核心要點(diǎn)總結(jié)
通過本文的深入分析,我們可以總結(jié)出 MySQL 索引優(yōu)化的核心要點(diǎn):
- 理解索引本質(zhì):索引是以空間換時(shí)間的數(shù)據(jù)結(jié)構(gòu),基于 B+ 樹實(shí)現(xiàn)高效的數(shù)據(jù)檢索
- 合理選擇索引類型:根據(jù)業(yè)務(wù)需求選擇主鍵索引、唯一索引、普通索引或復(fù)合索引
- 遵循設(shè)計(jì)原則:考慮選擇性、最左前綴、覆蓋索引等原則
- 持續(xù)監(jiān)控優(yōu)化:通過執(zhí)行計(jì)劃分析、性能監(jiān)控等手段持續(xù)優(yōu)化索引策略
7.2 性能提升效果
正確使用索引可以帶來顯著的性能提升:
- 查詢速度提升:從秒級(jí)優(yōu)化到毫秒級(jí)
- 系統(tǒng)吞吐量:提升 10-100 倍不等
- 資源利用率:減少 CPU 和 I/O 消耗
7.3 未來發(fā)展趨勢
隨著數(shù)據(jù)庫技術(shù)的不斷發(fā)展,索引技術(shù)也在持續(xù)演進(jìn):
- 智能索引推薦:基于機(jī)器學(xué)習(xí)的自動(dòng)索引優(yōu)化
- 列式存儲(chǔ)索引:適應(yīng)大數(shù)據(jù)分析場景的新型索引結(jié)構(gòu)
- 內(nèi)存索引優(yōu)化:針對(duì)內(nèi)存數(shù)據(jù)庫的索引算法優(yōu)化
- 分布式索引:支持分布式數(shù)據(jù)庫的全局索引管理
7.4 實(shí)踐建議
在實(shí)際項(xiàng)目中應(yīng)用索引優(yōu)化時(shí),建議:
- 漸進(jìn)式優(yōu)化:從最頻繁的查詢開始,逐步優(yōu)化索引策略
- 測試驅(qū)動(dòng):在生產(chǎn)環(huán)境應(yīng)用前,充分測試索引的性能影響
- 監(jiān)控為先:建立完善的性能監(jiān)控體系,及時(shí)發(fā)現(xiàn)和解決問題
- 團(tuán)隊(duì)協(xié)作:建立索引設(shè)計(jì)規(guī)范,確保團(tuán)隊(duì)成員遵循最佳實(shí)踐
索引優(yōu)化是一個(gè)持續(xù)的過程,需要結(jié)合具體的業(yè)務(wù)場景和數(shù)據(jù)特點(diǎn),通過不斷的分析、測試和調(diào)優(yōu),才能發(fā)揮索引的最大價(jià)值。掌握了這些核心概念和實(shí)踐技巧,相信你能夠在實(shí)際項(xiàng)目中有效地運(yùn)用 MySQL 索引,顯著提升數(shù)據(jù)庫的查詢性能。
到此這篇關(guān)于Mysql 索引從入門到精通(從原理到實(shí)踐)的文章就介紹到這了,更多相關(guān)mysql索引從入門到精通內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
MySQL對(duì)相同字段創(chuàng)建不同索引解析
這篇文章主要為大家介紹了MySQL?對(duì)相同字段創(chuàng)建不同索引解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-11-11
通過KeepAlived搭建MySQL雙主模式的Mysql集群圖文教程
在構(gòu)建高可用的MySQL集群時(shí),Keepalived是一個(gè)常用的工具,它可以實(shí)現(xiàn)雙主模式,確保在主節(jié)點(diǎn)發(fā)生故障時(shí),備節(jié)點(diǎn)可以接替其功能,保證系統(tǒng)的連續(xù)性和可用性,這篇文章主要介紹了通過KeepAlived搭建MySQL雙主模式的Mysql集群的相關(guān)資料,需要的朋友可以參考下2026-04-04
MySQL千萬級(jí)數(shù)據(jù)從190秒優(yōu)化到1秒的全過程
優(yōu)化MySQL千萬級(jí)數(shù)據(jù)策略還是比較多的,分表分庫,創(chuàng)建中間表,匯總表以及修改為多個(gè)子查詢,這里討論的情況是在MySQL一張表的數(shù)據(jù)達(dá)到千萬級(jí)別,在這樣的情況下,開發(fā)者可以嘗試通過優(yōu)化SQL來達(dá)到查詢的目的,所以本文給大家介紹了MySQL千萬級(jí)數(shù)據(jù)從190秒優(yōu)化到1秒的全過程2024-04-04
ERROR: Error in Log_event::read_log_event()
ERROR: Error in Log_event::read_log_event(): read error, data_len: 438, event_type: 22014-02-02
MySQL多層級(jí)結(jié)構(gòu)-樹搜索介紹
這篇文章主要介紹了MySQL多層級(jí)結(jié)構(gòu)-樹搜索,需要的朋友可以參考下2016-07-07
Linux(Ubuntu)下Mysql5.6.28安裝配置方法圖文教程
這篇文章主要為大家詳細(xì)介紹了Linux(Ubuntu)下Mysql5.6.28安裝配置方法圖文教程,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-01-01
MySQL批量修改表及表內(nèi)字段排序規(guī)則舉例詳解
在MySQL中字段排序規(guī)則(也稱為字符集和排序規(guī)則)用于確定如何比較和排序字符串,下面這篇文章主要給大家介紹了關(guān)于MySQL批量修改表及表內(nèi)字段排序規(guī)則的相關(guān)資料,需要的朋友可以參考下2024-05-05

