MySQL 核心知识全解析:从语法到实战(DDL/DML/DQL + 核心特性)

MySQL 作为目前最流行的开源关系型数据库管理系统之一,广泛应用于 Web 开发、数据分析等领域。对于初学者而言,掌握其核心基础概念和操作,是搭建数据存储层的第一步。本文将跳过安装环节(安装环节点此跳转),从核心概念、数据类型、基本操作、约束与索引等维度,带你快速入门 MySQL 基础。

一、MySQL 核心概念先知晓

在动手操作前,先理清几个关键概念,能让你对 MySQL 的工作模式有整体认知:

1. 数据库(Database)

数据库是数据表的集合 ,用于按特定规则组织和存储相关数据。比如一个博客系统,可创建名为 blog_system 的数据库,存放用户表、文章表、评论表等。

2. 数据表(Table)

数据表是数据库的核心组成单位,采用行(Row)和列(Column) 的二维结构存储数据:

  • 列(字段 / Column) :代表数据的属性,比如用户表的 idusernameage 等;
  • 行(记录 / Row) :代表一条具体的数据,比如某一个用户的信息就是一行记录。

3. 数据类型(Data Type)

MySQL 为不同类型的数据定义了专属的数据类型,用于约束字段的存储内容,选择合适的数据类型能提升存储效率和查询性能。

4. 主键(Primary Key)

唯一标识数据表中每一行记录的字段,具有唯一性非空性 ,比如用户表的 id 通常设为主键。

5. 索引(Index)

用于加速数据表的查询操作,类似书籍的目录,能让 MySQL 快速定位到目标数据,避免全表扫描。

二、DDL:定义表结构时,嵌入 MySQL 的核心设计逻辑

DDL(数据定义语言)负责数据库和表的结构创建与修改,而在 MySQL 中,表结构的设计直接决定了后续性能和数据完整性,我们需要将存储引擎、字符集、约束、索引设计融入 DDL 操作中。

1. 数据库创建

MySQL 的字符集选择是基础且关键的设计,utf8mb4作为真正的 UTF-8 编码,支持 emoji 和所有生僻字,是开发的首选,需在创建数据库时直接指定:

sql 复制代码
-- 创建博客系统数据库,嵌入MySQL的字符集配置
CREATE DATABASE IF NOT EXISTS blog_system 
DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

2.什么是约束

  • 约束:约束是作用于表中字段上的规则,用于限制存储在表中的数据。
  • 目的:保证数据库中数据的正确性、有效性和完整性。

3. 数据表创建

创建表时不仅要定义字段,还要结合 MySQL 的自增主键、外键约束和索引设计,这是 MySQL 表结构设计的核心:

sql 复制代码
--    auto_increment:设置主键自增长,默认从1开始,每次插入一条数据id值递增1,要求字段类型必须是数字类
--    数据类型:varchar(50),可变长度字符串,字符串长度可以使0~50个字符
--    数据类型:char(1),固定长度字符串,字符串只有1个字符
create table emp(
                    id int primary key auto_increment comment '主键',
                    username varchar(50) not null unique comment '用户账号',
                    name varchar(50) unique comment '姓名',
                    age int comment '年龄',
                    gender char(1) default '男' comment '性别'
)comment '员工表';

4. 操作表结构

sql 复制代码
-- DDL操作表结构
-- 查询所有表
show tables ;
-- 查询指定表详细信息
desc emp;
-- 查看建表语句
show create table emp;

-- 添加address字段
alter table emp add address varchar(200) comment '地址' not null ;

-- 修改字段类型,将 varchar(200)修改varchar(500)
alter table emp modify address varchar(500);

-- 修改字段名与字段类型
alter table emp change address adr varchar(200) comment '地址' not null ;

-- 删除字段
alter table emp drop column adr;

-- 修改表名
alter table emp rename emp2;

-- 删除表
drop table if exists emp2;

二、DML:操作数据时,结合 MySQL 的性能与事务特性

DML(数据操作语言)负责增删改数据,在 MySQL 中,数据操作的效率和安全性依赖于批量操作、事务控制、索引利用等特性,需将这些特性与 DML 语法深度结合。

1. INSERT:利用 MySQL 批量插入提升性能

MySQL 的单条插入会频繁触发日志写入和网络交互,而批量插入能大幅减少开销,这是 MySQL 优化插入性能的核心技巧:

