MySQL 索引、事务与约束操作命令大全

说明 :本文涵盖 MySQL 中三类重要功能:索引 (提高查询性能)、事务 (保证数据一致性)、约束(保证数据完整性)。每条命令附语法和实用示例,覆盖 MySQL 5.7 和 8.0 的常见特性。


一、索引操作

索引用于加速数据检索,但会占用额外存储空间并影响写性能。

1.1 创建索引

1.1.1 使用 CREATE INDEX 语句

语法

sql 复制代码
CREATE [UNIQUE | FULLTEXT | SPATIAL] INDEX 索引名
    ON 表名 (列名 [(长度)] [ASC | DESC], ...)
    [USING {BTREE | HASH}]
    [索引选项];

示例

sql 复制代码
-- 普通索引
CREATE INDEX idx_username ON users(username);

-- 唯一索引(不允许重复值)
CREATE UNIQUE INDEX idx_email ON users(email);

-- 全文索引(适用于 MyISAM 或 InnoDB MySQL 5.6+)
CREATE FULLTEXT INDEX ft_content ON articles(title, content);

-- 空间索引(用于地理数据,需 MyISAM/InnoDB 支持)
CREATE SPATIAL INDEX idx_location ON places(location);

-- 复合索引(多列)
CREATE INDEX idx_name_age ON users(last_name, first_name, age);

-- 前缀索引(仅索引字符串的前N个字符)
CREATE INDEX idx_title_prefix ON books(title(20));

-- 降序索引(MySQL 8.0 真正支持)
CREATE INDEX idx_created_desc ON orders(created_at DESC);

-- 指定索引类型(BTREE 是默认)
CREATE INDEX idx_hash ON temp_table(id) USING HASH;

1.1.2 在 CREATE TABLE 时创建索引

sql 复制代码
CREATE TABLE users (
    id INT PRIMARY KEY,
    name VARCHAR(50),
    email VARCHAR(100) UNIQUE,
    last_login DATETIME,
    INDEX idx_last_login (last_login),
    FULLTEXT INDEX ft_name (name)
);

1.1.3 使用 ALTER TABLE 创建索引

sql 复制代码
-- 添加主键索引(只能通过 ALTER 或 CREATE TABLE)
ALTER TABLE users ADD PRIMARY KEY (id);

-- 添加唯一索引
ALTER TABLE users ADD UNIQUE INDEX idx_email (email);

-- 添加普通索引
ALTER TABLE users ADD INDEX idx_name (name);

-- 添加全文索引
ALTER TABLE articles ADD FULLTEXT INDEX ft_body (body);

-- 添加空间索引
ALTER TABLE places ADD SPATIAL INDEX idx_geom (geom);

1.2 查看索引

sql 复制代码
-- 查看表的所有索引
SHOW INDEX FROM 表名;
SHOW INDEX FROM 表名\G   -- 垂直显示更详细

-- 从information_schema中查询
SELECT * FROM INFORMATION_SCHEMA.STATISTICS 
WHERE TABLE_SCHEMA = '数据库名' AND TABLE_NAME = '表名';

1.3 删除索引

sql 复制代码
-- 使用 DROP INDEX 语句
DROP INDEX 索引名 ON 表名;

-- 使用 ALTER TABLE 删除
ALTER TABLE 表名 DROP INDEX 索引名;

-- 删除主键索引(特殊)
ALTER TABLE 表名 DROP PRIMARY KEY;

-- 删除外键索引(实际删除的是外键约束,索引可能保留)
ALTER TABLE 表名 DROP FOREIGN KEY 外键约束名;

示例

sql 复制代码
DROP INDEX idx_username ON users;
ALTER TABLE users DROP INDEX idx_email;
ALTER TABLE orders DROP PRIMARY KEY;   -- 删除主键

1.4 修改索引

MySQL 没有直接"修改索引"的命令,通常采用"删除后重建"的方式:

sql 复制代码
-- 先删除旧索引
DROP INDEX idx_old ON table_name;
-- 再创建新索引
CREATE INDEX idx_new ON table_name (column1, column2);

如果只是想重命名索引(MySQL 5.7+ 支持 ALTER TABLE 重命名):

