Mysql

关注公众号 jb51net

关闭
首页 > 数据库 > Mysql > MySQL从建表到索引管理

MySQL从建表到索引管理的完整指南

作者:️学习的小王

在数据库学习和开发中,掌握从基础表操作到高级性能优化(如索引)的完整 SQL 技能至关重要,本文将通过一个连贯的实战案例,手把手演示如何使用 MySQL 完成数据库创建、数据表管理、数据插入、表结构修改,需要的朋友可以参考下

1. 引言

在数据库学习和开发中,掌握从基础表操作到高级性能优化(如索引)的完整 SQL 技能至关重要。本文将通过一个连贯的实战案例,手把手演示如何使用 MySQL 完成数据库创建、数据表管理、数据插入、表结构修改,并深入讲解索引的创建、管理与核心原理。我们将创建一个名为 abc 的数据库,并在其中管理一个学生信息表 s1,通过具体的 SQL 语句讲解每个操作步骤及其背后的设计思考。

2. 创建数据库与选择数据库

首先,我们需要创建一个新的数据库来存放我们的数据表。

-- 创建数据库
CREATE DATABASE abc;

执行上述语句后,MySQL 会创建一个名为 abc 的数据库。接下来,我们需要告诉 MySQL 后续的操作都在这个数据库中进行。

-- 使用数据库
USE abc;

USE 语句用于选择当前要操作的数据库。执行后,所有未指定数据库的表操作都将默认在 abc 数据库中进行。

3. 创建学生信息表

在操作表之前,一个好的习惯是确保目标表不存在,避免因重复创建而报错。

-- 删除数据表(如果存在)
DROP TABLE IF EXISTS s1;

DROP TABLE IF EXISTS 是一个安全的做法,它只在表存在时才执行删除操作。

现在,我们来创建核心的学生信息表 s1

-- 创建学生表
CREATE TABLE s1 (
   id INT PRIMARY KEY AUTO_INCREMENT COMMENT '编号',
   s_name VARCHAR(20) UNIQUE NOT NULL COMMENT '姓名',
   age INT NOT NULL COMMENT '年龄',
   sex ENUM('男', '女', '未知') DEFAULT '未知' COMMENT '性别',
   s_sno CHAR(12) UNIQUE NOT NULL COMMENT '学号',
   tel CHAR(11) NOT NULL COMMENT '手机号',
   start_time DATE DEFAULT (CURRENT_DATE) COMMENT '入学时间',
   status ENUM('在读', '毕业') DEFAULT '在读' COMMENT '状态'
);

表结构说明:

4. 查看表结构信息

创建表后,我们可以通过多种方式查看其结构。

1. 查看表的基本字段信息(DESC)

-- 查看表结构
DESC s1;

DESC (或 DESCRIBE) 命令会以表格形式列出表的所有字段名、类型、是否为空、键信息、默认值和额外说明。

2. 查看字段信息(SHOW COLUMNS)

-- 查看字段
SHOW COLUMNS FROM s1;

SHOW COLUMNSDESC 功能类似,提供了另一种查看表结构的方式。

3. 查看完整的建表语句

-- 查看创建表语句
SHOW CREATE TABLE s1;

这条命令会返回创建该表的完整 SQL 语句,包括引擎、字符集等所有细节,对于备份或迁移表结构非常有用。

5. 向表中插入数据

表创建好后,我们需要向其中添加数据。以下是插入8条学生记录的示例:

-- 插入数据
INSERT INTO s1 VALUES (NULL, '张三', 18, '男', '2019001', '13888888888', '2020-09-01', '在读');
INSERT INTO s1 VALUES (NULL, '李四', 19, '女', '2019002', '13888888889', '2020-09-01', '在读');
INSERT INTO s1 VALUES (NULL, '王五', 20, '未知', '2019003', '13888888890', '2020-09-01', '在读');
INSERT INTO s1 VALUES (NULL, '赵六', 21, '男', '2019004', '13888888891', '2020-09-01', '在读');
INSERT INTO s1 VALUES (NULL, '孙七', 22, '女', '2019005', '13888888892', '2020-09-01', '在读');
INSERT INTO s1 VALUES (NULL, '周八', 23, '未知', '2019006', '13888888893', '2020-09-01', '在读');
INSERT INTO s1 VALUES (NULL, '吴九', 24, '男', '2019007', '13888888894', '2020-09-01', '在读');
INSERT INTO s1 VALUES (NULL, '郑十', 25, '女', '2019008', '13888888895', '2020-09-01', '在读');