sql 复制代码
-- DML : 数据操作语言
-- DML : 插入数据 - insert

-- 添加password
alter table employee add password varchar(50) default '123456' comment '密码';

-- 1. 为 emp 表的 username, password, name, gender, phone 字段插入值
insert into employee(username, password, name, gender, phone) values
    ('zhangsan',null,'张三',1,'15012345678');

-- 2. 为 emp 表的 所有字段插入值
-- 注意:如果没有指定字段,就插入全部,顺序必须按照字段列表顺序插入
insert into employee values (null,'lisi','李四',2,'15012345671',1,8015.31,'1.png',
                             2025-12-18,null,'123345678');

-- 3. 批量为 emp 表的 username, password, name, gender, phone  字段插入数据
insert into employee(username, password, name, gender, phone) values
                                                                  ('zhangsan2',null,'张三2',1,'15012345672'),
                                                                  ('zhangsan3',null,'张三3',1,'15012345673');

2. UPDATE/DELETE:结合 MySQL 的事务和索引,保证安全与效率

  • 安全层面:利用 MySQL 的事务特性,在批量更新 / 删除前开启事务,出错时可回滚;
  • 效率层面:通过索引字段作为 WHERE 条件,让 MySQL 快速定位数据,避免全表扫描。
sql 复制代码
-- DML : 更新数据 - update
-- 1. 将 emp 表的ID为1员工 用户名更新为 'zhangsan', 姓名name字段更新为 '张三'
update employee set username='zhangsan4' ,name='张三4' where id = 1;

-- 2. 将 emp 表的所有员工的入职日期更新为 '2010-01-01'
update employee set entry_date = '2010-01-01';

-- DML : 删除数据 - delete
-- 1. 删除 emp 表中 ID为1的员工
delete from employee where id = 1;

-- 2. 删除 emp 表中的所有员工
delete from employee;

核心注意点

  • 避免无 WHERE 条件的 UPDATE/DELETE,这会导致 MySQL 全表更新 / 删除,性能极低且数据风险大;

三、DQL:查询数据时,深度利用 MySQL 的索引和查询特性

DQL(数据查询语言)是 MySQL 使用最频繁的操作,查询效率的高低直接取决于是否利用索引、是否遵循 MySQL 的查询优化规则,需将查询语法与 MySQL 的索引、函数、分页特性深度融合。

1. 基础查询

查询之前先创建一个user表并初始化表的数据

sql 复制代码
create table emp
(
    id          int unsigned primary key auto_increment comment 'ID,主键',
    username    varchar(20)      not null unique comment '用户名',
    password    varchar(32)      not null comment '密码',
    name        varchar(10)      not null comment '姓名',
    gender      tinyint unsigned not null comment '性别, 1:男, 2:女',
    phone       char(11)         not null unique comment '手机号',
    job         tinyint unsigned comment '职位, 1:班主任,2:讲师,3:学工主管,4:教研主管,5:咨询师',
    salary      int unsigned comment '薪资',
    image       varchar(300) comment '头像',
    entry_date  date comment '入职日期',
    create_time datetime comment '创建时间',
    update_time datetime comment '修改时间'
) comment '员工表';