sql 复制代码
ALTER TABLE 表名 RENAME INDEX 旧索引名 TO 新索引名;

-- 示例
ALTER TABLE users RENAME INDEX idx_username TO idx_uname;

1.5 索引可见性(MySQL 8.0)

可以设置索引对优化器是否可见,而不实际删除索引。

sql 复制代码
-- 设置索引不可见(优化器忽略该索引)
ALTER TABLE 表名 ALTER INDEX 索引名 INVISIBLE;

-- 设置索引可见
ALTER TABLE 表名 ALTER INDEX 索引名 VISIBLE;

-- 示例
ALTER TABLE users ALTER INDEX idx_email INVISIBLE;

1.6 强制使用或忽略索引(查询提示)

sql 复制代码
-- 强制使用索引
SELECT * FROM users FORCE INDEX (idx_username) WHERE username = 'john';

-- 忽略索引
SELECT * FROM users IGNORE INDEX (idx_username) WHERE username = 'john';

-- 使用索引(建议,优化器可自行决定)
SELECT * FROM users USE INDEX (idx_username) WHERE username = 'john';

二、事务操作

事务保证一组操作要么全部成功(COMMIT),要么全部失败回滚(ROLLBACK),满足 ACID 特性。

2.1 事务控制语句

| 命令 | 说明 |
|-------------------------------|-------------------|-----------------|
| START TRANSACTIONBEGIN | 显式开启一个新事务 |
| COMMIT | 提交事务,使更改永久生效 |
| ROLLBACK | 回滚事务,撤销当前事务中的所有更改 |
| SAVEPOINT 名称 | 在事务中设置保存点 |
| ROLLBACK TO SAVEPOINT 名称 | 回滚到指定保存点 |
| RELEASE SAVEPOINT 名称 | 删除保存点 |
| `SET autocommit = {0 | 1}` | 禁用(0)/启用(1)自动提交 |

2.2 自动提交模式

MySQL 默认 autocommit = 1,每条 DML 自动提交。要使用多语句事务,需先禁用自动提交或显式 START TRANSACTION

sql 复制代码
-- 查看当前自动提交设置
SELECT @@autocommit;

-- 关闭自动提交(仅当前会话)
SET autocommit = 0;

-- 开启自动提交
SET autocommit = 1;

2.3 基本事务示例

sql 复制代码
-- 方式一:使用 START TRANSACTION
START TRANSACTION;
    UPDATE accounts SET balance = balance - 100 WHERE id = 1;
    UPDATE accounts SET balance = balance + 100 WHERE id = 2;
COMMIT;   -- 或 ROLLBACK

-- 方式二:使用 BEGIN
BEGIN;
    INSERT INTO logs (user_id, action) VALUES (1, '转账');
    SAVEPOINT sp1;
    UPDATE accounts SET balance = balance - 100 WHERE id = 1;
    -- 发现错误,回滚到保存点
    ROLLBACK TO SAVEPOINT sp1;
COMMIT;   -- INSERT 已提交,UPDATE 被撤销

2.4 保存点(SAVEPOINT)

sql 复制代码
START TRANSACTION;
    INSERT INTO orders (user_id, amount) VALUES (1, 500);
    SAVEPOINT after_insert;
    
    UPDATE inventory SET stock = stock - 5 WHERE product_id = 10;
    -- 库存不足,决定回滚到保存点
    ROLLBACK TO SAVEPOINT after_insert;
    
    -- 可继续其他操作
    INSERT INTO order_log (msg) VALUES ('库存不足,未扣减');
    
    -- 释放不再需要的保存点
    RELEASE SAVEPOINT after_insert;
COMMIT;

2.5 事务隔离级别

隔离级别影响事务并发时的可见性。

查看当前隔离级别

sql 复制代码
-- 全局级
SELECT @@global.transaction_isolation;
-- 会话级
SELECT @@transaction_isolation;

设置隔离级别

sql 复制代码
-- 设置会话隔离级别
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;  -- MySQL 默认
SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;

-- 设置全局隔离级别(需要 SUPER 权限)
SET GLOBAL TRANSACTION ISOLATION LEVEL READ COMMITTED;

