
索引是数据库性能优化的核心要素,如同书籍的目录,能极大加快数据查询速度。然而,不合理的索引设计反而会降低数据库性能。本文将深入解析 MySQL 索引的工作原理、类型划分、创建策略及优化技巧,帮助你构建高效的索引体系。
索引是存储在磁盘上的特殊数据结构,它包含表中一列或多列的值,并指向这些值在表中的物理位置。MySQL 索引主要基于 B + 树实现,这是一种平衡多路查找树,具有以下特点:
优点:
缺点:
索引选择性是指不重复的索引值与表中记录数的比值,计算公式:
plaintext
选择性 = 不重复的索引值数量 / 表中总记录数选择性越接近 1,索引效果越好。例如,用户表的email字段比status字段(可能只有 "active"/"inactive" 两个值)选择性更高,更适合创建索引。
最基本的索引类型,没有任何限制
sql
CREATE INDEX idx_user_name ON users(username);
-- 或在创建表时定义
CREATE TABLE users (
id INT,
username VARCHAR(50),
INDEX idx_user_name (username)
);确保索引列的值唯一,允许 NULL 值(但 NULL 只允许出现一次)
sql
CREATE UNIQUE INDEX idx_user_email ON users(email);特殊的唯一索引,不允许 NULL 值,一个表只能有一个主键
sql
-- 创建表时定义
CREATE TABLE users (
id INT,
username VARCHAR(50),
PRIMARY KEY (id)
);用于全文搜索,适用于 CHAR、VARCHAR、TEXT 类型字段
sql
CREATE FULLTEXT INDEX idx_article_content ON articles(content);
-- 使用全文索引查询
SELECT * FROM articles
WHERE MATCH(content) AGAINST('database mysql');只包含单个列的索引
sql
CREATE INDEX idx_order_date ON orders(order_date);包含多个列的索引,遵循 "最左前缀原则"
sql
CREATE INDEX idx_user_status_age ON users(status, age);复合索引的生效规则:
sql
CREATE [UNIQUE|FULLTEXT] INDEX index_name
ON table_name(column1[length], column2[length], ...);sql
ALTER TABLE table_name
ADD [UNIQUE|FULLTEXT] INDEX index_name(column_list);sql
CREATE TABLE table_name (
column1 data_type,
column2 data_type,
...,
INDEX index_name(column_list)
);对于字符串类型的长字段,可以只对字段的前 n 个字符创建索引,节省空间并提高效率
sql
-- 对username字段的前10个字符创建索引
CREATE INDEX idx_username_prefix ON users(username(10));前缀长度选择原则:
sql
SELECT COUNT(DISTINCT LEFT(username, 10))/COUNT(*) AS selectivity
FROM users;sql
-- 删除指定索引
DROP INDEX index_name ON table_name;
-- 或使用ALTER TABLE
ALTER TABLE table_name DROP INDEX index_name;sql
-- 查看表中所有索引
SHOW INDEX FROM table_name;
-- 查看表结构(包含索引信息)
DESCRIBE table_name;
-- 更详细的索引信息
SELECT * FROM information_schema.statistics
WHERE table_name = 'your_table' AND table_schema = 'your_database';sql
-- 频繁按status查询,适合创建索引
SELECT * FROM orders WHERE status = 'completed';sql
-- user_id用于关联查询,适合在两个表都创建索引
SELECT * FROM orders
JOIN users ON orders.user_id = users.id;sql
-- 对order_date创建索引可加速排序
SELECT * FROM orders ORDER BY order_date DESC;sql
-- 索引失效
SELECT * FROM users WHERE YEAR(created_at) = 2023;
-- 应改为
SELECT * FROM users WHERE created_at BETWEEN '2023-01-01' AND '2023-12-31';sql
-- 可能导致索引失效
SELECT * FROM users WHERE status != 'active';sql
-- 如果age没有索引,整个查询可能不使用索引
SELECT * FROM users WHERE username = 'john' OR age = 30;sql
-- 索引失效
SELECT * FROM users WHERE username LIKE '%john';
-- 索引有效
SELECT * FROM users WHERE username LIKE 'john%';sql
-- phone是字符串类型,查询时用数字会导致索引失效
SELECT * FROM users WHERE phone = 13800138000;
-- 应改为
SELECT * FROM users WHERE phone = '13800138000';EXPLAIN 是分析索引使用情况的强大工具,能帮助识别性能问题:
sql
EXPLAIN SELECT * FROM users WHERE status = 'active' AND age > 25;关键输出字段解析:
覆盖索引是指索引包含查询所需的所有字段,无需回表查询数据:
sql
-- 创建包含所需所有字段的复合索引
CREATE INDEX idx_user_status_age_name ON users(status, age, username);
-- 查询只使用索引中的字段,无需访问表数据
SELECT username, age FROM users WHERE status = 'active' AND age > 25;sql
ANALYZE TABLE users;sql
-- InnoDB表重建索引
ALTER TABLE users ENGINE=InnoDB;
-- 或优化特定索引
REBUILD INDEX idx_user_email ON users;ini
# my.cnf配置
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 2
log_queries_not_using_indexes = 1订单表常见查询场景:
合理的索引设计:
sql
CREATE TABLE orders (
id INT PRIMARY KEY AUTO_INCREMENT,
order_no VARCHAR(50) NOT NULL,
user_id INT NOT NULL,
status ENUM('pending', 'paid', 'shipped', 'delivered') NOT NULL,
create_time DATETIME NOT NULL,
total_amount DECIMAL(10,2) NOT NULL,
-- 唯一索引确保订单号不重复
UNIQUE INDEX idx_order_no (order_no),
-- 按用户查询订单
INDEX idx_user_id (user_id),
-- 复合索引支持按状态和时间查询
INDEX idx_status_create_time (status, create_time)
);sql
CREATE TABLE articles (
id INT PRIMARY KEY AUTO_INCREMENT,
title VARCHAR(200) NOT NULL,
content TEXT NOT NULL,
author_id INT NOT NULL,
category_id INT NOT NULL,
publish_time DATETIME NOT NULL,
views INT DEFAULT 0,
-- 按作者查询文章
INDEX idx_author_id (author_id),
-- 按分类和发布时间查询
INDEX idx_category_publish_time (category_id, publish_time),
-- 全文索引支持内容搜索
FULLTEXT INDEX idx_article_content (title, content)
);索引是 MySQL 性能优化的关键,但并非越多越好。优秀的索引设计需要:
记住,没有放之四海而皆准的索引方案,最佳实践是根据具体业务场景进行设计,并通过持续监控和优化来保持数据库的高性能。
希望本文能帮助你建立对 MySQL 索引的系统认知,在实际项目中设计出更高效的数据库结构。如果你有任何索引优化的经验或疑问,欢迎在评论区分享讨论!
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。