-- 准备测试数据
INSERT INTO emp(id, username, password, name, gender, phone, job, salary, image, entry_date, create_time, update_time)
VALUES (1, 'shinaian', '123456', '施耐庵', 1, '13309090001', 4, 15000, '1.jpg', '2000-01-01', '2024-04-11 16:35:33',
        '2024-04-11 16:35:35'),
       (2, 'songjiang', '123456', '宋江', 1, '13309090002', 2, 8600, '2.jpg', '2015-01-01', '2024-04-11 16:35:33',
        '2024-04-11 16:35:37'),
       (3, 'lujunyi', '123456', '卢俊义', 1, '13309090003', 2, 8900, '3.jpg', '2008-05-01', '2024-04-11 16:35:33',
        '2024-04-11 16:35:39'),
       (4, 'wuyong', '123456', '吴用', 1, '13309090004', 2, 9200, '4.jpg', '2007-01-01', '2024-04-11 16:35:33',
        '2024-04-11 16:35:41'),
       (5, 'gongsunsheng', '123456', '公孙胜', 1, '13309090005', 2, 9500, '5.jpg', '2012-12-05', '2024-04-11 16:35:33',
        '2024-04-11 16:35:43'),
       (6, 'huosanniang', '123456', '扈三娘', 2, '13309090006', 3, 6500, '6.jpg', '2013-09-05', '2024-04-11 16:35:33',
        '2024-04-11 16:35:45'),
       (7, 'chaijin', '123456', '柴进', 1, '13309090007', 1, 4700, '7.jpg', '2005-08-01', '2024-04-11 16:35:33',
        '2024-04-11 16:35:47'),
       (8, 'likui', '123456', '李逵', 1, '13309090008', 1, 4800, '8.jpg', '2014-11-09', '2024-04-11 16:35:33',
        '2024-04-11 16:35:49'),
       (9, 'wusong', '123456', '武松', 1, '13309090009', 1, 4900, '9.jpg', '2011-03-11', '2024-04-11 16:35:33',
        '2024-04-11 16:35:51'),
       (10, 'lichong', '123456', '林冲', 1, '13309090010', 1, 5000, '10.jpg', '2013-09-05', '2024-04-11 16:35:33',
        '2024-04-11 16:35:53'),
       (11, 'huyanzhuo', '123456', '呼延灼', 1, '13309090011', 2, 9700, '11.jpg', '2007-02-01', '2024-04-11 16:35:33',
        '2024-04-11 16:35:55'),
       (12, 'xiaoliguang', '123456', '小李广', 1, '13309090012', 2, 10000, '12.jpg', '2008-08-18',
        '2024-04-11 16:35:33', '2024-04-11 16:35:57'),
       (13, 'yangzhi', '123456', '杨志', 1, '13309090013', 1, 5300, '13.jpg', '2012-11-01', '2024-04-11 16:35:33',
        '2024-04-11 16:35:59'),
       (14, 'shijin', '123456', '史进', 1, '13309090014', 2, 10600, '14.jpg', '2002-08-01', '2024-04-11 16:35:33',
        '2024-04-11 16:36:01'),
       (15, 'sunerniang', '123456', '孙二娘', 2, '13309090015', 2, 10900, '15.jpg', '2011-05-01', '2024-04-11 16:35:33',
        '2024-04-11 16:36:03'),
       (16, 'luzhishen', '123456', '鲁智深', 1, '13309090016', 2, 9600, '16.jpg', '2010-01-01', '2024-04-11 16:35:33',
        '2024-04-11 16:36:05'),
       (17, 'liying', '12345678', '李应', 1, '13309090017', 1, 5800, '17.jpg', '2015-03-21', '2024-04-11 16:35:33',
        '2024-04-11 16:36:07'),
       (18, 'shiqian', '123456', '时迁', 1, '13309090018', 2, 10200, '18.jpg', '2015-01-01', '2024-04-11 16:35:33',
        '2024-04-11 16:36:09'),
       (19, 'gudasao', '123456', '顾大嫂', 2, '13309090019', 2, 10500, '19.jpg', '2008-01-01', '2024-04-11 16:35:33',
        '2024-04-11 16:36:11'),
       (20, 'ruanxiaoer', '123456', '阮小二', 1, '13309090020', 2, 10800, '20.jpg', '2018-01-01', '2024-04-11 16:35:33',
        '2024-04-11 16:36:13'),
       (21, 'ruanxiaowu', '123456', '阮小五', 1, '13309090021', 5, 5200, '21.jpg', '2015-01-01', '2024-04-11 16:35:33',
        '2024-04-11 16:36:15'),
       (22, 'ruanxiaoqi', '123456', '阮小七', 1, '13309090022', 5, 5500, '22.jpg', '2016-01-01', '2024-04-11 16:35:33',
        '2024-04-11 16:36:17'),
       (23, 'ruanji', '123456', '阮籍', 1, '13309090023', 5, 5800, '23.jpg', '2012-01-01', '2024-04-11 16:35:33',
        '2024-04-11 16:36:19'),
       (24, 'tongwei', '123456', '童威', 1, '13309090024', 5, 5000, '24.jpg', '2006-01-01', '2024-04-11 16:35:33',
        '2024-04-11 16:36:21'),
       (25, 'tongmeng', '123456', '童猛', 1, '13309090025', 5, 4800, '25.jpg', '2002-01-01', '2024-04-11 16:35:33',
        '2024-04-11 16:36:23'),
       (26, 'yanshun', '123456', '燕顺', 1, '13309090026', 5, 5400, '26.jpg', '2011-01-01', '2024-04-11 16:35:33',
        '2024-04-11 16:36:25'),
       (27, 'lijun', '123456', '李俊', 1, '13309090027', 5, 6600, '27.jpg', '2004-01-01', '2024-04-11 16:35:33',
        '2024-04-11 16:36:27'),
       (28, 'lizhong', '123456', '李忠', 1, '13309090028', 5, 5000, '28.jpg', '2007-01-01', '2024-04-11 16:35:33',
        '2024-04-11 16:36:29'),
       (29, 'songqing', '123456', '宋清', 1, '13309090029', 5, 5100, '29.jpg', '2020-01-01', '2024-04-11 16:35:33',
        '2024-04-11 16:36:31'),
       (30, 'liyun', '123456', '李云', 1, '13309090030', NULL, NULL, '30.jpg', '2020-03-01', '2024-04-11 16:35:33',
        '2024-04-11 16:36:31');