2.6 锁语句(辅助事务)

sql 复制代码
-- 共享锁(读锁)
SELECT * FROM accounts WHERE id = 1 LOCK IN SHARE MODE;

-- 排他锁(写锁)
SELECT * FROM accounts WHERE id = 1 FOR UPDATE;

-- 表锁(手动)
LOCK TABLES accounts WRITE;
-- 执行更新...
UNLOCK TABLES;

2.7 XA 事务(分布式事务)

sql 复制代码
XA START 'xid1';        -- 开启 XA 事务
    UPDATE accounts SET balance = balance - 100 WHERE id = 1;
XA END 'xid1';
XA PREPARE 'xid1';      -- 准备阶段
XA COMMIT 'xid1';       -- 提交
-- 或 XA ROLLBACK 'xid1';

2.8 查看事务信息

sql 复制代码
-- 查看当前正在运行的事务
SELECT * FROM information_schema.INNODB_TRANSACTION;

-- 查看锁信息
SELECT * FROM information_schema.INNODB_LOCKS;
SELECT * FROM information_schema.INNODB_LOCK_WAITS;

-- 查看引擎状态(包含事务详情)
SHOW ENGINE INNODB STATUS\G

三、约束操作

约束用于限制表中数据的合法性和完整性。

3.1 约束类型概览

约束类型 关键字 作用
主键约束 PRIMARY KEY 唯一标识一行,非空且唯一
外键约束 FOREIGN KEY 参照另一表的主键,维护引用完整性
唯一约束 UNIQUE 列值不能重复(可多个 NULL)
检查约束 CHECK 限制列值满足条件(MySQL 8.0.16+ 完整支持)
非空约束 NOT NULL 列值不能为 NULL
默认约束 DEFAULT 提供默认值

3.2 主键约束(PRIMARY KEY)

创建主键

sql 复制代码
-- 列级定义
CREATE TABLE t1 (id INT PRIMARY KEY, name VARCHAR(50));

-- 表级定义(适合复合主键)
CREATE TABLE t2 (
    user_id INT,
    role_id INT,
    PRIMARY KEY (user_id, role_id)
);

-- 为已有表添加主键
ALTER TABLE t1 ADD PRIMARY KEY (id);

-- 添加自增属性
ALTER TABLE t1 MODIFY id INT AUTO_INCREMENT;

删除主键

sql 复制代码
ALTER TABLE t1 DROP PRIMARY KEY;

⚠️ 如果主键列是自增列,需先修改列定义去掉 AUTO_INCREMENT

3.3 外键约束(FOREIGN KEY)

外键用于维持两张表之间的引用完整性。

创建外键

sql 复制代码
-- 建表时定义
CREATE TABLE orders (
    order_id INT PRIMARY KEY,
    user_id INT,
    FOREIGN KEY (user_id) REFERENCES users(id)
        ON DELETE CASCADE ON UPDATE RESTRICT
);

-- 带约束名
CREATE TABLE orders (
    order_id INT PRIMARY KEY,
    user_id INT,
    CONSTRAINT fk_orders_user FOREIGN KEY (user_id) REFERENCES users(id)
);

-- 为已有表添加外键
ALTER TABLE orders ADD CONSTRAINT fk_user 
    FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE SET NULL;

外键选项

  • ON DELETE CASCADE:主表记录删除,子表相关记录自动删除
  • ON DELETE SET NULL:子表外键列设为 NULL
  • ON DELETE RESTRICT / NO ACTION:阻止删除(默认行为)
  • ON UPDATE CASCADE:主键更新时同步更新子表外键
  • ON UPDATE SET NULL:主键更新时子表外键设为 NULL

查看外键

sql 复制代码
SELECT * FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE 
WHERE TABLE_NAME = 'orders' AND CONSTRAINT_NAME NOT IN ('PRIMARY');

-- 或使用 SHOW CREATE TABLE
SHOW CREATE TABLE orders\G

删除外键

sql 复制代码
-- 必须使用约束名删除
ALTER TABLE orders DROP FOREIGN KEY fk_orders_user;

-- 如果不知道约束名,可通过 SHOW CREATE TABLE 查看

禁用/启用外键检查(全局会话)