注意:id 字段传入了 NULL,由于其是 AUTO_INCREMENT,数据库会自动为其生成递增值。

6. 修改表结构(ALTER TABLE)

在实际应用中,表结构可能需要调整。ALTER TABLE 语句用于添加、修改或删除表中的列。

1. 添加新字段
假设我们需要为学生表增加一个“身份证号”字段。

-- 添加身份证号字段
ALTER TABLE s1 ADD COLUMN id_card CHAR(18) COMMENT '身份证号';

2. 删除字段
如果添加的字段不再需要,可以将其删除。

-- 删除身份证号字段
ALTER TABLE s1 DROP COLUMN id_card;

7. 索引(Index)详解

7.1 索引是什么

索引是建立在数据表字段上的数据结构(MySQL InnoDB 默认使用 B+Tree),相当于书本的目录。

作用:快速定位数据,减少全表扫描,极大提升查询(SELECT)语句的速度

7.2 索引的优缺点

优点:

  1. 极大加快数据查询速度:特别是在 WHERE 条件筛选、ORDER BY 排序、GROUP BY 分组时效率提升显著。

缺点:

  1. 占用额外磁盘存储空间:索引本身需要存储。
  2. 降低 DML 性能:进行 INSERTUPDATEDELETE 操作时,数据库需要额外维护索引结构,可能导致写入变慢。
  3. 索引不是越多越好:无用的索引只会增加存储与写入开销,需要根据查询需求合理设计。

7.3 InnoDB 常见索引分类

主键索引 (PRIMARY)

唯一索引 (UNIQUE)

普通索引 (INDEX)

联合索引(复合索引)

全文索引 (FULLTEXT)

7.4 基础语法示例

以下示例基于已添加的 id_card 字段和已有的 s_nameage 字段。

1. 创建普通索引

-- 语法:CREATE INDEX 索引名 ON 表名(字段名);
CREATE INDEX name ON s1(s_name);

2. 创建联合索引

-- 语法:CREATE INDEX 索引名 ON 表名(字段名1, 字段名2);
CREATE INDEX name_age ON s1(s_name, age);

3. 创建全文索引

-- 语法:CREATE FULLTEXT INDEX 索引名 ON 表名(字段名);
CREATE FULLTEXT INDEX name_fulltext ON s1(s_name);

4. 创建唯一索引

-- 语法:CREATE UNIQUE INDEX 索引名 ON 表名(字段名);
CREATE UNIQUE INDEX idcard ON s1(id_card);

5. 查看索引

-- 语法:SHOW INDEX FROM 表名;
SHOW INDEX FROM s1;

该命令会显示表上所有索引的名称、类型、关联的字段、唯一性等信息。

6. 删除索引

-- 语法:DROP INDEX 索引名 ON 表名;
DROP INDEX idcard ON s1;

7.6 索引使用注意事项了解了索引的创建语法后,让我们通过具体的查询示例来展示索引如何提升性能。

示例1:普通索引加速查询

假设我们经常需要按学生姓名查询:

-- 无索引时的查询(全表扫描)
EXPLAIN SELECT * FROM s1 WHERE s_name = '张三';

-- 创建姓名索引后
CREATE INDEX idx_name ON s1(s_name);

-- 再次执行相同查询(使用索引)
EXPLAIN SELECT * FROM s1 WHERE s_name = '张三';

执行计划对比:

示例2:联合索引与最左前缀原则

创建联合索引后,观察不同查询条件的效果:

-- 创建联合索引
CREATE INDEX idx_name_age ON s1(s_name, age);

-- 情况1:使用索引(包含最左列s_name)
EXPLAIN SELECT * FROM s1 WHERE s_name = '李四' AND age = 19;

