今天我们来聊聊 MySQL 中的索引分类,这可是数据库优化的重中之重。作为一个资深 Java 开发工程师,我经常碰到各种关于索引的疑问。干货满满,技术点不少,记得收藏。
在 MySQL 中,索引主要可以从四个角度进行分类:数据结构、物理存储、字段特性和字段个数。这些分类不仅仅是面试时的考点,更是日常开发中优化查询性能的必修课。
首先,从数据结构的角度来看,MySQL 支持三种主要索引结构:B+Tree 索引、Hash 索引和 Full-Text 索引。
InnoDB 默认支持 B+Tree 索引,这是最常用的结构。B+Tree 是一个高度平衡的树结构,其叶子节点保存着完整的数据,查询效率高,适用于范围查询和排序操作。
-- 创建一个使用 B+Tree 索引的表
CREATE TABLE users (
id INT PRIMARY KEY,
name VARCHAR(100),
email VARCHAR(100)
) ENGINE=InnoDB;
Hash 索引则适合等值查询,常用于 Memory 引擎。例如:
-- 使用 HASH 索引创建表
CREATE TABLE cache (
id INT,
value VARCHAR(100),
PRIMARY KEY (id)
) ENGINE=MEMORY;
Full-Text 索引常用于全文检索,适合大段文本的查询,如博客内容:
-- 使用全文索引
CREATE TABLE articles (
id INT PRIMARY KEY,
title VARCHAR(200),
content TEXT,
FULLTEXT (title, content)
);
接下来,从物理存储的角度,MySQL 索引分为聚簇索引和二级索引。聚簇索引存储实际的数据记录,InnoDB 表默认使用主键作为聚簇索引。
如果没有主键,InnoDB 会自动选择第一个非 NULL 的唯一列,或者创建一个隐式的内部 ID 列。二级索引保存的是主键值,查询时需要通过二级索引找到主键,再去主键索引中定位实际数据,这个过程称为“回表”。
-- 演示主键索引和二级索引
CREATE TABLE orders (
order_id INT PRIMARY KEY, -- 聚簇索引
customer_id INT,
amount DECIMAL(10,2),
INDEX (customer_id) -- 二级索引
);
从字段特性来看,索引可分为主键索引、唯一索引、普通索引和前缀索引。主键索引强制唯一,且不能为空。
唯一索引也要求值唯一,但允许空值。普通索引无特殊约束,用于加速查询。前缀索引则只索引字段的前几个字符,节省存储空间,常用于长文本字段。
-- 创建不同类型的索引
CREATE TABLE products (
product_id INT PRIMARY KEY, -- 主键索引
product_code VARCHAR(100),
product_name VARCHAR(255),
UNIQUE (product_code), -- 唯一索引
INDEX (product_name(10)) -- 前缀索引
);
最后,从字段个数来看,索引分为单列索引和联合索引。单列索引只针对一个字段,联合索引则针对多个字段组合。联合索引遵循“最左匹配原则”:查询从左至右依次匹配,遇到范围查询时停止匹配。
-- 创建联合索引
CREATE TABLE employees (
emp_id INT PRIMARY KEY,
first_name VARCHAR(50),
last_name VARCHAR(50),
department_id INT,
INDEX idx_name_department (first_name, last_name, department_id)
);
-- 查询示例(最左匹配)
SELECT * FROM employees WHERE first_name = 'John'; -- 命中索引
SELECT * FROM employees WHERE first_name = 'John' AND last_name = 'Doe'; -- 命中索引
SELECT * FROM employees WHERE last_name = 'Doe'; -- 无法使用索引
最后,面试官问你:什么是联合索引?最左匹配原则是什么?
你的回答:联合索引是对多个字段组合建立的索引,在 B+Tree 中这些字段的值会被组合成一个键值对。MySQL 在查询时会按联合索引的定义顺序进行匹配。
这遵循“最左匹配原则”:查询时必须从联合索引的最左侧字段开始匹配,匹配过程从左到右依次进行,一旦遇到范围查询或缺失字段,匹配过程就会中断。
例如,对于联合索引 (a, b, c)
,查询 WHERE a=1 AND b=2
可以使用索引,但查询 WHERE b=2
无法命中索引。
这样解释是不是清晰多了?学会了这些,你的数据库技能又进阶了一级。还有什么数据库疑问,评论区见!