sql 复制代码
-- 暂时禁用外键检查(可用于重排序表导入)
SET FOREIGN_KEY_CHECKS = 0;

-- 执行数据操作(如 TRUNCATE 被引用的表)

-- 恢复检查
SET FOREIGN_KEY_CHECKS = 1;

3.4 唯一约束(UNIQUE)

创建唯一约束

sql 复制代码
-- 列级
CREATE TABLE users (email VARCHAR(100) UNIQUE);

-- 表级命名
CREATE TABLE users (
    email VARCHAR(100),
    CONSTRAINT uk_email UNIQUE (email)
);

-- 复合唯一约束
CREATE TABLE user_roles (
    user_id INT,
    role_id INT,
    UNIQUE KEY uk_user_role (user_id, role_id)
);

-- 为已有表添加
ALTER TABLE users ADD UNIQUE INDEX uk_email (email);
-- 或
ALTER TABLE users ADD CONSTRAINT uk_username UNIQUE (username);

删除唯一约束

sql 复制代码
-- 唯一约束会自动创建同名索引,通过删除索引即可
ALTER TABLE users DROP INDEX uk_email;

3.5 检查约束(CHECK)

MySQL 8.0.16+ 完整支持 CHECK;早期版本解析但不执行。

创建 CHECK

sql 复制代码
-- 列级 CHECK
CREATE TABLE products (
    price DECIMAL(10,2) CHECK (price > 0),
    quantity INT CHECK (quantity >= 0)
);

-- 表级 CHECK(可命名)
CREATE TABLE employees (
    id INT,
    salary DECIMAL(10,2),
    CONSTRAINT chk_salary CHECK (salary >= 0)
);

-- 跨列 CHECK
CREATE TABLE reservations (
    start_date DATE,
    end_date DATE,
    CHECK (start_date < end_date)
);

-- 为已有表添加 CHECK
ALTER TABLE users ADD CONSTRAINT chk_age CHECK (age BETWEEN 0 AND 150);

删除 CHECK

sql 复制代码
ALTER TABLE users DROP CONSTRAINT chk_age;

查看 CHECK 约束

sql 复制代码
SELECT * FROM INFORMATION_SCHEMA.CHECK_CONSTRAINTS 
WHERE CONSTRAINT_SCHEMA = '数据库名' AND TABLE_NAME = '表名';

3.6 非空约束(NOT NULL)

添加非空

sql 复制代码
-- 建表时
CREATE TABLE t (id INT NOT NULL);

-- 修改已有列
ALTER TABLE users MODIFY email VARCHAR(100) NOT NULL;

删除非空(允许 NULL)

sql 复制代码
ALTER TABLE users MODIFY email VARCHAR(100) NULL;

3.7 默认约束(DEFAULT)

设置默认值

sql 复制代码
-- 建表时
CREATE TABLE t (status VARCHAR(20) DEFAULT 'active');

-- 修改已有列默认值(两种方法)
ALTER TABLE users ALTER COLUMN status SET DEFAULT 'inactive';
-- 或
ALTER TABLE users MODIFY status VARCHAR(20) DEFAULT 'inactive';

-- 设置表达式默认值(MySQL 8.0+)
CREATE TABLE t (created_at DATETIME DEFAULT (NOW()));

删除默认值

sql 复制代码
ALTER TABLE users ALTER COLUMN status DROP DEFAULT;

3.8 查看所有约束

sql 复制代码
-- 通过 INFORMATION_SCHEMA 查看表的所有约束
SELECT CONSTRAINT_NAME, CONSTRAINT_TYPE 
FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS 
WHERE TABLE_SCHEMA = '数据库名' AND TABLE_NAME = '表名';

3.9 修改约束的其他方式

由于没有直接的"修改约束"命令,通常需要删除后重建。例如修改 NOT NULLNULL 允许,或修改 CHECK 条件。

sql 复制代码
-- 修改 CHECK:先删除,再添加
ALTER TABLE t DROP CONSTRAINT chk_old;
ALTER TABLE t ADD CONSTRAINT chk_new CHECK (new_condition);

3.10 完整的约束管理示例

