MySQL 入门笔记 📒
前言
什么是 MySQL?引用官方说明
MySQL is the world’s most popular open source database. Whether you are a fast growing web property, technology ISV or large enterprise, MySQL can cost-effectively help you deliver high performance, scalable database applications.
MySQL 是世界上最受欢迎的开源数据库。无论您是快速增长的 Web 资产,技术 ISV 还是大型企业,MySQL 都能经济高效地帮助您交付高性能,可扩展的数据库应用程序。
MySQL 是目前最流行的关系型数据库,国内外很多公司都在使用,作为一个应用开发人员还是有必要学习一下 MySQL 的基本知识的。
基础操作
使用 Docker 运行一个 MySQL 容器
1 | docker run --name my-mysql -e MYSQL_ROOT_PASSWORD=1234 -d -v volume_folder -p 3306:3306 mysql:5 |
命令行登录 MySQL
1 | docker exec -it my-mysql bash |
1 | mysql -u root -p |
创建数据库
1 | CREATE DATABASE db-name; |
显示数据库列表
1 | show databases; |
选择数据库
1 | use dbname; |
显示数据表
1 | show tables; |
创建数据表
1 | DROP TABLE IF EXISTS `user`; |
插入数据
1 | INSERT INTO table_name ( field1, field2 ) VALUES ( value1, value2 ); |
查询数据
1 | SELECT username FROM table_name where id=1 limit 1; |
更新数据
1 | update table_name set username='update' where id=1; |
删除数据
1 | delete from table_name where id=1; |
WHERE 有条件地从表中选取数据
1 | SELECT field1, field2,...fieldN FROM table_name1, table_name2... |
LIKE 有条件地从表中选取数据
1 | SELECT field1, field2,...fieldN |
UNION 连接 SELECT 语句的结果组合到一个结果集合中
1 | SELECT expression1, expression2, ... expression_n |
JOIN 根据两个或多个表中的列之间的关系从中查询数据
1 | SELECT Persons.LastName, Persons.FirstName, Orders.OrderNo |
查找表中多余的重复记录,重复记录是根据单个字段(peopleId)来判断
1 | select * from people |
删除表中多余的重复记录,重复记录是根据单个字段(peopleId)来判断
1 | delete from people |
显示数据表的结构
1 | describe table_name; |
添加列
1 | alter table 表名 add 列名 列数据类型 [after 插入位置]; |
修改列
1 | alter table 表名 change 列名称 列新名称 新数据类型; |
删除列
1 | alter table 表名 drop 列名称; |
重命名表
1 | alter table 表名 rename 新表名; |
清空数据表
1 | delete from table_name; |
删除数据表
1 | drop table table_name; |
删除数据库
1 | drop database dbname; |
退出 MySQL
1 | exit |
SQL 执行流程
- 当客户端连接到MySQL服务器时,服务器对其进行认证。可以通过用户名与密码认证,也可以通过SSL证书进行认证。登录认证后,服务器还会验证客户端是否有执行某个查询的操作权限。
- 在正式查询之前,服务器会检查查询缓存,如果能找到对应的查询,则不必进行查询解析,优化,执行等过程,直接返回缓存中的结果集。
- MySQL的解析器会根据查询语句,构造出一个解析树,主要用于根据语法规则来验证语句是否正确,比如SQL的关键字是否正确,关键字的顺序是否正确。而预处理器主要是进一步校验,比如表名,字段名是否正确等
- 查询优化器将解析树转化为查询计划,一般情况下,一条查询可以有很多种执行方式,最终返回相同的结果,优化器就是根据成本找到这其中最优的执行计划
- 执行计划调用查询执行引擎,而查询引擎通过一系列API接口查询到数据
- 得到数据之后,在返回给客户端的同时,会将数据存在查询缓存中
使用 MySQL
使用 DataGrip 链接 MySQL
在 Egg.js 中使用 MySQL 数据库
1 | module.exports = () => { |
MySQL 索引
MySQL 官方对索引的定义为:索引(Index)是帮助MySQL高效获取数据的数据结构。是针对表而建立的,它是由数据页面以外的索引页面组成,每个索引页中的行都含有逻辑指针,以便加速检索物理数据,创建索引的目的在于提高查询效率。
MyISAM
MyISAM 引擎使用 B+Tree 作为索引结构,叶节点的data域存放的是数据记录的地址。MyISAM 中索引检索的算法为首先按照 B+Tree 搜索算法搜索索引,如果指定的 Key 存在,则取出其 data 域的值,然后以 data 域的值为地址,读取相应数据记录。MyISAM的索引方式也叫做“非聚集”的,之所以这么称呼是为了与InnoDB的聚集索引区分。
InnoDB
在 InnoDB 中,表数据文件本身就是按B+Tree组织的一个索引结构,这棵树的叶节点data域保存了完整的数据记录。这个索引的key是数据表的主键,因此InnoDB表数据文件本身就是主索引。InnoDB 的辅助索引 data 域存储相应记录主键的值而不是地址。
创建使用索引的原则
1、索引尽量少,索引过多,影响写速度
2、建立索引尽量满足左匹配,索引只能命中最左边的范围查询,比如存在索引idx_a_b_c_d, 查询如select * from table where a=1 and b=2 and c>3 and d<4,则只能用到a,b,c
3、使用explain查看执行计划,需求所有的查询至少到达range级别
4、区分度不高的字段不建索引,比如性别,只有男和女,这种字段不需要建索引
5、表必须有主键索引,PRIMARY KEY (id
)
6、建立索引时,把区分度高的字段放在前面
建表三范式
- 要求有主键,并且要求每一个字段原子性不可再分
- 第一范式基础上,要求所有非主键字段完全依赖主键,不能产生部分依赖
- 在第二范式基础上,所有非主键字段和主键字段之间不能产生传递依赖
建表规范
命名规范
- 表名不使用复数名词
- 库名、表名、字段名使用小写字母,下划线 “_” 分割
- 库名、表名、字段名不超过 12 个字符
- 表名不使用复数名词
- 库名、表名、字段名见名知意, 尽量使用名词不是动词
- 不使用数据库保留字比如:key,desc,delete,order……
- 表的命名使用 “统一前缀_业务名称_表的作用” 模式,如:tb_plan, tb_task, tb_target
设计规范
- 使用布尔值类型存储是/否类字段
- 禁止在表中建立预留字段
- 所有表和字段都需添加注释
- 禁止在数据库存储图片、文件等二进制数据
- 存储引擎选择 InnoDB,表字符集选择 utf8mb4
- 将大字段拆分值其他表中
- 字段小写命名,禁止出现大写
- 尽可能把所有列定义为 NOT NULL,因为 NULL 在 MySQL 中得特殊处理、很难优化
- 优先选择符合存储需要的最小数据类型
- 对于非负整数,优先使用无符号整型存储(id)
- 避免使用 TEXT、BLOB 数据类型,非用不可的情况,可以把 BLOB 和 TEXT 拆分到单独的拓展表中
- 使用 TIMESTAMP 或 DATETIME 类型存储时间
- TIMESTAMP(4BYTE)1970-01-01 00:00:01 - 2038-01-19 03:14:07
- DATETIME(8BYTE)1000-01-01 00:00:00’ - 9999-12-31 23:59:59
- 用 decimal 来存储金额字段,不要用 float 和 double,会出现数据精度丢失
- 使用 INT UNSIGNED 存储 IP,IP 转数字函数 inet_aton()、数字转 IP 函数 inet_ntoa()
- VARCHAR(N) 中的 N 表示字符数(不是字节数、比如 VARCHAR(N) 能存储 N 个汉字)、满足需求的情况下 N 越小越好、最大长度65535个字节
- 对于定长的字符类型、比如密码 MD5 值等、建议用 char 类型,效率可以得到提升
最佳实践
- Optimize Your Queries For the Query Cache
- EXPLAIN Your SELECT Queries
- LIMIT 1 When Getting a Unique Row
- Index the Search Fields
- Index and Use Same Column Types for Joins
- Avoid SELECT *
- Almost Always Have an id Field
- Use ENUM over VARCHAR
- Get Suggestions with PROCEDURE ANALYSE()
- Use NOT NULL If You Can
- Prepared Statements
- Unbuffered Queries
- Fixed-length(Static) Tables are Faster
- Vertical Partitioning
- Split the Big DELETE or INSERT Queries
- Smaller Columns Are Faster
- Choose the Right Storage Engine
- Use an Object Relational Mapper
- 在使用 InnoDB 存储引擎时,如果没有特别的需要,请永远使用一个与业务无关的自增字段作为主键。
- 禁止从开发环境、测试环境直连生产环境数据库