数据库的基本操作
MySQL 是当前最流行的开源关系型数据库管理系统之一,广泛应用于 Web 应用程序开发。以下是 MySQL 数据库的详细操作指南,包含文字说明和代码示例。
MySQL 数据库操作指南
一、数据库基础管理
1.1 数据库的创建与选择
MySQL 数据库作为关系型数据库管理系统(RDBMS)的核心数据存储容器,可包含多张数据表,用于组织和管理结构化数据。创建数据库是 MySQL 操作的首要步骤,也是数据存储的基础架构。
基本操作示例
-- 创建新数据库(指定字符集和排序规则)
CREATE DATABASE company_db
CHARACTER SET utf8mb4
COLLATE utf8mb4_general_ci;-- 安全创建(避免重复创建报错)
CREATE DATABASE IF NOT EXISTS company_db;-- 查看所有数据库(包括系统数据库)
SHOW DATABASES;-- 选择要操作的数据库(后续SQL将在此数据库执行)
USE company_db;
高级数据库创建选项
-- 创建带详细参数的数据库
CREATE DATABASE inventory_db
CHARACTER SET utf8mb4
COLLATE utf8mb4_unicode_ci
DEFAULT ENCRYPTION='N';
注意事项:
命名规范:
- MySQL 中数据库名称默认区分大小写(取决于操作系统,Linux区分而Windows不区分)
- 建议使用下划线命名数据库(如
company_db
)而非空格或特殊字符 - 避免使用MySQL保留关键字作为数据库名
字符集推荐:
- 推荐使用
utf8mb4
字符集以支持完整的Unicode字符(包括emoji) - 排序规则根据语言需求选择(如中文排序用
utf8mb4_unicode_ci
)
- 推荐使用
操作前必须通过
USE
命令选择目标数据库,否则会报"No database selected"错误权限控制:创建数据库需要
CREATE
权限,可通过GRANT CREATE ON *.* TO 'user'@'host'
授权
1.2 数据库删除
数据库删除是不可逆操作,执行前务必确认数据已备份或不再需要。
删除操作示例
-- 基本删除命令
DROP DATABASE company_db;-- 安全删除(避免不存在的数据库报错)
DROP DATABASE IF EXISTS company_db;-- 删除并立即释放空间(MySQL 8.0+)
DROP DATABASE company_db WAIT 10; -- 等待10秒IO完成
警告与注意事项:
数据永久丢失:删除操作将清除数据库内所有数据,包括:
- 所有表结构和数据
- 视图、存储过程等数据库对象
- 相关权限设置
备份建议:
# 使用mysqldump备份数据库 mysqldump -u root -p company_db > company_db_backup.sql
生产环境防护:
- 设置
--safe-updates
选项防止误删 - 实施权限分离,限制DROP权限
- 考虑使用数据库回收站插件(如MySQL Shell的
util.enableRecursiveDeletionProtection
)
- 设置
替代方案:对于测试环境,可考虑重命名而非删除:
RENAME DATABASE company_db TO company_db_old;
二、数据表管理
2.1 创建数据表
数据表是MySQL中存储数据的基本结构,由行(记录)和列(字段)组成二维关系模型。
完整表示例
CREATE TABLE employees (id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY COMMENT '员工ID',name VARCHAR(50) NOT NULL COMMENT '员工姓名',age TINYINT UNSIGNED CHECK (age >= 18) COMMENT '员工年龄',department VARCHAR(50) DEFAULT '未分配' COMMENT '所属部门',salary DECIMAL(10,2) COMMENT '月薪(保留2位小数)',hire_date DATE NOT NULL COMMENT '入职日期',email VARCHAR(100) UNIQUE COMMENT '电子邮箱',resume TEXT COMMENT '个人简历',status ENUM('active', 'on_leave', 'terminated') DEFAULT 'active' COMMENT '在职状态',created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',INDEX idx_department (department),FULLTEXT INDEX idx_resume (resume)
) ENGINE=InnoDB
DEFAULT CHARSET=utf8mb4
COMMENT='公司员工信息表'
PARTITION BY RANGE (YEAR(hire_date)) (PARTITION p2019 VALUES LESS THAN (2020),PARTITION p2020 VALUES LESS THAN (2021),PARTITION p2021 VALUES LESS THAN (2022),PARTITION pmax VALUES LESS THAN MAXVALUE
);
字段类型详解
类型 | 说明 | 示例 |
---|---|---|
整数类型 | ||
TINYINT | 1字节整数(-128~127) | age TINYINT |
SMALLINT | 2字节整数 | small_id SMALLINT |
INT | 4字节整数 | id INT |
BIGINT | 8字节整数 | big_id BIGINT |
小数类型 | ||
DECIMAL(m,n) | 精确小数 | salary DECIMAL(10,2) |
FLOAT | 4字节浮点数 | ratio FLOAT |
DOUBLE | 8字节浮点数 | precise DOUBLE |
字符串类型 | ||
CHAR(n) | 定长字符串 | gender CHAR(1) |
VARCHAR(n) | 变长字符串 | name VARCHAR(50) |
TEXT | 长文本 | content TEXT |
日期时间 | ||
DATE | 日期 | birthday DATE |
TIME | 时间 | work_time TIME |
DATETIME | 日期时间 | login_time DATETIME |
TIMESTAMP | 时间戳 | created_at TIMESTAMP |
特殊类型 | ||
ENUM | 枚举值 | status ENUM('Y','N') |
SET | 集合 | tags SET('red','blue','green') |
JSON | JSON数据 | profile JSON |
约束详解
主键约束:
-- 单列主键 id INT PRIMARY KEY-- 复合主键 PRIMARY KEY (department, employee_code)
外键约束(确保引用完整性):
CREATE TABLE orders (order_id INT PRIMARY KEY,employee_id INT,FOREIGN KEY (employee_id) REFERENCES employees(id)ON DELETE CASCADEON UPDATE RESTRICT );
检查约束(MySQL 8.0+):
salary DECIMAL(10,2) CHECK (salary > 0)
默认值约束:
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
2.2 修改表结构
随着业务需求变化,表结构可能需要调整,MySQL提供丰富的ALTER TABLE操作。
常用修改操作
-- 添加新列(带位置控制)
ALTER TABLE employees
ADD COLUMN phone VARCHAR(20) AFTER email;-- 修改列定义(保持数据)
ALTER TABLE employees
MODIFY COLUMN phone VARCHAR(15) NOT NULL
COMMENT '联系电话';-- 重命名列(同时可修改类型)
ALTER TABLE employees
CHANGE COLUMN phone mobile_phone VARCHAR(15);-- 删除列(MySQL 8.0支持原子DDL)
ALTER TABLE employees
DROP COLUMN mobile_phone,
ALGORITHM=INPLACE, LOCK=NONE;-- 添加外键约束
ALTER TABLE orders
ADD CONSTRAINT fk_employee
FOREIGN KEY (employee_id) REFERENCES employees(id);-- 修改表选项
ALTER TABLE employees
ENGINE=InnoDB,
COMMENT='更新后的员工表',
AUTO_INCREMENT=1001;
索引管理
-- 添加普通索引
ALTER TABLE employees
ADD INDEX idx_name_department (name, department);-- 添加唯一索引
ALTER TABLE employees
ADD UNIQUE INDEX idx_unique_email (email);-- 删除索引
ALTER TABLE employees
DROP INDEX idx_name_department;-- 重建表优化(MyISAM适用)
ALTER TABLE employees ENGINE=MyISAM;
分区表操作(MySQL 5.7+)
-- 添加新分区
ALTER TABLE employees
ADD PARTITION (PARTITION p2022 VALUES LESS THAN (2023)
);-- 重组分区
ALTER TABLE employees
REORGANIZE PARTITION pmax INTO (PARTITION p2023 VALUES LESS THAN (2024),PARTITION pmax VALUES LESS THAN MAXVALUE
);-- 删除分区(数据会丢失)
ALTER TABLE employees
DROP PARTITION p2019;
三、数据操作
3.1 插入数据
单行插入
-- 完整字段插入
INSERT INTO employees
(name, age, department, salary, hire_date, email)
VALUES
('张伟', 28, '研发部', 15000.00, '2020-06-15', 'zhangwei@example.com');-- 省略可为NULL字段
INSERT INTO employees
(name, age, salary, hire_date)
VALUES
('李娜', 26, 12000.00, '2021-03-10');-- 使用DEFAULT关键字
INSERT INTO employees
(name, age, department, salary, hire_date)
VALUES
('王芳', 30, DEFAULT, 18000.00, '2019-11-22');
批量插入
-- 多值插入(高效)
INSERT INTO employees
(name, age, department, salary, hire_date, email)
VALUES
('赵明', 32, '市场部', 14000.00, '2018-09-05', 'zhaoming@example.com'),
('刘红', 29, '人事部', 13000.00, '2020-02-18', 'liuhong@example.com'),
('陈强', 35, '研发部', 20000.00, '2017-07-30', 'chenqiang@example.com');-- 从查询结果插入
INSERT INTO new_employees
(name, department, salary)
SELECT name, department, salary
FROM employees
WHERE hire_date > '2022-01-01';
高级插入技术
-- 插入或更新(ON DUPLICATE KEY UPDATE)
INSERT INTO employees
(id, name, email, salary)
VALUES
(101, '张伟', 'zhangwei@example.com', 16000.00)
ON DUPLICATE KEY UPDATE
salary = VALUES(salary),
updated_at = CURRENT_TIMESTAMP;-- 替换数据(REPLACE)
REPLACE INTO employees
(id, name, email)
VALUES
(101, '张伟新', 'zhangwei_new@example.com');-- 忽略错误插入(IGNORE)
INSERT IGNORE INTO employees
(email, name)
VALUES
('zhangwei@example.com', '张伟');
3.2 查询数据
基础查询
-- 查询所有列
SELECT * FROM employees;-- 查询特定列
SELECT id AS 员工编号,name AS 姓名,CONCAT('¥', FORMAT(salary, 2)) AS 月薪
FROM employees;-- 使用计算字段
SELECT name,salary,salary * 12 AS 年薪,salary * 0.2 AS 季度奖
FROM employees;-- 去重查询
SELECT DISTINCT department FROM employees;
条件查询
-- 比较运算符
SELECT * FROM employees WHERE salary >= 15000;-- 逻辑运算符
SELECT * FROM employees
WHERE department = '研发部' AND salary > 10000;-- BETWEEN范围查询
SELECT * FROM employees
WHERE hire_date BETWEEN '2020-01-01' AND '2021-12-31';-- IN查询
SELECT * FROM employees
WHERE department IN ('研发部', '市场部');-- LIKE模糊查询
SELECT * FROM employees
WHERE name LIKE '张%' OR name LIKE '%强%';-- NULL值处理
SELECT * FROM employees
WHERE department IS NOT NULL;-- 正则表达式查询
SELECT * FROM employees
WHERE name REGEXP '^[赵钱孙李]';
排序与分页
-- 单字段排序
SELECT * FROM employees
ORDER BY hire_date DESC;-- 多字段排序
SELECT * FROM employees
ORDER BY department ASC, salary DESC;-- 分页查询(LIMIT offset, count)
SELECT * FROM employees
ORDER BY id
LIMIT 10 OFFSET 20; -- 第3页,每页10条-- MySQL 8.0+窗口函数
SELECT id, name, salary,RANK() OVER (ORDER BY salary DESC) AS salary_rank
FROM employees
LIMIT 10;
聚合函数
-- 基本聚合
SELECT COUNT(*) AS 总人数,AVG(salary) AS 平均薪资,MAX(hire_date) AS 最新入职日期
FROM employees;-- 分组聚合
SELECT department,COUNT(*) AS 人数,ROUND(AVG(salary), 2) AS 平均薪资,SUM(salary) AS 薪资总额
FROM employees
GROUP BY department;-- HAVING筛选
SELECT department,AVG(salary) AS avg_salary
FROM employees
GROUP BY department
HAVING avg_salary > 15000
ORDER BY avg_salary DESC;-- WITH ROLLUP小计
SELECT department,gender,COUNT(*) AS count
FROM employees
GROUP BY department, gender WITH ROLLUP;
3.3 更新数据
基本更新
-- 条件更新
UPDATE employees
SET salary = salary * 1.05
WHERE department = '研发部';-- 多字段更新
UPDATE employees
SET salary = salary + 1000,department = '技术研发部',updated_at = CURRENT_TIMESTAMP
WHERE id = 1005;-- 使用子查询更新
UPDATE employees e
JOIN (SELECT department, AVG(salary) AS avg_salFROM employeesGROUP BY department
) dept ON e.department = dept.department
SET e.salary = e.salary * 1.1
WHERE e.salary < dept.avg_sal;
高级更新技术
-- CASE条件更新
UPDATE employees
SET salary = CASEWHEN performance = 'A' THEN salary * 1.2WHEN performance = 'B' THEN salary * 1.1ELSE salary * 1.05
END;-- LIMIT限制更新数量
UPDATE employees
SET last_notice = CURRENT_DATE
WHERE notice_count = 0
LIMIT 100;-- 基于JOIN的更新
UPDATE employees e
JOIN departments d ON e.department_id = d.id
SET e.salary = e.salary * 1.15
WHERE d.location = '上海';
3.4 删除数据
条件删除
-- 基本删除
DELETE FROM employees
WHERE status = 'terminated';-- 多表关联删除
DELETE e FROM employees e
JOIN departments d ON e.department_id = d.id
WHERE d.name = '临时部门';-- LIMIT限制删除数量
DELETE FROM log_records
ORDER BY create_time
LIMIT 10000;
清空表数据
-- DELETE方式(可回滚)
DELETE FROM temp_data; -- 保留自增值-- TRUNCATE方式(更快,不可回滚)
TRUNCATE TABLE temp_data; -- 重置自增值-- 外键约束下的安全删除
SET FOREIGN_KEY_CHECKS = 0;
TRUNCATE TABLE important_data;
SET FOREIGN_KEY_CHECKS = 1;
四、高级查询技术
4.1 连接查询
内连接(INNER JOIN)
-- 基本内连接
SELECT e.name, d.department_name,p.project_name
FROM employees e
INNER JOIN departments d ON e.department_id = d.id
INNER JOIN projects p ON e.current_project = p.id;-- 使用USING简化相同列名连接
SELECT e.name, p.project_name
FROM employees e
INNER JOIN projects p USING (department_id);
外连接(OUTER JOIN)
-- 左外连接(保留左表所有记录)
SELECT e.name,m.name AS manager_name
FROM employees e
LEFT JOIN employees m ON e.manager_id = m.id;-- 右外连接(保留右表所有记录)
SELECT d.department_name,COUNT(e.id) AS employee_count
FROM departments d
RIGHT JOIN employees e ON d.id = e.department_id
GROUP BY d.department_name;-- 全外连接模拟(MySQL不支持FULL OUTER JOIN)
SELECT * FROM table1 LEFT JOIN table2 ON table1.id = table2.id
UNION
SELECT * FROM table1 RIGHT JOIN table2 ON table1.id = table2.id WHERE table1.id IS NULL;
特殊连接类型
-- 交叉连接(笛卡尔积)
SELECT e.name,p.project_name
FROM employees e
CROSS JOIN projects p;-- 自然连接(自动匹配相同列名,慎用)
SELECT * FROM employees NATURAL JOIN departments;-- STRAIGHT_JOIN强制连接顺序
SELECT STRAIGHT_JOIN e.name, d.name
FROM employees e JOIN departments d ON e.department_id = d.id;
4.2 子查询
WHERE子句中的子查询
-- 单行子查询
SELECT * FROM employees
WHERE salary > (SELECT AVG(salary) FROM employees);-- 多行子查询(IN)
SELECT * FROM employees
WHERE department_id IN (SELECT id FROM departments WHERE location = '北京'
);-- 多行子查询(EXISTS)
SELECT * FROM departments d
WHERE EXISTS (SELECT 1 FROM employees eWHERE e.department_id = d.id AND e.salary > 20000
);-- 比较运算符子查询(ALL/ANY)
SELECT * FROM employees
WHERE salary >= ALL (SELECT salary FROM managers
);
FROM子句中的派生表
-- 基本派生表
SELECT dept_stats.department, dept_stats.avg_sal
FROM (SELECT department, AVG(salary) AS avg_salFROM employeesGROUP BY department
) AS dept_stats
WHERE dept_stats.avg_sal > 15000;-- LATERAL派生表(MySQL 8.0+)
SELECT e.name, latest_review.review
FROM employees e,
LATERAL (SELECT review FROM performance_reviewsWHERE employee_id = e.idORDER BY review_date DESCLIMIT 1
) AS latest_review;
SELECT子句中的标量子查询
SELECT e.name,e.salary,(SELECT AVG(salary) FROM employees) AS company_avg,e.salary - (SELECT AVG(salary) FROM employees) AS diff_from_avg
FROM employees e;
公用表表达式(CTE)
-- 基本CTE
WITH dept_stats AS (SELECT department, COUNT(*) AS emp_count, AVG(salary) AS avg_salFROM employeesGROUP BY department
)
SELECT * FROM dept_stats
WHERE emp_count > 5;-- 递归CTE(生成序列)
WITH RECURSIVE numbers AS (SELECT 1 AS nUNION ALLSELECT n + 1 FROM numbers WHERE n < 100
)
SELECT * FROM numbers;-- 递归CTE(组织架构查询)
WITH RECURSIVE org_chart AS (SELECT id, name, manager_id, 1 AS levelFROM employees WHERE manager_id IS NULLUNION ALLSELECT e.id, e.name, e.manager_id, oc.level + 1FROM employees eJOIN org_chart oc ON e.manager_id = oc.id
)
SELECT * FROM org_chart ORDER BY level;
五、索引优化
5.1 索引创建策略
单列索引
-- 基本索引
CREATE INDEX idx_employee_name ON employees(name);-- 前缀索引(长字符串)
CREATE INDEX idx_email_prefix ON employees(email(10));-- 函数索引(MySQL 8.0+)
CREATE INDEX idx_name_lower ON employees((LOWER(name)));
复合索引
-- 基本复合索引
CREATE INDEX idx_dept_salary ON employees(department, salary);-- 包含INCLUDE列的索引(MySQL不支持,此为概念示例)
-- 实际MySQL中所有索引列都会参与索引结构
特殊类型索引
-- 唯一索引
CREATE UNIQUE INDEX idx_unique_employee_code ON employees(employee_code);-- 全文索引(MyISAM/InnoDB)
CREATE FULLTEXT INDEX idx_article_content ON articles(content);-- 空间索引(地理数据)
CREATE SPATIAL INDEX idx_location ON stores(coordinates);
索引选项
-- 指定索引类型
CREATE INDEX idx_hash_name ON employees(name) USING HASH;-- 指定索引算法
CREATE INDEX idx_btree_name ON employees(name) USING BTREE;-- 索引注释
CREATE INDEX idx_department ON employees(department) COMMENT '部门查询优化';
5.2 索引管理与优化
索引维护
-- 查看表索引
SHOW INDEX FROM employees;-- 获取索引信息
SELECT * FROM information_schema.STATISTICS
WHERE table_name = 'employees';-- 删除索引
DROP INDEX idx_employee_name ON employees;-- 重建索引(MyISAM)
REPAIR TABLE employees QUICK;-- 优化表(InnoDB)
OPTIMIZE TABLE employees;
索引使用分析
-- 使用EXPLAIN分析查询
EXPLAIN SELECT * FROM employees WHERE name = '张伟';-- 检查索引使用情况
SELECT object_type,object_schema,object_name,index_name,count_read,count_fetch
FROM performance_schema.table_io_waits_summary_by_index_usage
ORDER BY count_read DESC;-- 查找未使用索引
SELECT object_schema, object_name, index_name
FROM performance_schema.table_io_waits_summary_by_index_usage
WHERE index_name IS NOT NULL
AND count_star = 0
AND object_schema NOT IN ('mysql', 'performance_schema');
索引优化建议
选择合适索引列:
- 高选择性的列(如ID、用户名)
- 常用于WHERE、JOIN、ORDER BY的列
- 避免过度索引(一般表不超过5-6个索引)
复合索引设计原则:
- 最左前缀原则:
INDEX(a,b,c)
可优化a=1
、a=1 AND b=2
、a=1 AND b=2 AND c=3
- 等值查询列在前,范围查询列在后
- 常用排序字段可加入索引
- 最左前缀原则:
避免索引失效场景:
-- 索引失效示例 SELECT * FROM employees WHERE LEFT(name, 1) = '张'; -- 函数操作 SELECT * FROM employees WHERE salary * 1.1 > 10000; -- 计算操作 SELECT * FROM employees WHERE name LIKE '%伟'; -- 前导通配符
使用索引提示:
-- 强制使用索引 SELECT * FROM employees FORCE INDEX (idx_name) WHERE name = '张伟';-- 忽略索引 SELECT * FROM employees IGNORE INDEX (idx_salary) WHERE salary > 10000;-- 多索引选择 SELECT * FROM employees USE INDEX (idx_name, idx_dept) WHERE name = '张伟' OR department = '研发部';
定期维护:
- 使用
ANALYZE TABLE
更新索引统计信息 - 对大表考虑分区表设计
- 监控慢查询日志调整索引策略
- 使用