基础查询演示

sql 复制代码
--  =================== DQL: 基本查询 ======================
-- 1. 查询指定字段 name,entry_date 并返回
select name, emp.entry_date
from emp;

-- 2. 查询返回所有字段
select *
from emp;
-- 注意:在企业开发中不推荐使用*,企业推荐需要多少个字段就查询多少个字段,不要查询所有浪费空间

-- 3. 查询所有员工的 name,entry_date, 并起别名(姓名、入职日期)
select emp.name as 名字, emp.entry_date as 入职日期
from emp;
select emp.name 名字, emp.entry_date 入职日期
from emp;

-- 4. 查询已有的员工关联了哪几种职位(不要重复)
select distinct emp.job
from emp;

2. 条件查询

sql 复制代码
--  =================== DQL: 条件查询 ======================
-- 1. 查询 姓名 为 柴进 的员工
select *
from emp
where name = '柴进';

-- 2. 查询 薪资小于等于5000 的员工信息
select *
from emp
where salary <= 5000;

-- 3. 查询 没有分配职位 的员工信息
# select * from emp where job = null ;错误的
select *
from emp
where job is null;

-- 4. 查询 有职位 的员工信息
# select * from emp where job != null;错误的
select *
from emp
where job is not null;

-- 5. 查询 密码不等于 '123456' 的员工信息
select *
from emp
where password != '123456';

-- 6. 查询 入职日期 在 '2000-01-01' (包含) 到 '2010-01-01'(包含) 之间的员工信息
select *
from emp
where entry_date >= '2000-01-01'
  and entry_date <= '2010-01-01';
select *
from emp
where entry_date between '2000-01-01' and '2010-01-01';

-- 7. 查询 入职时间 在 '2000-01-01' (包含) 到 '2010-01-01'(包含) 之间 且 性别为女 的员工信息
select *
from emp
where entry_date between '2000-01-01' and '2010-01-01'
  and gender = 2;

-- 8. 查询 职位是 2 (讲师), 3 (学工主管), 4 (教研主管) 的员工信息
select *
from emp
where job in (2, 3, 4);
select *
from emp
where job = 2
   or job = 3
   or job = 4;

-- 9. 查询 姓名 为两个字的员工信息
select *
from emp
where name like '__';
-- like 模糊匹配 _代表任意一个字符

-- 10. 查询 姓 '李' 的员工信息
select *
from emp
where name like '李%';

-- 11. 查询 姓名中包含 '二' 的员工信息
select *
from emp
where name like '%二%';

3. 分组查询

sql 复制代码
--  =================== DQL: 分组查询 ======================
-- 聚合函数

-- 1. 统计该企业员工数量
select count(*)
from emp;
select count(100)
from emp;
select count(job)
from emp;
-- count聚合函数其他用户
--   count(*) 统计所有符合的记录数
--   count(数字) 功能与count(*),例如 count(0)
--   count(字段) 统计该字段非空的数量

-- 2. 统计该企业员工的平均薪资
select avg(emp.salary)
from emp;

-- 3. 统计该企业员工的最低薪资
select min(emp.salary)
from emp;

-- 4. 统计该企业员工的最高薪资
select max(emp.salary)
from emp;

-- 5. 统计该企业每月要给员工发放的薪资总额(薪资之和)
select sum(emp.salary)
from emp;



-- 分组
-- 1. 根据性别分组 , 统计男性和女性员工的数量
--    注意:sql规范,要求分组查询字段只能包含:分组字段和聚合函数
select emp.gender 性别, count(*) 数量
from emp
group by gender;