sql 复制代码
-- 创建带所有约束类型的表
CREATE TABLE employees (
    id INT PRIMARY KEY AUTO_INCREMENT,
    emp_no VARCHAR(20) NOT NULL UNIQUE,
    name VARCHAR(100) NOT NULL,
    age INT DEFAULT 25 CHECK (age >= 18 AND age <= 65),
    dept_id INT,
    salary DECIMAL(10,2) CHECK (salary >= 0),
    email VARCHAR(100),
    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
    CONSTRAINT fk_dept FOREIGN KEY (dept_id) REFERENCES departments(id)
);

-- 添加新约束
ALTER TABLE employees ADD CONSTRAINT chk_salary_positive CHECK (salary > 0);
ALTER TABLE employees MODIFY email VARCHAR(100) NOT NULL;

-- 删除约束
ALTER TABLE employees DROP FOREIGN KEY fk_dept;
ALTER TABLE employees DROP CONSTRAINT chk_salary_positive;
ALTER TABLE employees MODIFY email VARCHAR(100) NULL;

-- 查看最终约束
SELECT CONSTRAINT_NAME, CONSTRAINT_TYPE 
FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS 
WHERE TABLE_NAME = 'employees';

四、综合应用场景示例

4.1 索引与事务配合

sql 复制代码
-- 开启事务,在更新前检查索引使用情况
START TRANSACTION;
    -- 使用排他锁锁定待更新行
    SELECT * FROM accounts WHERE account_no = 'A123' FOR UPDATE;
    
    -- 确保 account_no 列有唯一索引
    CREATE UNIQUE INDEX idx_acc_no ON accounts(account_no);
    
    UPDATE accounts SET balance = balance - 500 WHERE account_no = 'A123';
    UPDATE accounts SET balance = balance + 500 WHERE account_no = 'B456';
COMMIT;

4.2 约束与事务保证数据一致性

sql 复制代码
START TRANSACTION;
    -- 检查外键关系
    SET FOREIGN_KEY_CHECKS = 0;   -- 临时关闭(谨慎)
    DELETE FROM departments WHERE id = 10;
    -- 实际应使用 ON DELETE CASCADE 或先删除子表记录
    SET FOREIGN_KEY_CHECKS = 1;
COMMIT;

五、最佳实践与注意事项

方面 建议
索引 避免过多索引(影响写性能);复合索引遵循最左前缀原则;使用 EXPLAIN 分析查询;定期清理无用索引。
事务 尽量短小,避免长事务;合理选择隔离级别(通常 READ COMMITTEDREPEATABLE READ);使用 SAVEPOINT 实现部分回滚;避免在事务中进行用户交互或网络调用。
约束 优先使用数据库约束而非应用层校验;外键会带来额外开销,但能保证引用完整性;CHECK 在 MySQL 8.0 之前不生效,注意兼容性;修改约束前备份数据。

以上内容涵盖了 MySQL 中索引、事务和约束的所有核心操作命令,包括创建、查看、删除、修改及管理语句,并附有详细示例。根据实际业务场景灵活运用即可。

相关推荐
Rust语言中文社区2 小时前
【Rust日报】2026-04-24 Vizia 0.4 发布——纯 Rust 声明式响应式 GUI 框架
开发语言·后端·rust
Lisonseekpan2 小时前
Git:如何将一个分支的特定提交合并到另一个分支?
java·大数据·git·后端·elasticsearch
程序员Better2 小时前
前端成功转型AI全栈,我踩过的坑都替你填上了
前端·后端·ai编程
兔子零10242 小时前
GPT-5.5 与 DeepSeek-V4:大模型竞争的本质,正在从“谁更强”变成“谁让成本更低”
前端·javascript·后端
楼田莉子4 小时前
CMake学习:CMake语法
c++·后端·学习·软件构建
无限进步_4 小时前
C++ 继承机制完全解析:从基础原理到菱形继承问题
java·开发语言·数据结构·c++·vscode·后端·算法
武子康4 小时前
大数据-278 Spark MLib-GBDT梯度提升决策树详解:从原理到实战案例
大数据·后端·spark
SamDeepThinking4 小时前
适合中小型企业的出口入口网关微服务
java·后端·架构