第400集MySQL索引创建与索引类型详解 | 字数总计: 3.4k | 阅读时长: 14分钟 | 阅读量:
MySQL索引创建与索引类型详解 1. 索引概述 1.1 什么是索引 索引(Index)是帮助MySQL高效获取数据的数据结构。索引类似于书籍的目录,可以快速定位到数据所在的位置,而不需要扫描整个表。
1.2 索引的作用
提高查询速度 : 通过索引可以快速定位到数据,避免全表扫描
加速排序 : 索引可以帮助ORDER BY和GROUP BY操作
保证数据唯一性 : 唯一索引可以保证数据的唯一性
加速表连接 : 外键索引可以加速JOIN操作
1.3 索引的缺点
占用存储空间 : 索引需要额外的存储空间
降低写入性能 : INSERT、UPDATE、DELETE操作需要维护索引
增加维护成本 : 索引需要定期维护和优化
2. MySQL索引类型 2.1 按存储结构分类
索引类型
说明
适用场景
B-Tree索引
最常用的索引类型,支持范围查询
大多数场景
Hash索引
基于哈希表,只支持等值查询
等值查询场景
Full-Text索引
全文索引,用于文本搜索
文本搜索场景
Spatial索引
空间索引,用于地理数据
GIS应用
2.2 按功能分类
索引类型
说明
特点
普通索引
最基本的索引,没有任何限制
允许重复值
唯一索引
索引列的值必须唯一
不允许重复值
主键索引
特殊的唯一索引,不允许NULL
表的主键
复合索引
多个列组合的索引
支持多列查询
前缀索引
只索引列的前几个字符
节省存储空间
3. B-Tree索引 3.1 B-Tree索引概述 B-Tree(Balanced Tree)索引是MySQL最常用的索引类型,InnoDB和MyISAM存储引擎都支持B-Tree索引。
特点 :
支持范围查询(>, <, BETWEEN, LIKE等)
支持排序(ORDER BY)
支持最左前缀匹配
适用于大多数查询场景
3.2 B-Tree索引结构 1 2 3 4 5 6 B-Tree索引结构示例: [50] / \ [25] [75] / \ / \ [10] [30] [60] [90]
3.3 创建B-Tree索引 创建普通索引 1 2 3 4 5 6 7 8 9 10 11 12 13 14 CREATE TABLE users ( id INT PRIMARY KEY, username VARCHAR (50 ), email VARCHAR (100 ), INDEX idx_username (username), INDEX idx_email (email) ); ALTER TABLE users ADD INDEX idx_username (username);CREATE INDEX idx_username ON users (username);
创建唯一索引 1 2 3 4 5 CREATE UNIQUE INDEX idx_email ON users (email);ALTER TABLE users ADD UNIQUE INDEX idx_email (email);
创建复合索引 1 2 3 4 5 6 7 CREATE INDEX idx_name_age ON users (username, age);
3.4 B-Tree索引使用示例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 CREATE TABLE products ( id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR (100 ), category_id INT , price DECIMAL (10 , 2 ), created_at DATETIME, INDEX idx_category (category_id), INDEX idx_price (price), INDEX idx_category_price (category_id, price) ); SELECT * FROM products WHERE category_id = 1 ;SELECT * FROM products WHERE category_id = 1 AND price > 100 ;SELECT * FROM products WHERE price BETWEEN 100 AND 500 ;SELECT * FROM products ORDER BY price DESC ;
4. Hash索引 4.1 Hash索引概述 Hash索引基于哈希表实现,只支持等值查询(=, IN),不支持范围查询和排序。
特点 :
查询速度非常快(O(1))
只支持等值查询
不支持范围查询
不支持排序
只适用于Memory存储引擎
4.2 创建Hash索引 1 2 3 4 5 6 7 8 9 CREATE TABLE hash_table ( id INT PRIMARY KEY, name VARCHAR (50 ), INDEX USING HASH (name) ) ENGINE= MEMORY; ALTER TABLE hash_table ADD INDEX USING HASH (name);
4.3 Hash索引使用示例 1 2 3 4 5 SELECT * FROM hash_table WHERE name = 'test' ;SELECT * FROM hash_table WHERE name > 'test' ;
5. Full-Text全文索引 5.1 Full-Text索引概述 Full-Text索引用于全文搜索,支持对文本内容进行搜索。
特点 :
支持全文搜索
支持中文分词(MySQL 5.7+)
只适用于CHAR、VARCHAR、TEXT类型
只适用于MyISAM和InnoDB存储引擎(MySQL 5.6+)
5.2 创建Full-Text索引 1 2 3 4 5 6 7 8 9 10 11 CREATE TABLE articles ( id INT PRIMARY KEY AUTO_INCREMENT, title VARCHAR (200 ), content TEXT, FULLTEXT INDEX idx_content (content), FULLTEXT INDEX idx_title_content (title, content) ) ENGINE= InnoDB; ALTER TABLE articles ADD FULLTEXT INDEX idx_content (content);
5.3 Full-Text索引使用示例 1 2 3 4 5 6 7 8 9 10 11 SELECT * FROM articles WHERE MATCH (content) AGAINST('MySQL索引' IN NATURAL LANGUAGE MODE);SELECT * FROM articles WHERE MATCH (title, content) AGAINST('+MySQL -Oracle' IN BOOLEAN MODE);SELECT * FROM articles WHERE MATCH (content) AGAINST('数据库' WITH QUERY EXPANSION);
5.4 Full-Text索引配置 1 2 3 4 5 6 7 SHOW VARIABLES LIKE 'ft_min_word_len' ;[mysqld] ft_min_word_len = 2
6. 前缀索引 6.1 前缀索引概述 前缀索引只索引列的前几个字符,可以节省存储空间,适用于较长的字符串列。
6.2 创建前缀索引 1 2 3 4 5 CREATE INDEX idx_email_prefix ON users (email(10 ));ALTER TABLE users ADD INDEX idx_email_prefix (email(10 ));
6.3 前缀索引长度选择 1 2 3 4 5 6 7 8 9 SELECT COUNT (DISTINCT LEFT (email, 5 )) / COUNT (* ) AS selectivity_5, COUNT (DISTINCT LEFT (email, 10 )) / COUNT (* ) AS selectivity_10, COUNT (DISTINCT LEFT (email, 15 )) / COUNT (* ) AS selectivity_15, COUNT (DISTINCT email) / COUNT (* ) AS selectivity_full FROM users;
7. 复合索引 7.1 复合索引概述 复合索引(联合索引)是在多个列上创建的索引,支持多列查询。
7.2 创建复合索引 1 2 3 4 5 CREATE INDEX idx_category_price ON products (category_id, price);
7.3 复合索引最左前缀原则 1 2 3 4 5 6 7 8 9 10 SELECT * FROM products WHERE category_id = 1 ;SELECT * FROM products WHERE category_id = 1 AND price > 100 ;SELECT * FROM products WHERE category_id = 1 AND price > 100 AND created_at > '2024-01-01' ;SELECT * FROM products WHERE price > 100 ;SELECT * FROM products WHERE price > 100 AND created_at > '2024-01-01' ;
7.4 复合索引列顺序选择
8. 索引创建方法总结 8.1 创建索引的三种方式 方式1: 创建表时指定索引 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 CREATE TABLE users ( id INT PRIMARY KEY AUTO_INCREMENT, username VARCHAR (50 ) NOT NULL , email VARCHAR (100 ) NOT NULL , age INT , created_at DATETIME, INDEX idx_username (username), UNIQUE INDEX idx_email (email), INDEX idx_age_created (age, created_at), INDEX idx_email_prefix (email(10 )) );
方式2: 使用ALTER TABLE添加索引 1 2 3 4 5 6 7 8 9 10 11 ALTER TABLE users ADD INDEX idx_username (username);ALTER TABLE users ADD UNIQUE INDEX idx_email (email);ALTER TABLE users ADD INDEX idx_age_created (age, created_at);ALTER TABLE users ADD PRIMARY KEY (id);
方式3: 使用CREATE INDEX创建索引 1 2 3 4 5 6 7 8 9 10 11 CREATE INDEX idx_username ON users (username);CREATE UNIQUE INDEX idx_email ON users (email);CREATE INDEX idx_age_created ON users (age, created_at);CREATE FULLTEXT INDEX idx_content ON articles (content);
8.2 删除索引 1 2 3 4 5 6 7 8 DROP INDEX idx_username ON users;ALTER TABLE users DROP INDEX idx_username;ALTER TABLE users DROP PRIMARY KEY;
8.3 查看索引 1 2 3 4 5 6 7 8 SHOW INDEX FROM users;SHOW CREATE TABLE users;EXPLAIN SELECT * FROM users WHERE username = 'test' ;
9. 索引最佳实践 9.1 索引设计原则
选择性高的列 : 选择区分度高的列创建索引
经常查询的列 : 为WHERE、JOIN、ORDER BY中的列创建索引
避免过多索引 : 索引过多会影响写入性能
考虑复合索引 : 多个列经常一起查询时使用复合索引
最左前缀原则 : 复合索引要遵循最左前缀原则
9.2 索引使用建议 应该创建索引的情况
主键和外键
经常出现在WHERE子句中的列
经常用于JOIN的列
经常用于ORDER BY和GROUP BY的列
选择性高的列
不应该创建索引的情况
选择性很低的列(如性别、状态等)
很少用于查询的列
经常更新的列(影响写入性能)
数据量很小的表(全表扫描可能更快)
9.3 索引优化技巧 技巧1: 使用覆盖索引 1 2 3 4 5 6 CREATE INDEX idx_covering ON products (category_id, name, price);SELECT category_id, name, price FROM products WHERE category_id = 1 ;
技巧2: 使用索引提示 1 2 3 4 5 6 7 8 SELECT * FROM users USE INDEX (idx_username) WHERE username = 'test' ;SELECT * FROM users IGNORE INDEX (idx_username) WHERE username = 'test' ;SELECT * FROM users FORCE INDEX (idx_username) WHERE username = 'test' ;
技巧3: 分析索引使用情况 1 2 3 4 5 6 7 8 9 10 11 12 SELECT OBJECT_SCHEMA, OBJECT_NAME, INDEX_NAME, COUNT_FETCH, COUNT_INSERT, COUNT_UPDATE, COUNT_DELETE FROM performance_schema.table_io_waits_summary_by_index_usageWHERE OBJECT_SCHEMA = 'your_database' ORDER BY COUNT_FETCH DESC ;
10. 索引性能分析 10.1 使用EXPLAIN分析索引 1 2 3 4 5 6 7 8 EXPLAIN SELECT * FROM users WHERE username = 'test' ;
10.2 索引效果评估 1 2 3 4 5 6 7 SELECT COUNT (DISTINCT username) / COUNT (* ) AS username_selectivity, COUNT (DISTINCT email) / COUNT (* ) AS email_selectivity FROM users;
10.3 索引维护 1 2 3 4 5 6 7 8 ANALYZE TABLE users; OPTIMIZE TABLE users; CHECK TABLE users;
11. 实战案例 11.1 案例1: 电商商品表索引设计 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 CREATE TABLE products ( id BIGINT PRIMARY KEY AUTO_INCREMENT, name VARCHAR (200 ) NOT NULL , category_id INT NOT NULL , brand_id INT , price DECIMAL (10 , 2 ) NOT NULL , stock INT DEFAULT 0 , status TINYINT DEFAULT 1 , created_at DATETIME NOT NULL , updated_at DATETIME NOT NULL , INDEX idx_category (category_id), INDEX idx_brand (brand_id), INDEX idx_status (status), INDEX idx_category_price (category_id, price), INDEX idx_created (created_at), INDEX idx_name (name(50 )) ) ENGINE= InnoDB; SELECT * FROM products WHERE category_id = 1 ;SELECT * FROM products WHERE category_id = 1 AND price BETWEEN 100 AND 500 ;SELECT * FROM products WHERE status = 1 ORDER BY created_at DESC LIMIT 20 ;
11.2 案例2: 用户表索引设计 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 CREATE TABLE users ( id BIGINT PRIMARY KEY AUTO_INCREMENT, username VARCHAR (50 ) NOT NULL , email VARCHAR (100 ) NOT NULL , phone VARCHAR (20 ), password VARCHAR (255 ) NOT NULL , status TINYINT DEFAULT 1 , created_at DATETIME NOT NULL , last_login_at DATETIME, UNIQUE INDEX idx_username (username), UNIQUE INDEX idx_email (email), UNIQUE INDEX idx_phone (phone), INDEX idx_status (status), INDEX idx_created (created_at), INDEX idx_status_created (status, created_at) ) ENGINE= InnoDB; SELECT * FROM users WHERE username = 'test' AND password = 'xxx' ;SELECT * FROM users WHERE status = 1 AND created_at > '2024-01-01' ;
11.3 案例3: 订单表索引设计 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 CREATE TABLE orders ( id BIGINT PRIMARY KEY AUTO_INCREMENT, user_id BIGINT NOT NULL , order_no VARCHAR (50 ) NOT NULL , total_amount DECIMAL (10 , 2 ) NOT NULL , status TINYINT NOT NULL , created_at DATETIME NOT NULL , paid_at DATETIME, UNIQUE INDEX idx_order_no (order_no), INDEX idx_user (user_id), INDEX idx_status (status), INDEX idx_created (created_at), INDEX idx_user_status (user_id, status), INDEX idx_status_created (status, created_at) ) ENGINE= InnoDB; SELECT * FROM orders WHERE user_id = 1 ;SELECT * FROM orders WHERE user_id = 1 AND status = 2 ;SELECT * FROM orders WHERE status = 2 ORDER BY created_at DESC LIMIT 20 ;
12. 索引常见问题 12.1 索引不生效的原因
不满足最左前缀原则 : 复合索引查询不满足最左前缀
函数操作 : 对索引列使用函数(如WHERE YEAR(created_at) = 2024)
类型不匹配 : 查询条件类型与索引列类型不匹配
OR条件 : 多个OR条件可能导致索引失效
NULL值 : 索引列包含大量NULL值
12.2 索引优化建议 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 SELECT * FROM orders WHERE YEAR (created_at) = 2024 ;SELECT * FROM orders WHERE created_at >= '2024-01-01' AND created_at < '2025-01-01' ;SELECT * FROM users WHERE id = '123' ;SELECT * FROM users WHERE id = 123 ;SELECT * FROM users WHERE username LIKE '%test%' ;SELECT * FROM users WHERE username LIKE 'test%' ;
13. 命令总结 13.1 索引创建命令
命令
功能
示例
CREATE INDEX
创建索引
CREATE INDEX idx_name ON table (col)
CREATE UNIQUE INDEX
创建唯一索引
CREATE UNIQUE INDEX idx_email ON users (email)
CREATE FULLTEXT INDEX
创建全文索引
CREATE FULLTEXT INDEX idx_content ON articles (content)
ALTER TABLE ADD INDEX
添加索引
ALTER TABLE users ADD INDEX idx_name (name)
ALTER TABLE ADD UNIQUE
添加唯一索引
ALTER TABLE users ADD UNIQUE idx_email (email)
13.2 索引管理命令
命令
功能
示例
DROP INDEX
删除索引
DROP INDEX idx_name ON table
ALTER TABLE DROP INDEX
删除索引
ALTER TABLE users DROP INDEX idx_name
SHOW INDEX
查看索引
SHOW INDEX FROM users
ANALYZE TABLE
分析表
ANALYZE TABLE users
OPTIMIZE TABLE
优化表
OPTIMIZE TABLE users
13.3 索引查询命令
命令
功能
示例
EXPLAIN
分析查询计划
EXPLAIN SELECT * FROM users WHERE id = 1
SHOW CREATE TABLE
查看表结构
SHOW CREATE TABLE users
SHOW INDEX
查看索引信息
SHOW INDEX FROM users