-- case when 条件判断返回不同的值
--    用法1
select case emp.gender
           when 1 then '男'
           when 2 then '女'
           else '保密' end
                性别,
       count(*) 数量
from emp
group by gender;

--    用法2
select case
           when emp.gender = 1 then '男'
           when emp.gender = 2 then '女'
           else '保密' end
                性别,
       count(*) 数量
from emp
group by gender;


-- 2. 先查询入职时间在 '2015-01-01' (包含) 以前的员工 , 并对结果根据职位分组 , 获取员工数量大于等于2的职位
select job 职位, count(*) 数量
from emp
where entry_date <= '2015-01-01'
group by job;

select job 职位, count(*) 数量
from emp
where entry_date <= '2015-01-01'
group by job
having count(*) >= 2;

select job 职位, count(*) 数量
from emp
where entry_date <= '2015-01-01'
group by job
having 数量 >= 2;

select case job
           when 1 then '班主任'
           when 2 then '讲师'
           when 3 then '学工主管'
           when 4 then '教研主管'
           when 5 then '咨询师'
           else '其他' end
                职位,
       count(*) 数量
from emp
where entry_date <= '2015-01-01'
group by job
having 数量 >= 2;

4.排序查询

sql 复制代码
--  =================== 排序查询 ======================
-- 1. 根据入职时间, 对员工进行升序排序
select *
from emp
order by entry_date;
-- 默认升序

-- 2. 根据入职时间, 对员工进行降序排序
select *
from emp
order by entry_date desc;

-- 3. 根据 入职时间 对公司的员工进行 升序排序 , 入职时间相同 , 再按照 更新时间 进行降序排序
-- 如果是多字段排序,当第一个字段值相同时,才会根据第二个字段进行排序
select *
from emp
order by entry_date, update_time desc;

5.分页查询

sql 复制代码
--  =================== 分页查询 ======================
-- 1.  需求:从起始索引0开始查询员工数据, 每页展示5条记录
-- 2. 查询 第1页 员工数据, 每页展示5条记录
select *
from emp
limit 0,5;
-- 开始索引 = (1-1)* 5 = 0

-- 3. 查询 第2页 员工数据, 每页展示5条记录
select *
from emp
limit 5,5;
-- 开始索引 = (2-1)* 5 = 0

-- 4. 查询 第3页 员工数据, 每页展示5条记录
select *
from emp
limit 10,5;
-- 开始索引 = (3-1)* 5 = 0

-- 已知条件,查询第几页page和每页显示多少条pageSize,求 limit 开始索引,查询多少条
-- 开始索引 = (page-1)* pageSize
-- 查询多少条 = pageSize
-- 注意:limit是方言,其他关系型数据库没有。

四、核心总结:SQL 与 MySQL 特性融合的关键原则

  1. 结构设计阶段 :DDL 需结合 MySQL 的InnoDB引擎、utf8mb4字符集、索引和约束,从源头保证数据存储的高效性和完整性;
  2. 数据操作阶段:DML 需利用 MySQL 的批量操作、事务控制,兼顾性能和数据安全;
  3. 数据查询阶段 :DQL 需深度利用 MySQL 的索引特性、内置函数和分页语法,通过EXPLAIN工具优化查询。

MySQL 的使用本质是SQL 语法数据库自身特性的结合,脱离特性的语法操作会导致性能低下,而脱离语法的特性则无法落地。只有将两者深度融合,才能在实际开发中发挥 MySQL 的最大价值。

相关推荐
卡尔特斯2 小时前
Mysql 报错 “Public Key Retrieval is not allowed”
mysql
P-surp2 小时前
mysql 数据库 批量库 迁移、恢复
数据库·mysql
繁星星繁2 小时前
【Mysql】数据库的操作
数据库·mysql·oracle
dvlinker2 小时前
动态代理技术实战测评—高效解锁Zillow房价历史
android·java·数据库
API开发2 小时前
体验“不存数据”的数据库:Trino 容器化部署与极速入门
数据库
我科绝伦(Huanhuan Zhou)2 小时前
Oracle索引技术:理论与实操全解析
数据库·oracle
sc.溯琛2 小时前
MySQL 实战:表数据维护核心技能(插入 / 更新 / 删除全解析)
数据库·oracle
wniuniu_2 小时前
object->osd
android·java·数据库
大道之简2 小时前
SpringAi基于PgSQL数据库存储扩展ChatMemory
数据库