数据库与MySQL基础知识
数据库系统(Database System)–DBS
数据库系统:
- 数据库,Database,–DB
- 数据库管理系统,Database Management System,–DBMS
- 数据库管理系统三个阶段:
- 网状模型
- 层级模型
- 关系模型(非关系模型)
关系型数据库(Relation Database Management System)(RDBMS):
常见关系型数据库有: Oracle DB2 Sybase MS SQL Server MySQL
- 数据以表格形式记录
- 行是各种记录
- 列为记录对应的数据域(字段名)
- 行和列组成表,若干表组成数据库
MySQL安装配置
-
win 安装包: 下载msi安装文件,安装完后,以管理员身份运行配置程序即可
-
win 打包文件: 下载zip压缩文件,解压到指定位置
- 修改配置文件: 复制my-default.ini备份, 改名为my.ini
# 基本设置 basedir='D:/mysql' //基本文件路径 datadir='D:/mysql/data' //数据文件路径(存储数据库文件,备份时一般得进控制台用命令行备份) port=3306 //MySQL默认端口 default-character-set=gbk/utf8/ascii //设置数据库编码方式 default-storage-engine=InnoDb //设置默认数据库存储引擎
- win安装mysql服务并命名为MySQL5, (mysql解压目录下启动cmd)
mysqld --install 'MySQL5' --default-file="D:/mysql/my.ini"
- 初始化数据库(即数据文件夹data)
mysqld --initialize --user=mysql --console
- 设置管理员密码
- my.ini 尾添加 skip_grant_tables //忽略权限(无密码登录MySQL)
- 登录MySQL
mysql -u root -p
直接回车 - 修改密码
mysql > use mysql; mysql > desc mysql > update use set authentication_string = PASSWORD('123456'); //初始化密码 set password = password('*******') //修改密码
- 在配置文件中my.ini删除skip_grant_tables
-
将mysql添加到环境变量: 将bin目录加入
Path
下 -
CMD命令行启动 or 停止MySQL服务 :
net start MySQL5 net stop MySQL5
-
其他常用命令
登录:mysql -u root -p -h127.0.0.1
显示MySQL系统相关信息:mysql > \s
退出MySQL:\q(quit)
MySQl其他注意项
- MySQL字符集
- 显示MySQL支持的字符集:
show characte set;
- 查看本地字符编码设置:
show VARIABLES LIKE '%CHARACTER%';
- 设置本地字符编码设置:
set NAMES xxxx;
- 显示MySQL支持的字符集:
- MySQL字母大小写问题:
- 关键字不区分大小写(建议使用大写)
- 数据库/表/视图名字由服务器的系统决定: 类UNIX下,名区分大小写;windows下,名不区分大小写
存储引擎
数据库存储引擎是规划决定数据存储方式,索引建立方式,更行/查询放式的某种技术手段
- MySQL支持的数据引擎:MyISAM,InnoDb,BDB,MEMORY,ARCHIVE
- MySQL5.5默引擎为MyISAM,后改用InnoDB
- 查看MySQL支持的引擎类型:
SHOW ENGINE
MyISAM与InnoDB的区别
- 存储结构
- MyISAM:每个MyISAM在磁盘上存储成三个文件. 第一个文件的名字以表的名字开始, 扩展名指出文件类型. .frm文件存储表定义. 数据文件的扩展名为.MYD (MYData). 索引文件的扩展名是.MYI (MYIndex).
- InnoDB:所有的表都保存在同一个数据文件中(也可能是多个文件, 或者是独立的表空间文件), InnoDB表的大小只受限于操作系统文件的大小, 一般为2GB.
- 存储空间
- MyISAM:可被压缩, 存储空间较小. 支持三种不同的存储格式:静态表(默认, 但是注意数据末尾不能有空格, 会被去掉)、动态表、压缩表.
- InnoDB:需要更多的内存和存储, 它会在主内存中建立其专用的缓冲池用于高速缓冲数据和索引.
- 可移植性、备份及恢复
- MyISAM:数据是以文件的形式存储, 所以在跨平台的数据转移中会很方便. 在备份和恢复时可单独针对某个表进行操作.
- InnoDB:免费的方案可以是拷贝数据文件、备份 binlog, 或者用 mysqldump, 在数据量达到几十G的时候就相对痛苦了.
- 事务支持
- MyISAM:强调的是性能, 每次查询具有原子性,其执行数度比InnoDB类型更快, 但是不提供事务支持.
- InnoDB:提供事务支持事务, 外部键等高级数据库功能. 具有事务(commit)、回滚(rollback)和崩溃修复能力(crash recovery capabilities)的事务安全(transaction-safe (ACID compliant))型表.
- AUTO_INCREMENT
- MyISAM:可以和其他字段一起建立联合索引. 引擎的自动增长列必须是索引, 如果是组合索引, 自动增长可以不是第一列, 他可以根据前面几列进行排序后递增.
InnoDB:InnoDB中必须包含只有该字段的索引. 引擎的自动增长列必须是索引, 如果是组合索引也必须是组合索引的第一列.
- MyISAM:可以和其他字段一起建立联合索引. 引擎的自动增长列必须是索引, 如果是组合索引, 自动增长可以不是第一列, 他可以根据前面几列进行排序后递增.
- 表锁差异
- MyISAM:只支持表级锁, 用户在操作myisam表时, select, update, delete, insert语句都会给表自动加锁, 如果加锁以后的表满足insert并发的情况下, 可以在表的尾部插入新的数据.
- InnoDB:支持事务和行级锁, 是innodb的最大特色. 行锁大幅度提高了多用户并发操作的新能. 但是InnoDB的行锁, 只是在WHERE的主键是有效的, 非主键的WHERE都会锁全表的.
- 表主键
- MyISAM:允许没有任何索引和主键的表存在, 索引都是保存行的地址.
- InnoDB:如果没有设定主键或者非空唯一索引, 就会自动生成一个6字节的主键(用户不可见), 数据是主索引的一部分, 附加索引保存的是主索引的值.
- 表的具体行数
- MyISAM:保存有表的总行数, 如果select count(*) from table;会直接取出出该值.
- InnoDB:没有保存表的总行数, 如果使用select count(*) from table;就会遍历整个表, 消耗相当大, 但是在加了wehre条件后, myisam和innodb处理的方式都一样.
- CURD操作
- MyISAM:如果执行大量的SELECT, MyISAM是更好的选择.
- InnoDB:如果你的数据执行大量的INSERT或UPDATE, 出于性能方面的考虑, 应该使用InnoDB表. DELETE 从性能上InnoDB更优, 但DELETE FROM table时, InnoDB不会重新建立表, 而是一行一行的删除, 在innodb上如果要清空保存有大量数据的表, 最好使用truncate table这个命令.
- 外键
- MyISAM:不支持
- InnoDB:支持
通过上述的比较, 基本上可以考虑使用InnoDB来替代MyISAM引擎了, 原因是InnoDB自身很多良好的特点, 比如事务支持、存储 过程、视图、行级锁定等等, 在并发很多的情况下, 相信InnoDB的表现肯定要比MyISAM强很多. 另外, 任何一种表都不是万能的, 只用恰当的针对业务类型来选择合适的表类型, 才能最大的发挥MySQL的性能优势. 如果不是很复杂的Web应用, 非关键应用, 还是可以继续考虑MyISAM的, 这个具体情况可以自己斟酌.
存储引擎选择的基本原则
- 采用MyISAM引擎
- R/W > 100:1 且update相对较少 //R/W读写比时
- 并发不高
- 表数据量小
- 硬件资源有限
- 采用InnoDB引擎
- R/W比较小, 频繁更新大字段
- 表数据量超过1000万, 并发高
- 安全性和可用性要求高
- 采用Memory引擎
- 有足够的内存
- 对数据一致性要求不高, 如在线人数和session等应用
- 需要定期归档数据
MySQL基本操作
创建/查看/删除数据库
CREATE DATABASE [IF NOT EXISTS] db_name [create_specification [,create_specification [,...ect]]];
- IF NOT EXISTS: 可选如果此名的数据库不存在则创建,存在则不创建但继续执行语句,不报错,也不覆盖原数据库
- create_specification: [DEFAULT] CHARACTER SET characte_name //设置编码格式
- [DEFAULT] COLLATE collate_name //设置排序方式(即比较时使用的字符集)
查看所有数据库
SHOW DATABASES;
查看数据库db_name创建时的语句
SHOW CREATE DATABASE db_name;
删除数据库db_name
DROP DATABASE [IF EXISTS] db_name;
创建/查看/删除表
CREATE TABLE tb_name (
fild1 datatype([size]) [comment '描述'], // 字段描述, 不是等号
fild2 datatype([size]),
fild3 datatype([size]),
fild4 datatype([size]),
fild5 datatype([size]),
...
fildn datatype([size])
)[engine [=] MyISAM | InnoDB| other engine_name] // 设置表引擎
[CHARACTER SET [=] utf8 | gbk | other charset_name] // 设置字符集
[comment [=]'描述']; // 添加表描述
SHOW TABLES; //显示所有表
DESC tb_name; //显示表结构
SHOW CREATE TABLE tb_name; //显示表创建语句
DROP TABLE tb_name; //删除表
SELECT * FROM tb_name; //查询表所有记录信息
SELECT col1,col2,...etc FROM tb_name; //查询指定col的记录信息
INSERT INTO tb_name [(col1,col2,...etc)] VALUES(val1,val2,...etc) //按指定的col插入记录
***当[(col1,col2,...etc)]省略时,VALUES插入值必须是按顺序的对应的所有col的值,不能有遗漏
MySQL数据类型:
数值型,文本型(字符串),日期时间型
数值型
-
整型: tinyint(1bt) samllint(2bt) mediumint(3bt) int(4bt) bigint(8bt)
- 一般使用用int类型
- 默认是有符号的,有正负,unsigned可设置为无符号的只有整数,数值范围翻倍
- zerofill标识,在数值位数不够时加前导零,默认加上unsigned属性
-
浮点型:float(M,D)(4bt) double(M,D)(8bt)
- M,数总长度,不算小数点;
- D,精度,即小数位数
-
定点型:decimal(M,D)(M>D?(M+2)bt:(D+2)bt)
- M,D同上
- decimal的小数点不可移动,是精确值
-
文本型
- CHAR 定长字符,定义多少放多少,不足以空格补齐,select查询去空格;范围,0~255个字符(无论中英文符号等)
- VARCHAR 变长字符,是多少放多少,select查询不会去空格;范围,0~65535个字节,具体可存字符数量由字段使用的字符集决定, 从第二个开始存放,后面1到2个字节存字符个数,所以最多也就存65532个字符
- text 文本类型,不能长度,不限字符数量,也没有默认长度
- enum 枚举,值限定在枚举列表中,只能选一个值;范围,最大65535个值
- set 枚举,值限定在枚举列表中,值可多选;范围,最大64个值
字符串尽量使用单引号
如果字符数量超过255个,请尽量使用text -
日期时间型
类型 | 范围 | 长度 | 零值 |
---|---|---|---|
date | 1000-01-01~9999-12-31 | 3 | 0000-00-00 |
time | -838:59:59~838:59:59 3 00:00:00 | ||
datetime | 1000-01-01 00:00:00~9999-12-31 23:59:59 | 8 | 0000-00-00 00:00:00 |
timestamp | 1970-01-01 00:00:00~2038-01-19 03:14:17 | 4 | 0000-00-00 00:00:00 |
year | 1901~2155 | 1 | 000 |
实际开发中一般使用int保存时间戳,或用date保存生日等日期
- NOW()返回当前系统时间:
select NOW();
- DATE_FORMAT(NOW(), ‘%Y’)返回当前年份:
select DATE_FORMAT(NOW(), '%Y');
MySQL字段属性
-
有无符号(unsigned),是否为空(is/not null),默认值(default ‘’),索引(index),额外(extra)
-
NULL和空字符的区别:
- 空字符不占用空间,而NULL不占用空间
- 空字符可以插入声明NOT NULL 的列,而NULL不能
- 空字符在select语句中没结果,NULL有结果
- 空字符在count计行时有数值,而NULL则不计入行数
条件表达式中不能用=NULL/!=NULL,得用is NULL /is NOT NULL
一般字段名设置NOT NULL,因为NULL要占用空间,而NOT NULL可插入’’(空字符)
create table tb_name(id int(10) unsigned not null primary key auto_increment , d timestamp);
insert into tb_name(null,null);
- 主键(primary key):
- 用于独一无二的识别每条记录,它是表中的某一列的属性,可以让每一条记录成为唯一的
- 一张表只能定义一个主键,可以指定一列或多列;指定多列的称为组合主键,创建时要使用表定义;
- 创建方式: 行级定义,表级定义
create table tb_name(id int(10) not null unsigned primary key auto_increment,name char(10) not null)auto_increment=1001;
create table tb_name(id int(10) not null unsigned name char(10) not null,primary key ('id','name'));//id-name组合主键
- auto_increment,自加,一般用在id 列上
- 列类型必须为整数,且有索引
- 可以有重复值,但唯一索引不能有重复值
- 列必须设为NOT NULL ,若无 auto_increment 会自动加上 not null
- 一张表只有一列可以设置为 auto_increment
- 在创建表时,列名后面加 auto_increment标记,字段名括号外可用 auto_increment=n赋初始值,
- 列中的值一经使用,就不会再次被用,除非用truncate清空数据(delete不行),或是主键列插入式指定
MySQL字段类型选择
- 布尔型用tinyint表示,例如0代表false,1代表true
- 时间一般用int保留时间戳
- 整数能用小的就不用大的
- 小数,根据需要使用(近似值float,精确值,decimal)
- 字符串,若字符数固定,如身份证/MD5加密后的数据,手机号等用char比较好; 若字符数不固定,则使用varchar
- 字符数超过255个,推荐使用text
- 字符串的结果是预定义值,并且值较少,可以使用enum/set,十几个就可以另建表
- IP保存:使用char,15或16位字符; 使用inet_aton和inet_ntoa,前者存储室将其转为整型,后者读取时转为字符IP
mysql> create table tb1(ip int(11) unsigned ,c char(2));
mysql> insert into tb1 values (inet_aton('127.0.0.1'),'a'),(inet_aton('192.168.0.1'),'b');
mysql> select * from tb1;
+------------+------+
| ip | c |
+------------+------+
| 2130706433 | a |
| 3232235521 | b |
+------------+------+
mysql> select inet_ntoa(ip),c from tb1;
+---------------+------+
| inet_ntoa(ip) | c |
+---------------+------+
| 127.0.0.1 | a |
| 192.168.0.1 | b |
+---------------+------+
CURD操作
SQL
SQL(Structured Query Language),结构化查询语言,在关系型数据库上执行数据操作/检索/维护的标准语言
SQL 功能
- 改变数据库结构
- 更改系统安全设置
- 维护用户对数据库或表的许可权限
- 在数据库中检索需要的信息
- 对数据库的信息进行更新
SQL 分类
- DDL(Data Defeinition Language),数据定义语言,定义对数据库对象(库/表/列/索引)的操作
CREATE DROP ALTER RENAME TRUNCATE //库/表级操作 - DML(Data Manipulation Language),数据操作语言,定义对数据记录的操作
INSERT DELETE UODATE SELECT等 //行级操作 - DCL(Data Control Language),数据控制语言,定义对数据库,表,字段,用户的访问权限和安全级别
GRANT REVOKE 等 - Transaction Control事务控制
COMMIT ROLLBACK SAVEPOINT …
SQL书写规范
- 在数据库系统中,SQL语句不分大小写(建议用大写)
- 字符串常量区分大小写
- SQL语句可单行或多行书写,以;(英文下)结尾
- 关键词不能跨多行或简写
- 用空格,缩进来提高语句可读性
- 字句通常位于独立行,便于编辑和可读性
- 注释,SQL /**/多行注释 --单行注释;MySQL #注释
- MySQL中单引号起来的数值,字符…处理
CRUD–表,创建/读/更新/删除表
create database db_name;
create table tb_name;
insert into tb_name(col1,col2,col3,...etc) values (val1,val2,val3,...etc);
insert into tb_name values(val1,val2,...etc);
insert into tb_name(col1,col2,col3,...etc) select col1,col2,...etc from tb2;
查询语句:
select *|{col1,col2,col3...}
from tb_name
[where where_definition]
- where 常用的条件
运算符 | 说明 | 例子 |
---|---|---|
= != > < | 比较大小 | |
between … and … | 某一区间的值,闭区间 | between 5 and 10 |
in(set) | 显示in列表中的值 | in(100,200) |
like(_ %) | 模糊查询,%表示多个或0个字符,_表示一个字符 | |
is null | 判断是否为空 | |
and | 都成立则成立 | |
or | 一个成立则成立 | |
not | 非 |
5 <= colnum <= 10
无效, 可以使用between and
或者是colnum => 5 and colnum <= 10
更新语句:
update tb_name
set col1=val1 [,col2=val2,...]
[where where_definition]
- where 子句一般不可少,没有where,则会更新所有对应列的记录
- update成功的两条件,语句OK,数据行也更新成功
- update和insert连用,数据有符合条件的行存在则更新,无则插入新行:
insert into tb_name(colmun_list) values(val_list) on duplicate key update col1=val1,col2=val2,...etc;
删除语句:
delete from tb_name where where_definition;
- 一定得记得加where条件,不加则删表中除所有记录
- delete 语句删除以行为单位,不能删除某列某行的特定值
- delete 删表只删记录, auto_increment自增的值还没清
- truncate清空表是把表所有记录痕迹删除,auto_increment自增清除,从头再来
- 从表中删记录时要考虑表间的约束关系(其他表的参照完整性),如外键约束,唯一约束等,update,insert时也是要考虑
修改表结构(ALTER)
- RENAME(改表名): alter table tb_name rename new_tb_name;
- CHANGE(改列名): alter table tb_name change old_col_name new_col_name datatyepe[(len)];
- MODIFY(改列名的类型): alter table tb_name modify col_name new_datatype;
- DROP(删除列): alter table tb_name drop col_name;
- ADD(增加列): alter table tb_name add col_name datatype [fisrt|after col1]; //加在第一列,或col1之后
删除表
- DROP TABLE tb_name;
SELECT语句其它常用关键字
- DISTINCT( ),select查询结果去重
- ORDER BY (排序) ,查询结果排序(可对多列进行排序)
- LIMIT(限制),限制查询结果的输出行数,一般用于查询结果分页
- GROUP BY 分组, 将列中记录相同的值分到一组,一般和count的聚合函数一起用,统计组的相关信息,如统计同班同组的人数等
查询结果中col1,col2只显示组中的第一个值
函数group_concat(col1)可把其他列的结果横列(一个记录格里放多个数据记录)在同组的那一行
select查询的列,只限于select的聚合函数列和分组条件的列(coln),如 count(colm),coln
group by 可对多列进行分组:select col1,col2 from tb_name group by col1,col2; - having 子句,having同where写法类似,但having在结果中进行筛选,而where对原始记录进行删选,having一般跟在group by后面
- 常用的聚合函数(常于group by搭配)
- count(col|*),计数,返回某一列记录的行数
- sum(column),求和,返回column所有质的和,配合group by,可分类汇总
- avg(column),求平均数,返回column所有质的平均值,同上
- max/min(),求最大/最小值,同上
select distinct col_list from tb_name where ...;
select col1,col2,col3,...etc | col_name as as_name
from tb_name
order by coln[,colm] |as_name [asc | desc];
select col1,col2,col3,...etc
from tb_name
limit [offset,] rows | rows OFFSET offset; //offset偏移量从0计
select col1,col2,...coln |count(colm),coln
from tb_name wehre ...
group by coln;
select col1,col2,...coln |count(colm),coln
from tb_name wehre ...
group by coln having ...;
select count(*)| sum(column) | avg(column) |max(column) |min(column)
from tb_name
where where_definition
子句总结
- 书写顺序:where -->> group by -->> having -->>order by -->>limit;
- 执行顺序:
- from子句组装来自不同表(库)的数据
- where子句基于指定的条件对记录行进行筛选
- group by 子句将数据划分多个分组
- 使用聚合函数进行计算
- 使用having子句对结果进行筛选
- 计算所有表达式
- 使用order 不要对结果进行排序
- limit 语句调整输出的数量
MySQL 进阶操作
多表查询
连接查询
连接查询是将两个或两个以上的表按照某个条件连接起来,从中选取需要的数据,通过表中有意义相同的字段连接起来,分内连接和外连接
- 内连接,表中有意义相同的字段使用
=
或者>,<,!=
等作为连接条件连接两表
select * |col1,col2,...etc
from tb1 [inner] join tb2 on tb1.coln =| !=| >| < tb2.colm
[where where_definition ]
或者使用,
连接两表, where 连接条件
select * |col1,col2,...etc from tb1,tb2 where tb1.coln =| !=| >| < tb2.colm
- 外连接,分为左连接,右连接,大体同内连接,区别在做左连接会查询左表所有记录查询右边匹配记录,而右表查询右表所有记录只查左表所有记录,
- 左连接select col1,col2,…etc from tb1 left join tb2 on tb1.coln = tb2.colm
- 右连接select col1,col2,…etc from tb1 right join tb2 on tb1.coln = tb2.colm
复合连接查询
即多个表连接查询
select * |col1,col2,...etc
from tb1 [inner] join tb2 on tb1.coln =| !=| >| < tb2.colm
[inner] join tb2 on tb3.coln =| !=| >| < tb3.colm
[where where_definition ]
子查询
子查询,将一个查询语句作为子句嵌套到另一个查询语句中,子查询语句的结果作为外层查询到的条件
select * |col1,col2,...etc from tb1
where [coln] >|<|=|!=|[not]in |[not] exists |any |all (select col1,...form tb2);
常用的子查询条件:
- 比较运算符:=,!=,>,<,
- [not]in,
- [not]exists ,子查询有结果则where为真,执行外层查询,反之则反
- any,外层where条件满足任何一个子查询的结果,则条件满足,any一般和比较运算符一起用
- all,外层where条件满足所有一个子查询的结果,则条件满足,all也是一般和比较运算符一起用
合并查询
合并查询,将多个select查询结果合并到一起
- union,将多个select查询结果合并到一起,并去掉重复值
- union all,将多个select查询结果简单合并到一起,不会去掉重复值
AS(别名)
- 表别名:当表的名称特别长时, 在查询中直接使用表名很不方便, 这时可以为表取一个别名, 用别名来代替表的名称
SELECT * FROM salgrade as s where s.grade>2
; - 字段别名:查询数据时, 默认的情况下MySQL会显示创建表是定义的列名或是加函数得字段名,可加直观的名字来表示这一列
SELECT sum(coln) as sum(总数) FROM salgrade;
- as 可以省略, 别名直接跟在原名后面, 如:
table_name tb | column col
视图
视图(view),可视化表,是一个、多个表,或者是从已存在的视图导出的虚拟表,其行为和表很相似,可以使用select,delete,update的操作.
视图的作用
- 简单化:那些被经常使用的查询可以被定义为视图, 从而使得用户不必为以后的操作每次指定全部的条件
- 安全性:通过视图用户只能查询和修改他们所能见到的数据
- 逻辑数据独立性:视图可以帮助用户屏蔽真实表结构变化带来的影响
创建视图(CREATE VIEW)
create [algorihm={undefined | meegee |temptable}]
view view_name(column_list)
as select statement
[with [cascaded | local ] check option]
查看视图
show tables ; //查看当前数据库里的所有表,包括虚拟表---视图
describe(desc) view_name; //查看视图结构
show create view view_name; //查看视图创建语句
show table status like '%view_name%'; //like 跟匹配字符,可模糊查询所需的视图
select * from information_schema.views;//查看所有的视图
MySQL将所有的视图信息存放在数据库information下的views表内,包括系统和自建的视图
修改视图
若视图不存在,则创建(create),若存在则替换(replace)
create or replace [algorihm={undefined | meegee |temptable}]
view view_name(column_list)
as select statement
[with [cascaded | local ] check option]
直接修改
alter [algorihm={undefined | meegee |temptable}]
view view_name(column_list)
as select statement
[with [cascaded | local ] check option]
删除视图
drop view if exists view_name [restrict | cascade]
更新视图数据
update view_name
set col1=val1,col2=val2,...
where where_definition
删除视图数据
delete from view where where_definition
视图更新删除数据时,会把它对应基本表的上的信息也更新/删除掉
插入也是,但视图字段一般不全,插入不进去,字段全的视图没啥意思
- 以下情况视图无法删除
- 视图中包含sum(),count(),max(),min()等函数
- 视图中包含union[all],distinct,group by,having 等关键字
- 视图中包含子查询
- 有不可更新视图导出的视图
- 创建视图时,algorihm设为temptable(临时表)的
- 视图对应的表上存在没有默认值的列,而且该列没有包含在视图里
事务
事务是一种运行机制,由一组数据库操作命令组成的操作序列,具有以下特性:
- 原子性(atonmicity),事务是一个不可分割的逻辑单元,一组SQL语句要么全部执行,要么全部不执行
- 一致性(consistency),事务发生前后,数据具有一致性
- 隔离性(isolation),事务执行过程是不可见的
- 持久性(durability),事务一旦提交,则不可撤销
Atonmicity+Consistency+Isolation+Durability=ACID
事务语句:
- 开始事务 start transaction; | begin;
- 提交 commit;
- 回滚事务 rollback;
MySQL的事务是由存储引擎决定的
MyISAM:不支持事务,用于只读程序提高性能
InnoDB:支持ACID事务
表设计
构造数据库(表)必须遵循一定得规则,在关系型数据中这些规则称为范式
- 第一范式(1NF):原子性,即字段不能或者不应该再被分割,所有关系型数据库都必须遵循第一范式
- 第二范式(2NF):用单一主键标记整条记录,不要也不能出现多个主键
- 第三范式(3NF):先满足前两个范式,若不能则可新建一个表
规范化的表中没有重复的数据,但也不能为了遵守范式而非要拆分为多个表,有事本分重复可提高效率 - 需求处理
- 收集分析,用户在数据管理中的信息要求,处理要求,安全性要求,完整性要求;整理出数据字典
数据字典:数据项—数据结构—数据流—数据存储—处理过程
简版数据字典:字段名—数据类型—主键/外键 - ER图(Entily Relationship Digram),即需求分析—逻辑设计
一对多,多对一,(1:N N:1)
一对一,(1:1)
多对多,(M:N) 通过设置中间表转为多个一对多关系(1:M M:N N:1)
- 收集分析,用户在数据管理中的信息要求,处理要求,安全性要求,完整性要求;整理出数据字典
主键/外键关联
- 主键关联:通过两个表的主键建立关联联系,要求两个表的主键必须完全一致
- 外键关联:通过表(子表)的一列参照关联另一表的(父表)主键,形成的参照关系,称为外键关联,用来保证数据表的完整性和一致性
- 被引用的主键表通常称为父表
- 外键与它引用的主键名可不相同
- 外键值不要求唯一
- 外键的创建,建表时创建:
CREATE TABLE tb_name(col1,col2,...coln, foreign key (colm) references parent_tb_name(coli);
- 在已建好的表上添加:
ALTER TABLE tb_name add foreign references tb2(coli) ;
- 删除外键,
alter table tb1 drop foreign key key_name;
创建时未定义键名时,可用show create table 语句查看外键名
有了外键之后, 两个表之间的记录有严格的约束关系,在插入子表时,外键列不许有值,或是NULL,在删除父表记录时,要保证父表该记录主键的值没有对应子表的外键存在,否则无法删除,当然这些关系可以通过以下关键词调整:
- on delete | update cascade | set null | restrict | no action
- cascade 父表删除时,子表删除所对应外键的记录
- set null 父表删除时,子表设置所对应外键的记录字段为NULL
- restrict同no action 拒绝删除/更新操作(默认值)
- 外键需要注意的细节
- 外键指向的字段必须是primary key 或者unique
- 子表和父表的存储类型必须都是InnoDB,否则不支持外键
- 外键字段的值必须在主键中出现过,或者为NULL
索引
索引是一种特殊的数据结构(可称为加在表上的索引列),用来快速查询数据表中的特定记录,能大幅提高数据库性能. 常见索引:
- 普通索引,index
- 唯一索引,unique [index] ,索引列的值必须唯一,可以有null
- 主键索引,primary key ,特殊的唯一索引,不允许有空,null
- 全文索引,fulltext [index],全文索引,只能用在char/varchar/text类型的列上
索引设计原则
- 选择唯一索引
- 为经常需要排序,分组和联合操作的字段建立索引
- 为常作为查询条件的字段建立索引
- 限制索引的数目
- 尽量使用数量少的字段作为索引
- 删除不再或者很少使用的索引
创建索引
- 建表时是创建索引,
create table tb_name(
id int(10) not null primary key auto_increment,
name varchar(20) not null unique,
age int(3),
unique index index_name(name) //给name加上名为index_name的唯一索引
);
- 已建表上添加索引
create [unique|fulltext] index index_name on table_name (col_name);
alter table table_name add [unique|fulltext] index index_name(co_name);
alter table table_name add primary key (id); //给字段id加主键索引
MySQL函数
系统函数
系统函数,即MySQL系统定义的函数,如之前用到的sum,count等聚合函数
MySQL函数按处理数据的类型一般分为三类:数值函数,字符串函数,日期时间函数
数值函数:
- abs(num) 取绝对值
- bin(num) 十进制转二进制
- conv(number2,from_base,to_base) 进制转换
- hex(DecimalNumber) 转十六进制注:HEX()中可传入字符串,则返回其ASC-11码,如HEX(‘DEF’)返回4142143,也可以传入十进制整数,返回其十六进制编码,如HEX(25)返回19
- ceiling(number2) 向上取整
- floor(number2) 向下取整
- format(number,decimal_places) 保留小数位数
- least(number,number2[,…]) 求最小值
- mod(numerator,denominator) 求余
- power((number,power) 求指数
- rand([seed]) 随机数
- round(number[,decimals]) 四舍五入,decimals为小数位数
- sqrt(number) 开平方
字符串函数
- charset(str) 返回字串字符集
- concat(string[,…]) 连接字串
- instr(string,substring) 返回substring首次在string中出现的位置
- lacse(string) 转换成小写
- left(string,length) 从string中的左边起取length个字符
- length(string) string长度,字节
- char_length(string) string的字符个数
- load_file(file_name) 从文件读取内容
- locate(substring,string[,start_position]) 同INSTR,但可指定开始位置
- lpad(string,length,pad) 重复用pad加在string开头,直到字串长度为length
- ltrim(string) 去除前端空格
- repeat(string,count) 重复count次
- replace(str,search_str,replace_str) 在str中用replace_str替换search_str
- rpad(string,length,pad) 在str后用pad补充,直到长度为length
- ptrim(string) 去除后端空格
- strcmp(string1,string2) 逐字符比较两字串大小
- sunstring(str,position[,length]) 从str的position开始,取length个字符
日期时间函数:
- current_date( ) 当前日期
- current_time( ) 当前时间
- current_timestamp( ) 当前时间戳
- now( ) 当前时间
- date(datetime ) 返回datetime的日期部分
- year(datetime ) 返回年份
- month(datetime) 返回月份
- day(datetime ) 返回日期的天
- hour(datetime) 返回小时
- minute(datetime) 返回分
- microsecond(datetime) 返回微秒
- date_add(date , INTERVAL d_value d_type ) 在date中加上日期或时间
- date_format(datetime ,FormatCodes ) 使用formatcodes格式显示datetime
- date_sub(date , INTERVAL d_value d_type ) 在date上减去一个时间
- datediff(date1 ,date2 ) 两个日期差
- dayname(date ) 英文星期
- dayofyear(date ) 一年中的第几天
- dayofmonth(datetime) 月的第几天
- dayofweek(date ) 星期(1-7) ,1为星期天
- extract(interval_name FROM date ) 从date中提取日期的指定部分
- makedate(year ,day ) 给出年及年中的第几天,生成日期串
- maketime(hour ,minute ,second ) 生成时间串
- week(date_time [,start_of_week ]) 第几周
- last_day(date) date的月的最后日期
自定义函数
语法结构
create function fun_name( 参数名 参数类型)
retruns 类型(返回值类型,必须写);
函数体;
return XXX;
调用: select fun_name(参数);
eg: //创建函数时先要选取数据库
mysql> create function fun(n int)
-> returns int
-> return n*n;
Query OK, 0 rows affected (0.00 sec)
mysql> select fun(100) ;
+----------+
| fun(100) |
+----------+
| 10000 |
+----------+
1 row in set (0.00 sec)
- 查看当前数据库的函数
SHOW FUNCTION STATUS [LIKE ‘pattern’]; - 查看函数创建语句
SHOW CREATE FUNCTION function_name; - 删除过程或函数
DROP FUNCTION [IF EXISTS] sp_name
delimiter
当函数中需要使用分号(;)换行时,可用delimiter指定sql语句的结束符(如//)
delimiter $$
create function func(num int)
returns int
begin
declare nn int(10); //定义变量nn
set nn=num*num;
return nn;
end $$
select func(10) $$
存储过程
- 存储过程:是在数据库中定义一些SQL语句的集合
- 存储过程在数据库中存储过程经过第一次编译后再次调用不需要再次编译,
- 直接调用存储过程即可执行已经定义好的SQL语句
- 存储过程可以避免开发人员重复的编写相同的SQL语句,
- 存储过程是在MySQL服务器中存储和执行的,可以减少客户端和服务器端的数据传输.
- 定义方式:
cerate procedure pro_name({in|inout|out} arguments arg_type )
statements; //存储体
call pro_name(num) //调用存储过程
set @varname=value;
delimiter $$
cerate procedure pro1(in num int )
begin
insert into t1 values(num);
end $$
--调用存储过程
call pro1(20)$$
- 查看存储过程
SHOW {PROCEDURE | FUNCTION} STATUS [LIKE 'pattern']
SHOW PROCEDURE STATUS LIKE ‘Coun%'\G
SHOW CREATE {PROCEDURE | FUNCTION} sp_name
- 删除过程或函数
DROP {PROCEDURE | FUNCTION} [IF EXISTS] sp_name
- 参数形式:
- IN: 输入参数:表示该参数的值必须在调用存储过程时指定,在存储过程中修改该参数的值不能被返回,为默认值
- OUT: 输出参数:该值可在存储过程内部被改变,并可返回
- INOUT: 输入输出参数:调用时指定,并且可被改变和返回
关于函数与存储过程
一般来说,存储过程实现的功能要复杂一点,而函数的实现的功能针对性比较强.
存储过程,功能强大,可以执行包括修改表等一系列数据库操作;用户定义函数
不能用于执行一组修改全局数据库状态的操作.
对于存储过程来说可以返回参数,如记录集,而函数只能返回值或者表对象,函数
只能返回一个变量;而存储过程可以返回多个.存储过程的参数可以有IN,OUT,
INOUT三种类型,而函数只能有IN类~~存储过程声明时不需要返回类型,而函数声
明时需要描述返回类型,且函数体中必须包含一个有效的RETURN语句.
MySQL进阶操作2
MySQL主从复制
MySQL 复制基于主服务器在二进制日志中跟踪所有对数据库的更改(更新、删除等等).每个从服务器从主服务器接收主服务器已经记录到其二进制日志的保存的更新,以便从服务器可以对其数据拷贝执行相同的更新.通过主从复制还可以实现MySQL的读写分离将主服务器作为插入,删除,更新的表,从服务器用于读取(配置从服务器添加’read-only=ON’)
MySQL主从复制配置
安装多个MySQL服务:解压两个mysql包,修改各自配置文件(my.ini),笔者使用的版本为5.7.14; 解压到mysql3307和mysql3308两个文件夹
- 配置mysql3307:
- port=3307
- server-id=10;
- log-bin=mysql-bin //开启二进制日志
其他配置同一般设置,注意bin目录和data目录设置
- 安装MySQL3307服务:
cmd进入D:\MySQL\MySQL3307\bin\目录,执行mysqld -install MySQL3307 --defaults-file="D:\MySQL\MySQL3307\my.ini"
- 安装成功后,启动服务,执行
net start MySQL3307
- 配置MySQL3308:
- port=3308
- server-id=100 不同于其它的MySQL服务即可
- read-only=ON
- log-bin=mysql-bin //开启二进制日志
其它配置操作同上
设置主从服务
- 主服务(MySQL3307)添加从服务器使用的账号
GRANT REPLICATION SLAVE ON *.* TO 'uname'@'ip' IDENTIFIED BY 'password';
本地账户需设置3个账户,ip分别为::1,127.0.0.1,localhost
GRANT REPLICATION SLAVE ON *.* TO 'repl'@'::1' IDENTIFIED BY '123456';
GRANT REPLICATION SLAVE ON *.* TO 'repl'@'127.0.0.1' IDENTIFIED BY '123456';
GRANT REPLICATION SLAVE ON *.* TO 'repl'@'localhost' IDENTIFIED BY '123456';
- 查看主机状态,以便设置从服务器
mysql> show master status;
+------------------+----------+--------------+------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
| mysql-bin.000007 | 154 | | | |
+------------------+----------+--------------+------------------+-------------------+
- 设置从服务器(在3308中设置)
mysql> change master to MASTER_HOST='127.0.0.1',MASTER_PORT=3307,MASTER_USER='repl',MASTER_PASSWORD='123456',master_log_file='mysql-bin.000001',master_log_pos=154;
Query OK, 0 rows affected
- 参数解释:
- MASTER_HOST : 设置要连接的主服务器的ip地址
- MASTER_USER : 设置要连接的主服务器的用户名
- MASTER_PASSWORD : 设置要连接的主服务器的密码
- MASTER_LOG_FILE : 设置要连接的主服务器的bin日志的日志名称,
- MASTER_LOG_POS : 设置要连接的主服务器的bin日志的记录位置,
- 开启主从复制
mysql> start slave;
Query OK, 0 rows affected
- 查看从服务器复制设置
mysql> show slave status \G
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 127.0.0.1
Master_User: repl
Master_Port: 3307
Connect_Retry: 60
Master_Log_File: mysql-bin.000001
Read_Master_Log_Pos: 154
Relay_Log_File: huwhois-relay-bin.000002
Relay_Log_Pos: 320
Relay_Master_Log_File: mysql-bin.000001
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Replicate_Do_DB:
Replicate_Ignore_DB:
Replicate_Do_Table:
Replicate_Ignore_Table:
Replicate_Wild_Do_Table:
Replicate_Wild_Ignore_Table:
Last_Errno: 0
Last_Error:
Skip_Counter: 0
Exec_Master_Log_Pos: 154
Relay_Log_Space: 529
Until_Condition: None
Until_Log_File:
Until_Log_Pos: 0
Master_SSL_Allowed: No
Master_SSL_CA_File:
Master_SSL_CA_Path:
Master_SSL_Cert:
Master_SSL_Cipher:
Master_SSL_Key:
Seconds_Behind_Master: 0
Master_SSL_Verify_Server_Cert: No
Last_IO_Errno: 0
Last_IO_Error:
Last_SQL_Errno: 0
Last_SQL_Error:
Replicate_Ignore_Server_Ids:
Master_Server_Id: 1
Master_UUID: bf7740ad-4f62-11e7-99df-08d40c21b1f4
Master_Info_File: D:\mysql\MySQL3308\data\master.info
SQL_Delay: 0
SQL_Remaining_Delay: NULL
Slave_SQL_Running_State: Slave has read all relay log; waiting for more up
dates
Master_Retry_Count: 86400
Master_Bind:
Last_IO_Error_Timestamp:
Last_SQL_Error_Timestamp:
Master_SSL_Crl:
Master_SSL_Crlpath:
Retrieved_Gtid_Set:
Executed_Gtid_Set:
Auto_Position: 0
Replicate_Rewrite_DB:
Channel_Name:
Master_TLS_Version:
1 row in set (0.00 sec)
代表从服务复制已经开启<以下两个一定要是yes>
- Slave_IO_Running: Yes
- Slave_SQL_Running: Yes
主从复制测试
在3307中 创建test库
mysql> create database test ;
可在3308中查看到
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| sys |
| test |
+--------------------+
5 rows in set (0.00 sec)
重新配置需要先停止从服务 执行:stop slave;
/****补充:从服务的一些配置说明***/
read_only=ON
#该选项让从服务器只允许来自从服务器线程或具有SUPER权限的用户的更新.可以确保从服务器不接受来自客户的更新.
replicate_do_db=db_name
#告诉从服务器只做默认数据库(由USE所选择)为db_name的语句的复制.要指定多个数据库,应多次使用该选项,每个数据库使用一次.请注意不复制跨数据库的语句
replicate_do_table=db_name.tbl_name
#告诉从服务器线程只做对指定表的复制.要指定多个表,应多次使用该选项,每个表使用一次.同–replicate-do-db对比,允许跨数据库更新.
replicate_ignore_db=db_name
#告诉从服务器不要复制默认数据库(由USE所选择)为db_name的语句.要想忽略多个数据库,应多次使用该选项,每个数据库使用一次.
replicate-ignore-table=db_name.tbl_name
#告诉从服务器线程不要复制更新指定表的任何语句(即使该语句可能更新其它的表).要想忽略多个表,应多次使用该选项,每个表使用一次.
replicate_wild_do_table=db_name.tbl_name
#告诉从服务器线程限制复制更新的表匹配指定的数据库和表名模式的语句.模式可以包含‘%'和‘_'通配符,与LIKE模式匹配操作符具有相同的含义.要指定多个表,应多次使用该选项,每个表使用一次.该选项可以跨数据库进行更新.
–replicate_wild_ignore_table=db_name.tbl_name
#告诉从服务器线程不要复制表匹配给出的通配符模式的语句.要想忽略多个表,应多次使用该选项,每个表使用一次.该选项可以跨数据库进行更新.
#replicate_rewrite_db=from_name->to_name
告诉从服务器如果默认数据库(由USE所选择)为主服务器上的from_name,则翻译为to_name.只影响含有表的语句
report_host=slave_name
#从服务器注册过程中报告给主服务器的主机名或IP地址.该值出现在主服务器上SHOW SLAVE HOSTS的输出中.如果不想让从服务器自己在主服务器上注册,则不设置该值.
report_port=slave_port
#连接从服务器的TCP/IP端口号,从服务器注册过程中报告给主服务器.
skip_slave_start
#告诉从服务器当服务器启动时不启动从服务器线程.使用START SLAVE语句在以后启动线程.
slave_skip_errors=[err_code1,err_code2,… | all]
#通常情况,当出现错误时复制停止,这样给你一个机会手动解决数据中的不一致性问题.该选项告诉从服务器SQL线程当语句返回任何选项值中所列的错误时继续复制.
slave-skip-errors 一般使用的值
slave-skip-errors=1062,1053
slave-skip-errors=all
备份、恢复
备份(backup):整体部分,增量备份
备份方式:第三方软件,效果好,但收费如 navicat prem,也有免费的如phpmyadmin
mysql自带工具,Mysqldump
Mysqldump备份和恢复(命令行操作)
- 导出一张表 Mysqldump -u用户名 -p密码 库名 表名 > 文件名(D:/a.sql)
- 导出多张表 Mysqldump -u用户名 -p密码 库名 表名1 表名2 表名3 > 文件名(D:/a.sql)
- 导出所有表 Mysqldump -u用户名 -p密码 库名 > 文件名(D:/a.sql)
- 导出一个库 Mysqldump -u用户名 -p密码 -B 库名 > 文件名(D:/a.sql)
密码可先不输入,回车后再输入
MySQL恢复
- 在登录状态:
- use db_name
- source 备份文件
- 不登录状态:
- mysql -u用户名 -p密码 库名 <备份文件
MySQL优化
MySQL常用优化:
- 选择合适的存储引擎
- 越小的列会越快
- 使用 ENUM 而不是 VARCHAR
- 尽可能的使用 NOT NULL
- 把IP地址存成 UNSIGNED INT
- 永远为每张表设置一个ID
- 为搜索字段建索引
- 当只要一行数据时使用 LIMIT 1
- 避免 SELECT *
- 千万不要 ORDER BY RAND()
表和表结构优化
- 选择适合数据类型
- 更小通常更好更好,因为他们使用了更少的磁盘空间、内存、和CPU缓存.要确保不会低估需要保存的值,选择你人为不会超过范围的最小类型
- 数据类型越简单的越好,需要的CPU周期越少,比较整数的代价要小于字符串,以为字符串字符集和排序规则比整数更复杂.
- 避免NULL值,要尽量把字段设置为 NOT NULL,mysql难以优化引用了NULL值列的查询().
- 适合存储引擎,根据不同需求选择存储引擎,以下是常见数据类型的特点:
- MyISAM:
- 表级锁
- 不支持事务
- 占用磁盘少和能快速的全表扫描
- Memory:
- 表级锁
- 不支持动态行(varchar(500)会存为char(500))
- 重启后数据丢失
- InnoDB:
- 行级锁
- 支持事务
- 没有缓存的count(*) 值
- MyISAM:
- 合理的表结构
- 适度冗余
- 适当拆分:横向查分和纵向拆分
- 合理的索引设置.
- 避免在基数很小的列创建索引(提高索引选择性)
- 唯一字段使用唯一索引
- 需要排序的字段尽量使用整形
查询优化
- 只获取需要的字段(视情况而定)
- 减少查询(或链接数据库的)次数
- 把复杂的查询简化为多个简单的查询
- 高并发系统使用长连接
- 尽量避免向客户端返回大数据量,
- 使用批量插入节省交互
衡量查询操作开销的最简单指标
- 执行时间
- 检查的行数
- 返回的行数
Explain 定量分析
Explain 定量分析select查询语句和连接表,来调整sql语句的编写,优化查询
eg:<只有5条数据的表>
mysql> explain select id,goodsno,goodsname,price from goods where id =11;
+----+-------------+-------+------------+-------+---------------+---------+---------+-------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+-------+---------------+---------+---------+-------+------+----------+-------+
| 1 | SIMPLE | goods | NULL | const | PRIMARY | PRIMARY | 4 | const | 1 | 100 | NULL |
+----+-------------+-------+------------+-------+---------------+---------+---------+-------+------+----------+-------+
1 row in set, 1 warning (0.00 sec)
explain select id,goodsno,goodsname,price from goods where price between 1000 and 6000;
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
| 1 | SIMPLE | goods | NULL | ALL | NULL | NULL | NULL | NULL | 4 | 25 | Using where |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)
mysql> explain select * from brand where id in(select brandid from goods);
+----+--------------+-------------+------------+--------+---------------+---------+---------+---------------------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+--------------+-------------+------------+--------+---------------+---------+---------+---------------------+------+----------+-------+
| 1 | SIMPLE | <subquery2> | NULL | ALL | NULL | NULL | NULL | NULL | NULL | 100 | NULL |
| 1 | SIMPLE | brand | NULL | eq_ref | PRIMARY | PRIMARY | 2 | <subquery2>.brandid | 1 | 100 | NULL |
| 2 | MATERIALIZED | goods | NULL | ALL | NULL | NULL | NULL | NULL | 4 | 100 | NULL |
+----+--------------+-------------+------------+--------+---------------+---------+---------+---------------------+------+----------+-------+
3 rows in set
explain各列情况说明
- id:SELECT识别符.这是SELECT查询序列号.查询序号即为sql语句执行的顺序
- select_type:这列显示改行是简单的查询还是复杂的查询,simple 为简单查询,没有union和子查询.
- 如果查询内有复杂的子查询部分,最完成标记为primary 其余部分标记为以下集中类型
- Simple 简单查询,没有union和子查询.
- Subquery 包含在select列表中的子查询
- Derived 用来标识在form后的子查询
- Union UNION中的第二个或后面的SELECT语句, Result UNION的结果
- table:当前行查询所使用的表
- type:联接类型,从最好到最差依次为:null,const|system,eq_ref,ref,range,index,all
- NULL 这种访问方式意味这Mysql能在优化过程中分解查询语句,在执行缓解甚至不用在访问表或者索引
- Const,system 主键查询或者表内只有一行数据
- eq_ref 最多只返回一条符合条件的记录,可以在Mysql使用主键索引或者唯一索引是看到
- Ref 这是一种索引访问,他返回所有,有匹配索引值的行.
- Range 一个有限制的索引范围扫描
- Index 该联接类型与ALL相同,除了只有索引树被扫描.这通常比ALL快,因为索引文件通常比数据文件小. (也就是说虽然all和Index都是读全表,但index是从索引中读取的,而all是从硬盘中读的)
- All 全表扫描
- possible_keys:提示使用哪个索引会在该表中找到行,罗列出来的索引可能对后续优化没有
- keys:显示MySQL采用了那个索引来优化对该表的查询
- key_len:MySQL在索引里使用的字节数
- ref:ref列显示使用哪个列或常数与key一起从表中选择行
- rows:显示MySQL为找到所需的数据而读取的行数
- extra:一些不适合在其他列显示的额外信息,常见的值有: using index,Using where,Using temporary(查询使用了临时表),using filesort