1. MySQL基础查询概述
MySQL作为最流行的开源关系型数据库之一,其核心操作可以概括为CRUD(Create, Read, Update, Delete)。对于初学者而言,掌握基本的增删改查操作是使用MySQL的第一步。在实际工作中,大约80%的数据库操作都属于基础查询范畴,这也是为什么"增删改查"被称为数据库操作的"四大金刚"。
我见过不少开发者一上来就想研究索引优化、分库分表这些高级主题,结果连最基本的WHERE条件都写不完整。这就像还没学会走路就想跑马拉松一样不切实际。本文将系统性地介绍MySQL表的基础操作,从最基础的语法到实际应用中的技巧,帮助大家打好坚实的基础。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 表的创建与结构管理
2.1 创建表的完整语法
创建表是操作数据库的第一步,CREATE TABLE语句看似简单,实则包含许多需要注意的细节:
sql复制CREATE TABLE students (
id INT NOT NULL AUTO_INCREMENT,
name VARCHAR(50) NOT NULL,
age TINYINT UNSIGNED,
gender ENUM('男','女','其他') DEFAULT '男',
enrollment_date DATE,
PRIMARY KEY (id),
INDEX idx_name (name)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
这里有几个关键点需要注意:
- 字段类型选择:VARCHAR适合变长字符串,CHAR适合固定长度内容。数值类型要根据数据范围选择,避免浪费空间。
- 约束条件:NOT NULL保证数据完整性,AUTO_INCREMENT常用于主键自增。
- 字符集设置:utf8mb4支持完整的Unicode字符(包括emoji),比utf8更推荐使用。
- 存储引擎:InnoDB支持事务和外键,是MySQL 5.5后的默认引擎。
提示:在生产环境中,表名和字段名最好使用小写字母和下划线组合,避免大小写敏感问题。
2.2 表结构修改的实用技巧
ALTER TABLE语句用于修改表结构,但大表的结构变更可能会锁表,影响线上服务。以下是一些常见操作:
sql复制-- 添加新列
ALTER TABLE students ADD COLUMN email VARCHAR(100) AFTER name;
-- 修改列类型
ALTER TABLE students MODIFY COLUMN age SMALLINT UNSIGNED;
-- 重命名列
ALTER TABLE students CHANGE COLUMN gender sex ENUM('男','女','其他');
-- 删除列
ALTER TABLE students DROP COLUMN enrollment_date;
-- 添加索引
ALTER TABLE students ADD INDEX idx_age (age);
对于大表的ALTER操作,建议:
- 在业务低峰期执行
- 使用pt-online-schema-change等工具减少锁表时间
- 先在小规模测试环境验证变更
3. 数据插入操作详解
3.1 基础插入语句
最基本的INSERT语句有以下几种形式:
sql复制-- 指定列名插入
INSERT INTO students (name, age, sex) VALUES ('张三', 20, '男');
-- 批量插入
INSERT INTO students (name, age, sex) VALUES
('李四', 21, '女'),
('王五', 22, '男'),
('赵六', 19, '其他');
-- 省略列名(需提供所有列的值)
INSERT INTO students VALUES (NULL, '钱七', 23, '男', 'qianqi@example.com');
批量插入相比单条插入效率更高,特别是在需要插入大量数据时。实测表明,批量插入1000条记录比单条插入快10倍以上。
3.2 高级插入技巧
3.2.1 INSERT IGNORE与ON DUPLICATE KEY UPDATE
sql复制-- 忽略重复键错误
INSERT IGNORE INTO students (id, name) VALUES (1, '张三');
-- 遇到重复键时更新
INSERT INTO students (id, name) VALUES (1, '张三')
ON DUPLICATE KEY UPDATE name = VALUES(name), age = VALUES(age);
这两个语法在处理可能出现重复的数据时非常有用,特别是数据同步场景。
3.2.2 从其他表插入数据
sql复制-- 从临时表导入数据
INSERT INTO students (name, age)
SELECT name, age FROM temp_students WHERE status = 1;
这种写法常用于数据迁移或ETL过程。
4. 数据查询的艺术
4.1 SELECT基础与条件过滤
SELECT语句是使用最频繁的SQL语句,其基本结构如下:
sql复制SELECT
[DISTINCT] column1, column2, ...
FROM
table_name
[WHERE condition]
[GROUP BY column_name]
[HAVING group_condition]
[ORDER BY column_name [ASC|DESC]]
[LIMIT offset, row_count];
WHERE子句支持多种条件运算符:
sql复制-- 比较运算符
SELECT * FROM students WHERE age > 20;
-- 范围查询
SELECT * FROM students WHERE age BETWEEN 18 AND 22;
-- 集合查询
SELECT * FROM students WHERE id IN (1, 3, 5);
-- 模糊查询
SELECT * FROM students WHERE name LIKE '张%';
-- NULL值判断
SELECT * FROM students WHERE email IS NOT NULL;
注意:LIKE '%关键字%'这种前后都带通配符的查询无法使用索引,大数据量表慎用。
4.2 高级查询技巧
4.2.1 聚合函数与分组
sql复制-- 常用聚合函数
SELECT
COUNT(*) AS total,
AVG(age) AS avg_age,
MAX(age) AS max_age,
MIN(age) AS min_age,
SUM(age) AS sum_age
FROM students;
-- 分组统计
SELECT
sex,
COUNT(*) AS count,
AVG(age) AS avg_age
FROM students
GROUP BY sex
HAVING count > 1;
GROUP BY常与HAVING配合使用,WHERE在分组前过滤,HAVING在分组后过滤。
4.2.2 子查询与连接查询
sql复制-- 子查询
SELECT name FROM students WHERE age = (SELECT MAX(age) FROM students);
-- 内连接
SELECT s.name, c.course_name
FROM students s
INNER JOIN course_selection c ON s.id = c.student_id;
-- 左外连接
SELECT s.name, c.course_name
FROM students s
LEFT JOIN course_selection c ON s.id = c.student_id;
连接查询是关系型数据库的核心特性,理解各种连接类型的区别至关重要。
5. 数据更新与删除操作
5.1 更新数据的最佳实践
UPDATE语句用于修改现有数据:
sql复制-- 基础更新
UPDATE students SET age = 21 WHERE name = '张三';
-- 多列更新
UPDATE students SET age = age + 1, email = CONCAT(name, '@school.edu')
WHERE enrollment_date < '2023-01-01';
-- 带子查询的更新
UPDATE students s
JOIN (SELECT student_id, AVG(score) AS avg_score FROM scores GROUP BY student_id) t
ON s.id = t.student_id
SET s.avg_score = t.avg_score;
更新操作需要注意:
- 一定要有WHERE条件,否则会更新全表
- 大表更新分批进行,避免长时间锁表
- 先SELECT验证WHERE条件,再执行UPDATE
5.2 删除数据的注意事项
DELETE语句用于删除数据:
sql复制-- 条件删除
DELETE FROM students WHERE id = 1;
-- 清空表(谨慎使用)
DELETE FROM students;
-- 联表删除
DELETE s FROM students s
LEFT JOIN course_selection c ON s.id = c.student_id
WHERE c.student_id IS NULL;
对于重要数据,建议采用逻辑删除而非物理删除:
sql复制-- 添加is_deleted字段
ALTER TABLE students ADD COLUMN is_deleted TINYINT DEFAULT 0;
-- 逻辑删除
UPDATE students SET is_deleted = 1 WHERE id = 1;
-- 查询时排除已删除数据
SELECT * FROM students WHERE is_deleted = 0;
6. 实战中的常见问题与解决方案
6.1 性能优化基础
-
索引使用原则:
- 为WHERE、JOIN、ORDER BY涉及的列创建索引
- 避免在索引列上使用函数或计算
- 遵循最左前缀原则使用复合索引
-
EXPLAIN分析查询:
sql复制EXPLAIN SELECT * FROM students WHERE name LIKE '张%';关注type列(ALL表示全表扫描)、possible_keys和key列(是否使用了索引)
6.2 事务处理基础
sql复制-- 开启事务
START TRANSACTION;
-- 执行操作
UPDATE account SET balance = balance - 100 WHERE id = 1;
UPDATE account SET balance = balance + 100 WHERE id = 2;
-- 根据情况提交或回滚
COMMIT;
-- 或
ROLLBACK;
事务的ACID特性:
- 原子性(Atomicity):要么全部成功,要么全部失败
- 一致性(Consistency):保持数据一致性
- 隔离性(Isolation):事务间相互隔离
- 持久性(Durability):提交后永久生效
6.3 数据类型选择建议
-
字符串类型:
- CHAR(n):固定长度,适合短字符串(如手机号、身份证号)
- VARCHAR(n):变长字符串,适合大多数场景
- TEXT:大文本,避免在WHERE中使用
-
数值类型:
- TINYINT:小整数(-128~127)
- INT:常用整数类型
- DECIMAL:精确小数,适合金额
-
时间类型:
- DATE:仅日期
- DATETIME:日期时间(8字节)
- TIMESTAMP:时间戳(4字节,自动转换时区)
在实际项目中,我见过太多因为数据类型选择不当导致的问题。比如用VARCHAR存储手机号导致排序错误,用DATETIME存储时间戳浪费空间等。正确的数据类型不仅能节省存储空间,还能提高查询效率。
