13人参与 • 2025-10-21 • Mysql

索引(index)是数据库管理系统中一种重要的数据结构,它为表中的数据创建了一个有序的引用结构,类似于书籍的目录。通过索引,数据库可以快速定位到特定的数据行,而不需要扫描整个表。
-- 创建一个示例表
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)
);
索引在数据库性能优化中扮演着至关重要的角色:
-- 没有索引的查询(全表扫描) select * from users where username = 'john_doe'; -- 有索引的查询(索引查找) -- 执行计划会显示使用 idx_username 索引 explain select * from users where username = 'john_doe';

优点:
缺点:
主键索引是表中最重要的索引,每个表只能有一个主键索引,它具有唯一性且不能为空。
-- 创建表时定义主键
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);唯一索引确保索引列的值在表中是唯一的,但允许 null 值。
-- 创建唯一索引
create unique index idx_email on users (email);
-- 或者在创建表时定义
create table users (
id int primary key,
email varchar(100) unique
);普通索引是最基本的索引类型,没有唯一性限制。
-- 创建普通索引 create index idx_username on users (username); create index idx_age on users (age); -- 查看索引使用情况 explain select * from users where username = 'alice' and age > 25;
复合索引包含多个列,遵循最左前缀原则。
-- 创建复合索引 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'; -- 跳过了最左列
全文索引用于文本搜索,支持自然语言搜索和布尔搜索。
-- 创建全文索引
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 索引优化' in natural language mode);mysql 的 innodb 存储引擎使用 b+ 树作为索引的数据结构。b+ 树具有以下特点:
-- 演示 b+ 树索引的范围查询优势 select * from users where age between 25 and 35 order by age; -- 由于 b+ 树的有序性,这个查询非常高效

聚簇索引(clustered index):
非聚簇索引(non-clustered index):
-- 创建测试表演示聚簇索引和非聚簇索引
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;-- 查看表的索引信息
show index from users;
-- 查看索引的存储统计信息
select
table_name,
index_name,
stat_name,
stat_value
from mysql.innodb_index_stats
where table_name = 'users';-- 基本语法 create [unique|fulltext] index index_name on table_name (column1, column2, ...); -- 实际示例 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 创建索引 alter table users add index idx_created_at (created_at); alter table users add unique index idx_username_email (username, email);
-- 查看表的所有索引
show index from users;
-- 查看索引使用统计
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';-- 删除索引 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;
-- mysql 不支持直接修改索引,需要先删除再创建 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);
索引选择性是指索引列中不同值的数量与表中记录总数的比值。选择性越高,索引效果越好。
-- 计算列的选择性
select
count(distinct username) / count(*) as username_selectivity,
count(distinct email) / count(*) as email_selectivity,
count(distinct age) / count(*) as age_selectivity
from users;
-- 分析最适合创建索引的列
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';使用 explain 分析查询的执行计划,优化索引使用。
-- 分析查询执行计划 explain select * from users where username = 'john' and age > 25; -- 详细的执行计划分析 explain format=json select * from users where username = 'john' and age > 25; -- 实际执行统计 explain analyze select * from users where username = 'john' and age > 25;
索引覆盖是指查询所需的所有列都包含在索引中,避免回表操作。
-- 创建覆盖索引 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 列会显示 "using index"
-- 索引失效的常见情况 -- 1. 使用函数或表达式 -- 错误:索引失效 select * from users where upper(username) = 'john'; -- 正确:使用索引 select * from users where username = 'john'; -- 2. 使用 like 以通配符开头 -- 错误:索引失效 select * from users where username like '%john%'; -- 正确:使用索引 select * from users where username like 'john%'; -- 3. 使用 or 连接不同列 -- 错误:可能索引失效 select * from users where username = 'john' or age = 25; -- 正确:使用 union select * from users where username = 'john' union select * from users where age = 25; -- 4. 数据类型不匹配 -- 错误:索引失效 select * from users where age = '25'; -- age 是 int 类型 -- 正确:使用索引 select * from users where age = 25;

-- 好的索引设计示例
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),
-- 基于查询模式设计的复合索引
index idx_user_status_date (user_id, order_status, order_date),
-- 覆盖索引,避免回表
index idx_status_date_amount (order_status, order_date, total_amount)
);-- 陷阱1:过多的单列索引
-- 错误做法
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);
-- 正确做法:根据查询模式创建复合索引
create index idx_user_status_date on orders (user_id, order_status, order_date);
-- 陷阱2:重复索引
-- 错误:创建了重复的索引
create index idx_username on users (username);
create index idx_username_duplicate on users (username); -- 重复索引
-- 陷阱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;-- 定期分析表和索引统计信息
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;
-- 监控索引使用情况
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;通过本文的深入分析,我们可以总结出 mysql 索引优化的核心要点:
正确使用索引可以带来显著的性能提升:
随着数据库技术的不断发展,索引技术也在持续演进:
在实际项目中应用索引优化时,建议:
索引优化是一个持续的过程,需要结合具体的业务场景和数据特点,通过不断的分析、测试和调优,才能发挥索引的最大价值。掌握了这些核心概念和实践技巧,相信你能够在实际项目中有效地运用 mysql 索引,显著提升数据库的查询性能。
到此这篇关于mysql 索引从入门到精通(从原理到实践)的文章就介绍到这了,更多相关mysql索引从入门到精通内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
您想发表意见!!点此发布评论
版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。
发表评论