MySQL
一、MySQL 基础
1. 什么是 MySQL?
MySQL是一个开源的关系型数据库管理系统(RDBMS, Relational Database Management System),它使用结构化查询语言(Structured Query Language, SQL)进行数据库的创建、管理和操作。MySQL 是由瑞典公司 MySQL AB 开发的,现在最终成为 Oracle 公司的产品。
关系主要指键,主键唯一标识,外键建立表与表之间的关系。
RDBMS 通常有 ACID 特性:
- 原子性 (Atomicity):事务中的所有操作要么
全部完成,要么全部不完成 -回滚
比如银行转账,1️⃣A账户扣款,2️⃣B账户加款。
如果中途失败了,没有事务支持的 MyISAM 就会出现 A 账户的款也扣了,B 账户又没加,钱凭空消失了。
p.s.InnoDB 会把整个转账操作作为一个事务,要是中途失败了,就回滚所有操作重来。
- 一致性 (Consistency):数据库只会从一个
有效状态转换到另一个有效状态
还是转账,数据库会有一个约束条件:A账户余额 + B账户余额 = 常量。
无论转账过程中发生什么错误,这个约束条件都必须成立。这才叫有效状态。
- 隔离性 (Isolation):
并发执行的事务互不干扰
当A在给B转账时,C只会看到A账户扣款前的余额;等A的转账事务提交后,C才能看到最新的余额。不可能出现C看到一个中间状态的情况。
- 持久性 (Durability):一旦事务提交,对数据库的修改是
永久
即使数据库崩溃、断电重启,数据也不会丢失。
2. 怎么创建 / 删除 一张表?
可以使用 DROP TABLE 来删除表,使用 CREATE TABLE 来创建表。
创建表的时候,可以通过 PRIMARY KEY 设定主键。
CREATE TABLE employees (
id INT AUTO_INCREMENT,
name VARCHAR(100) NOT NULL,
email VARCHAR(100),
salary DECIMAL(10, 2),
birthdate DATE,
PRIMARY KEY (id),
INDEX idx_name (name),
INDEX idx_birthdate (birthdate),
department VARCHAR(100),
location VARCHAR(100)
);
p.s. 如果要添加索引,CREATE INDEX idx_name ON employees(name); 跟 ALTER TABLE employees ADD KEY idx_name (name)是完全等价的。
3. 请写一个升序 / 降序的 SQL 语句?
可以使用 ORDER BY 来进行排序,默认是升序,可以使用 DESC 来指定降序。
比如要给员工表,以工资降序:
SELECT id, name, salary
FROM employees
ORDER BY salary DESC;
如果要多重排序,可以指定多个字段 (列):
SELECT id, name, salary
FROM employees
ORDER BY salary DESC, name ASC;
这样就按优先级,先按工资降序排序;如果工资相同,再按名字升序排序。
4. MySQL 出现性能差的原因有哪些?
- 可能是 SQL 查询用了全表扫描
- 没有使用索引
SELECT *
FROM employees
WHERE name = 'John';
- 用了索引,但索引列上有函数操作
SELECT *
FROM employees
WHERE YEAR(birthdate) = 1990;
- 模糊查询以通配符
%开头
SELECT *
FROM employees
WHERE name LIKE '%ohn';
p.s. 这里很有意思。 如果是LIKE 'John%',或是LIKE '_ohn',都是可以走索引的。
前者是因为索引是有序的,可以直接定位到John开头的部分;后者是因为_代表单个字符,索引定位到以ohn作为第2,3,4个字符的记录。
- 也可能是查询语句过于复杂,如多表
JOIN或嵌套子查询
- 多表
JOIN:
SELECT *
FROM employees
JOIN departments ON employees.department = departments
JOIN locations ON departments.location = locations
意思是,把 employees 表和 departments 表通过 department 字段连接起来,再把结果和 locations 表通过 location 字段连接起来,最后返回所有字段。
这样需要扫描三张表。
- 嵌套子查询:
SELECT * FROM 订单表
WHERE 用户id IN (
SELECT id FROM 用户表
WHERE 城市 IN (
SELECT 城市名 FROM 城市表
WHERE 省份 = '广东'
)
)
这样也需要扫描三张表。
- 当然也有可能单纯因为单张表的数据量过大
通常情况下,添加索引就能解决大部分性能问题。对于一些热点数据,还可以通过增加 Redis 缓存,来减轻数据库的访问压力。
5. 怎么存储emoji?
emoji 是 4 个字节的 UTF-8 字符,而 MySQL 默认的 utf8 字符集只支持 3 个字节的 UTF-8 字符,所以需要把字符集改成 utf8mb4 字符集 (m: minimum, b: bytes)。
ALTER TABLE 表名
CONVERT TO CHARACTER SET utf8mb4 -- 将字符集改为 utf8mb4
COLLATE utf8mb4_unicode_ci; -- 将排序规则改为 utf8mb4_unicode编码标准_不区分大小写(Case Insensitive)
p.s. _ci是Case Insensitive, 不区分大小写;_ai是Accent Insensitive, 不区分重音符号, 比如 é 跟 e 是一样的。
可以通过 SHOW VARIABLES WHERE Variable_name LIKE 'character\_set\_%' OR Variable_name LIKE 'collation%'; 查看。