-- 添加普通索引 ALTER TABLE users ADD INDEX idx_email (email);
-- 添加唯一索引 ALTER TABLE users ADDUNIQUE INDEX idx_email_unique (email);
-- 添加主键索引 ALTER TABLE users ADDPRIMARY KEY (id);
-- 添加组合索引 ALTER TABLE orders ADD INDEX idx_user_status (user_id, status);
-- 添加前缀索引(针对长字符串) ALTER TABLE users ADD INDEX idx_email_prefix (email(10));
使用 CREATE INDEX 创建索引
1 2 3 4 5 6 7 8 9
-- 创建普通索引 CREATE INDEX index_name ON table_name (column_list);
-- 创建唯一索引 CREATEUNIQUE INDEX index_name ON table_name (column_list);
-- 示例 CREATE INDEX idx_username ON users (username); CREATEUNIQUE INDEX idx_phone ON users (phone);
删除索引
1 2 3 4 5 6 7 8
-- 使用 DROP INDEX DROP INDEX index_name ON table_name;
-- 使用 ALTER TABLE ALTER TABLE table_name DROP INDEX index_name;
-- 删除主键索引 ALTER TABLE table_name DROPPRIMARY KEY;
索引创建最佳实践
1 2 3 4 5 6 7 8 9 10 11 12 13
-- 示例表结构 CREATE TABLE `orders` ( `id` bigint unsigned NOT NULL AUTO_INCREMENT, `user_id` bigint unsigned NOT NULL, `order_no` varchar(32) NOT NULL, `status` tinyint unsigned NOT NULLDEFAULT'0', `amount` decimal(10,2) NOT NULL, `created_at` datetime NOT NULLDEFAULTCURRENT_TIMESTAMP, PRIMARY KEY (`id`), UNIQUE KEY `uk_order_no` (`order_no`), KEY `idx_user_id` (`user_id`), KEY `idx_status_created` (`status`, `created_at`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
组合索引设计原则
最左前缀法则
组合索引的查询条件必须从索引的最左边字段开始匹配,否则索引不会被使用。
1 2 3 4 5 6 7 8 9 10 11 12 13
-- 组合索引:(a, b, c) ALTER TABLE test ADD INDEX idx_abc (a, b, c);
-- 能使用索引的查询 SELECT*FROM test WHERE a =1; -- 使用 a SELECT*FROM test WHERE a =1AND b =2; -- 使用 a, b SELECT*FROM test WHERE a =1AND b =2AND c =3; -- 使用 a, b, c SELECT*FROM test WHERE a =1AND c =3; -- 只使用 a(c 跳跃了 b)
-- 不能使用索引的查询 SELECT*FROM test WHERE b =2; -- 缺少 a SELECT*FROM test WHERE b =2AND c =3; -- 缺少 a SELECT*FROM test WHERE c =3; -- 缺少 a, b
-- 差的设计: ALTER TABLE orders ADD INDEX idx_status (status); ALTER TABLE orders ADD INDEX idx_user_id (user_id); ALTER TABLE orders ADD INDEX idx_created_at (created_at); -- 问题:idx_status 选择性低(只有几种状态),idx_user_id 和 idx_created_at 无法联合使用
-- 好的设计: ALTER TABLE orders ADD INDEX idx_user_status_created (user_id, status, created_at); -- 优势: -- • WHERE user_id = ? 可以使用索引 -- • WHERE user_id = ? AND status = ? 可以使用索引 -- • WHERE user_id = ? ORDER BY created_at 可以使用索引(避免排序) -- • WHERE user_id = ? AND status = ? AND created_at > ? 可以使用索引
索引失效的常见场景
场景一:隐式类型转换
当查询条件中的字段类型与索引字段类型不一致时,MySQL 会进行隐式类型转换,导致索引失效。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
-- 表结构:pid VARCHAR(20),建有索引 CREATE TABLE products ( `pid` VARCHAR(20) NOT NULL, `name` VARCHAR(100), INDEX `idx_pid` (`pid`) );
-- 索引失效:pid 是字符串类型,但查询条件传入数字 SELECT*FROM products WHERE pid =1211111111; -- MySQL 会先将 pid 列转换为数字再比较 -- 相当于:CAST(pid AS UNSIGNED) = 1211111111 -- 导致全表扫描
-- 正确使用:传入字符串类型 SELECT*FROM products WHERE pid ='1211111111'; -- 索引有效