-- 情况2:使用索引(只使用最左列s_name)
EXPLAIN SELECT * FROM s1 WHERE s_name = '王五';

-- 情况3:索引失效(未包含最左列s_name)
EXPLAIN SELECT * FROM s1 WHERE age = 20;

-- 情况4:部分使用索引(s_name范围查询,age无法使用索引)
EXPLAIN SELECT * FROM s1 WHERE s_name LIKE '张%' AND age = 18;

示例3:唯一索引防止重复数据

-- 尝试插入重复学号(会失败)
INSERT INTO s1 VALUES (NULL, '测试', 20, '男', '2019001', '13800000000', '2020-09-01', '在读');
-- 错误:Duplicate entry '2019001' for key 's_sno'

-- 查看唯一约束错误信息
SHOW ERRORS;

示例4:索引对排序的优化

-- 无索引时的排序(可能使用文件排序)
EXPLAIN SELECT * FROM s1 ORDER BY s_name;

-- 创建索引后
CREATE INDEX idx_name ON s1(s_name);

-- 再次执行排序(可能使用索引排序)
EXPLAIN SELECT * FROM s1 ORDER BY s_name;

示例5:索引失效场景演示

-- 1. 在索引列上使用函数(索引失效)
EXPLAIN SELECT * FROM s1 WHERE LEFT(s_name, 1) = '张';

-- 2. 隐式类型转换(索引失效)
-- 假设tel字段是CHAR(11),但查询时使用数字
EXPLAIN SELECT * FROM s1 WHERE tel = 13888888888;

-- 3. 使用OR条件(如果OR的某一侧没有索引,可能导致全表扫描)
EXPLAIN SELECT * FROM s1 WHERE s_name = '张三' OR age = 18;

-- 4. 使用不等于(!=或<>)(可能无法使用索引)
EXPLAIN SELECT * FROM s1 WHERE s_name != '张三';

示例6:覆盖索引(Covering Index)

-- 创建覆盖索引
CREATE INDEX idx_covering ON s1(s_name, age, sex);

-- 查询只涉及索引列,无需回表
EXPLAIN SELECT s_name, age FROM s1 WHERE s_name = '赵六' AND age > 20;

-- Extra列显示"Using index"表示使用了覆盖索引

示例7:索引选择性测试

-- 查看字段值的分布情况(评估索引效果)
SELECT 
    COUNT(DISTINCT sex) as sex_distinct_count,
    COUNT(DISTINCT age) as age_distinct_count,
    COUNT(DISTINCT s_name) as name_distinct_count,
    COUNT(*) as total_rows
FROM s1;

-- 在区分度高的字段上建索引效果更好
-- sex只有3种值,区分度低
-- s_name有8种值(假设不重复),区分度高

示例8:多列索引顺序优化

-- 根据查询频率和选择性决定索引列顺序
-- 假设查询模式1:WHERE age > 20 AND sex = '男'
-- 假设查询模式2:WHERE sex = '女' AND age > 18

-- 创建测试索引
CREATE INDEX idx_age_sex ON s1(age, sex);
CREATE INDEX idx_sex_age ON s1(sex, age);

-- 分别测试两个查询
EXPLAIN SELECT * FROM s1 WHERE age > 20 AND sex = '男';
EXPLAIN SELECT * FROM s1 WHERE sex = '女' AND age > 18;

-- 根据实际查询模式选择更优的索引顺序

示例9:索引维护操作

-- 1. 修改索引名称(MySQL 8.0+)
ALTER TABLE s1 RENAME INDEX idx_name TO idx_student_name;

-- 2. 禁用/启用索引(某些存储引擎支持)
-- ALTER TABLE s1 DISABLE KEYS;
-- ALTER TABLE s1 ENABLE KEYS;

-- 3. 分析索引使用情况
ANALYZE TABLE s1;

-- 4. 检查索引碎片
SHOW TABLE STATUS LIKE 's1';
-- 关注Data_free列,值较大时考虑优化表
OPTIMIZE TABLE s1;

示例10:实际性能对比测试

-- 准备测试数据(插入更多数据以观察性能差异)
DELIMITER $$
CREATE PROCEDURE insert_test_data()
BEGIN
    DECLARE i INT DEFAULT 1;
    WHILE i <= 10000 DO
        INSERT INTO s1 VALUES (
            NULL,
            CONCAT('测试学生', i),
            FLOOR(18 + RAND() * 10),
            ELT(FLOOR(1 + RAND() * 3), '男', '女', '未知'),
            CONCAT('202400', LPAD(i, 4, '0')),
            CONCAT('138', LPAD(FLOOR(RAND() * 100000000), 8, '0')),
            DATE_SUB(CURRENT_DATE, INTERVAL FLOOR(RAND() * 365) DAY),
            ELT(FLOOR(1 + RAND() * 2), '在读', '毕业')
        );
        SET i = i + 1;
    END WHILE;
END$$
DELIMITER ;

-- 执行存储过程插入测试数据
CALL insert_test_data();

-- 删除无索引时的查询测试
SET profiling = 1;
SELECT * FROM s1 WHERE s_name LIKE '测试学生%' ORDER BY age DESC LIMIT 100;
SHOW PROFILES;

-- 创建索引后的查询测试
CREATE INDEX idx_test_name ON s1(s_name);
SELECT * FROM s1 WHERE s_name LIKE '测试学生%' ORDER BY age DESC LIMIT 100;
SHOW PROFILES;

-- 对比查询时间
SET profiling = 0;

性能优化建议:

  1. 使用 EXPLAIN 分析查询执行计划
  2. 关注 type 列:const > ref > range > index > ALL
  3. 关注 Extra 列:避免 Using filesortUsing temporary
  4. 定期使用 ANALYZE TABLE 更新索引统计信息
  5. 监控慢查询日志,针对慢查询优化索引

7.5 索引使用注意事项

  1. 遵循最左前缀原则:对于联合索引 (A, B, C),查询条件必须包含 A,索引才会生效。例如 WHERE A=1 AND B=2 有效,但 WHERE B=2 则无法使用该索引。
  2. 避免在索引列上使用函数或运算:例如 WHERE YEAR(create_time) = 2023WHERE amount * 2 > 100 会导致索引失效。
  3. 注意隐式类型转换:例如字符串字段与数字比较时,可能导致索引失效。
  4. 选择区分度高的字段建立索引:在性别(只有‘男’、‘女’)这种区分度很低的字段上建立索引,效果甚微。应优先在唯一性高或取值分布广泛的字段上建索引。
  5. 避免过度索引:每个额外的索引都会增加写操作的开销,定期审查并删除未使用的索引。
  6. 考虑索引大小:过长的索引字段(如TEXT类型)不适合建索引,可考虑前缀索引。
  7. 注意NULL值的影响:包含NULL值的索引列在查询时可能需要特殊处理。
  8. 定期维护索引:使用 OPTIMIZE TABLEALTER TABLE ... REBUILD 整理索引碎片。## 8. 总结

本文通过一个从零开始的连贯案例,系统演示了 MySQL 数据库操作与性能优化的核心流程:

  1. 环境准备:创建数据库 (CREATE DATABASE) 并切换使用 (USE)。
  2. 表管理:安全删除旧表 (DROP TABLE IF EXISTS)、创建新表 (CREATE TABLE) 并查看其结构 (DESC, SHOW CREATE TABLE)。
  3. 数据操作:向表中插入示例数据 (INSERT INTO)。
  4. 结构维护:使用 ALTER TABLE 动态添加或删除字段,适应业务变化。
  5. 性能优化:深入理解索引的原理、分类与优缺点,并实践了普通索引、联合索引、全文索引、唯一索引的创建 (CREATE INDEX)、查看 (SHOW INDEX) 和删除 (DROP INDEX),掌握了索引使用的关键注意事项。

掌握这些从基础到进阶的操作,是进行高效数据库设计、开发和优化的坚实基础。建议读者在 MySQL 客户端中亲自执行每一段 SQL 代码,并结合实际业务场景思考索引的设计,以加深理解。

以上就是MySQL从建表到索引管理的完整指南的详细内容,更多关于MySQL从建表到索引管理的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:
阅读全文