目录
1. 初始化数据库
1.1 常见的数据库
- 关系型数据库, Oracle、MySQL、SQLServer、Access
- 非关系型数据库, MongoDB、Redis、Solr、ElasticSearch、Hive、HBase
1.2 Mysql数据库
- mysql服务端,它来处理具体数据维护,保存磁盘
- mysql客户端,CRUD新增,修改,删除,查询
1.3 Mysql数据库的安装
注意:配置完,mysql开始执行,最后一步出错有时仍可以使用,使用SQLyog工具测试,如不行,再执行安装程序,选择remove,删除,然后重新安装。同时注意必须是管理员权限。
MySQL客户端1:DOS窗口
mysql -uroot -proot
Mysql客户端2:可视化工具
1.4 SQL语句
sql定义:
结构化查询语言(Structured Query Language)简称SQL(发音:/ˈes kjuː ˈel/ "S-Q-L"),是一种特殊目的的编程语言,是一种数据库查询和程序设计语言,用于存取数据以及查询、更新和管理关系数据库系统;同时也是数据库脚本文件的扩展名。
SQL 是1986年10 月由美国国家标准局(ANSI)通过的数据库语言美国标准,接着,国际标准化组织(ISO)颁布了SQL正式国际标准。
分类:
DML(Data Manipulation Language)数据操纵语言
如:insert,delete,update,select(插入、删除、修改、检索)简称CRUD操新增Create、查询Retrieve、修改Update、删除Delete
DDL(Data Definition Language)数据库定义语言
如:create table之类
DCL(Data Control Language)数据库控制语言
如:grant、deny、revoke等,只有管理员才有相应的权限
DQL(Data Query Language)数据库查询语言
如: select 语法
注意:SQL不区分大小写
1.5 SQL命令
create database 库名 charset utf8;---------创建数据库
drop database 库名;------删除数据库
show databases;---查询所有数据库
show tables;---查看表
use 库名;---使用库
create table 表名(字段名称 字段类型(字段长度),字段2,字段3); primary key auto_increment------创建表
alter table 表名 add column 字段名称 字段类型(字段长度);-----修改表
drop table 表名;---删除表
desc 表名;---查看表结构
select * from 表名;-----查询表中的记录
insert into 表名 values(1,2,3,4);---新增表中的记录
update 表名 set 字段名=修改值 where 条件;----修改字段
select count(*) from 表名;--表内总记录数
delete from 表名 where 条件;---删除表中的某个记录
set names gbk;---解决中文乱码
Select * from 表名 order by tel desc;---按照tel排序
2. 数据类型
2.1 命名规则
字段名必须以字母开头,尽量不要使用拼音
长度不能超过30个字符(不同数据库,不同版本会有不同)
不能使用SQL的保留字,如where,order,group
只能使用如下字符az、AZ、0~9、$ 等
Oracle习惯全大写:USER_NAME,mysql习惯全小写:user_name
多个单词用下划线隔开,而非java语言的驼峰规则
2.2 字符
char长度固定,不足使用空格填充,最多容纳2000个字符,char(11)存储abc,占11位。查询速度极快但浪费空间
varchar变长字符串,最多容纳4000个字符,varchar(11)存储abc,只占3位。查询稍慢,但节省空间。Oracle为varchar2
大文本: 大量文字(不推荐使用,尽量使用varchar替代)
以utf8编码计算的话,一个汉字在u8下占3个字节
2.3 数字
- tinyint,int整数类型
- float,double小数类型
- numeric(5,2) decimal(5,2)—也可以表示小数,表示总共5位,其中可以有两位小数
- decimal和numeric表示精确的整数数字
2.4 日期
- date 包含年月日
- time时分秒
- datetime包含年月日和时分秒
- timestamp时间戳,不是日期,而是从1970年1月1日到指定日期的毫秒数
2.5 图片
- blob 二进制数据,可以存放图片、声音,容量4g。早期有这样的设计。但其缺点非常明显,数据库庞大,备份缓慢,这些内容去备份多份价值不大。同时数据库迁移时过大,迁移时间过久。所以目前主流都不会直接存储这样的数据,而只存储其访问路径,文件则存放在磁盘上。
3. 字段约束
3.1 主键约束 primary key
主键约束:如果为一个列添加了主键约束,那么这个列就是主键,主键的特点是唯一且不能为空。通常情况下,每张表都会有主键。
添加主键约束,例如将id设置为主键:
主键自增策略** **当主键为数值类型时,为了方便维护,可以设置主键自增策略(auto_increment),设置了主键自增策略后,数据库会在表中保存一个AUTO_INCREMENT变量值,初始值为1,当需要id值,不需要我们指定值,由数据库负责从AUTO_INCREMENT获取一个id值,作为主键值插入到表中。而且每次用完AUTO_INCREMENT值,都会自增1. AUTO_INCREMENT=1
create table abc(
id int primary key auto_increment
);
insert into abc values(null);
insert into abc values(null);
insert into abc values(null);
select * from abc;
3.2 非空约束 not null
非空约束:如果为一个列添加了非空约束,那么这个列的值就不能为空,但可以重复。
添加非空约束,例如为password添加非空约束:
create table user(
id int primary key auto_increment,
password varchar(50) not null
);
show tables;
insert into user values(null,null);//不符合非空约束
insert into user values(null,123;);//OK
3.3 唯一约束 unique
唯一约束:如果为一个列添加了唯一约束,那么这个列的值就必须是唯一的(即不能重复),但可以为空。
添加唯一约束,例如为username添加唯一约束及非空约束:
create table test(
id int primary key auto_increment,
username varchar(50) unique--唯一约束
);
show tables;
insert into test values(null,'lisi');
insert into test values(null,'lisi');--username的值要唯一,重复会报错的
select * from test;
3.4 外键约束 foreign key
CREATE TABLE tb_user_address (
user_id INT PRIMARY KEY NOT NULL,
address VARCHAR(200),
foreign key(user_id) REFERENCES tb_user(id)
);
DESC tb_user;
tb_user_address中user_id字段录入tb_user表不存在的主键值,将报错
3.5 检查约束 check
CREATE TABLE tb_user (
id INT PRIMARY KEY NOT NULL AUTO_INCREMENT, #自增主键
NAME VARCHAR(50) NOT NULL UNIQUE, #非空,唯一索引
sex CHAR(2) DEFAULT '男', #默认值
phone CHAR(18),
age INT,
CHECK (age>0 AND age<=200),
createdTime DATE DEFAULT NOW()
);
4. 基础函数
lower
SELECT 'ABC',LOWER('ABC') from dept; --数据转小写
upper
select upper(dname) from dept --数据转大写
length
select length(dname) from dept --数据的长度
substr
SELECT dname,SUBSTR(dname,1,3) FROM dept; --截取[1,3]
concat
select dname,concat(dname,'123') X from dept --拼接数据
replace
select dname,replace(dname,'a','666') X from dept --把a字符替换成666
ifnull
select ifnull(comm,10) comm from dept2 #判断,如果comm是null,用10替换
round & ceil & floor
round四舍五入,ceil向上取整,floor向下取整
–直接四舍五入取整
select comm,round(comm) from emp
–四舍五入并保留一位小数
select comm,round(comm,1) from emp
–ceil向上取整,floor向下取整
select comm,ceil(comm) ,floor(comm) from emp
uuid
SELECT UUID()
返回uuid:a08528ca-741c-11ea-a9a1-005056c00001
now
select now() -- 年与日 时分秒
select curdate() --年与日
select curtime() --时分秒
year & month & day
–hour()时 minute()分 second()秒
select now(),hour(now()),minute(now()),second(now()) from emp ;
–year()年 month()月 day()日
select now(),year(now()),month(now()),day(now()) from emp ;
转义字符
'作为sql语句符号,内容中出现单撇就会乱套,进行转义即可
select 'ab'cd' -- 单引号是一个SQL语句的特殊字符
select 'ab\'cd' --数据中有单引号时,用一个\转义变成普通字符
5. 条件查询
distinct
使用distinct关键字,去除重复的记录行
SELECT DISTINCT loc FROM dept;
where
注意:where中不能使用列别名!!
select * from emp where empno=100 --唯一条件
select * from emp where ename='tony' and deptno=2 --相当于两个条件的&关系
like
通配符%代表0到n个字符,通配符下划线_代表1个字符
select * from emp where ename like 'l%' --以l开头的
select * from emp where ename like '%a' --以a结束的
select * from emp where ename like '%a%' --中间包含a的
select * from emp where ename like 'l__' --l后面有两个字符的 _代表一个字符位置
null
select * from emp where mgr is null --过滤字段值为空的
select * from emp where mgr is not null --过滤字段值不为空的
limit
select * from emp limit 2 --列出前两条
select * from emp limit 1,2 --从第二条开始,展示2条记录
select * from emp limit 0,3 --从第一条开始,展示3条记录--前三条
limit
select * from emp limit 2 --列出前两条
select * from emp limit 1,2 --从第二条开始,展示2条记录
select * from emp limit 0,3 --从第一条开始,展示3条记录--前三条
6. 聚合函数 aggregation
count
select count(*) from emp --底层优化了
select count(1) from emp --效果和*一样
select count(comm) from emp --慢,只统计非NULL的
max / min
select max(sal) from emp --求字段的最大值
select max(sal) sal,max(comm) comm from emp
select min(sal) min from emp --获取最小值
select min(sal) min,max(sal) max from emp --最小值最大值
SELECT ename,MAX(sal) FROM emp group by ename --分组
sum / avg
select count(*) from emp --总记录数
select sum(sal) from emp --求和
select avg(sal) from emp --平均数
7. 分组Group
group by
SELECT deptno,MAX(sal),AVG(sal) FROM emp
GROUP BY deptno #按照deptno分组
SELECT job,MAX(sal),AVG(sal) FROM emp
GROUP BY job #按照job分组
SELECT deptno,job,MAX(sal),AVG(sal) FROM emp
GROUP BY deptno,job #deptno和job都满足的
having
select deptno, AVG(sal) from emp
group by deptno #按部门分组
having AVG(sal)<8000 #查询条件,类似where,但是group by只能配合having
#deptno出现的次数
SELECT deptno,COUNT(deptno) FROM emp
GROUP BY deptno #按deptno分组
HAVING COUNT(deptno)>1 #次数多的
8. 扩展
char和varchar有什么区别?
char为定长字符串,char(n),n最大为255
varchar为不定长字符串,varchar(n),n最大长度为65535
char(10)和varchar(10)存储abc,那它们有什么差别呢?
char保存10个字符,abc三个,其它会用空格补齐;而varchar只用abc三个位置。
datetime和timestamp有什么区别?
数据库字段提供对日期类型的支持,是所有数据类型中最麻烦的一个,慢慢使用就会体会出来。
date 是 年与日
time是 时分秒
datetime年月日时分秒,存储和显示是一样的
timestamp时间戳,存储的不是个日期,而是从1970年1月1日到指定日期的毫秒数
中文乱码
如果在dos命令下执行insert插入中文数据,数据又乱码,那现在sqlYog客户端执行下面命令:
set names gbk;
Mysql数据库默认字符集是lantin1,也就是以后网页中遇到的ISO8859-1,它是英文字符集,不支持存放中文。我们创建库时,可以指定字符集:
create database yhdb charset utf8;
主键、外键、唯一索引的区别?
- Primary Key 主键约束,自动创建唯一索引
- Foreign Key 外键约束,外键字段的内容是引用另一表的字段内容,不能瞎写
- Unique Index 唯一索引,唯一值但不是主键
drop、delete和truncate之间的区别?
drop删除库或者表,数据和结构定义
delete和truncate只是删除表的数据
delete可以指定where条件,删除满足条件的记录,tuncate删除所有记录
对于自增字段的表,delete不会自增值清零,而truncate是把表记录和定义都删除了,然后重建表的定义,所以自增主键会重头开始计数
9. 事务
事务定义:作为单个逻辑工作单元执行的一系列操作,要么完全地执行,要么完全地不执行。
事务的特性
一般来说,事务是必须满足4个条件(ACID):原子性(Atomicity,或称不可分割性)、一致性(Consistency)、隔离性(Isolation,又称独立性)、持久性(Durability)。
原子性:一个事务(transaction)中的所有操作,要么全部完成,要么全部不完成,不会结束在中间某个环节。事务在执行过程中如果发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。
一致性:在事务开始之前和事务结束以后,数据库的完整性没有被破坏。这表示写入的资料必须完全符合所有的预设规则,这包含资料的精确度、串联性以及后续数据库可以自发性地完成预定的工作。
隔离性:数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。
持久性:事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。
隔离级别
读未提交(Read uncommitted) 安全性最差,可能发生并发数据问题,性能最好
读提交(read committed) Oracle默认的隔离级别
可重复读(repeatable read)MySQL默认的隔离级别,安全性较好,性能一般
串行化(Serializable) 表级锁,读写都加锁,效率低下,安全性高,不能并发
查询Mysql的隔离级别
- 开启事务:start transaction;
- 结束事务:commit(提交事务)或rollback(回滚事务)
事务处理
在 MySQL 中只有使用了 Innodb 数据库引擎的数据库或表才支持事务
事务处理可以用来维护数据的完整性,保证成批的 SQL 语句要么全部执行,要么全部不执行
事务用来管理 insert、update、delete 语句,因为这些操作才会“破坏”数据,查询select语句是不会的
MySQL默认数据库的事务是开启的,执行SQL后自动提交。
MySQL的事务也可以改成手动提交,那就有两个步骤:先开启,写完SQL后,再手动提交。
10. 表关联
- 一对一 one to one QQ和QQ邮箱,员工和员工编号
- 一对多 one to many 最常见,部门和员工,用户和订单
- 多对一 many to one 一对多反过来,员工和部门,订单和用户
- 多对多 many to many 老师和学生,老师和课程
11. 多表联查
笛卡尔积 Cartesian product
SELECT * FROM emp
WHERE deptno = ( SELECT deptno FROM dept WHERE dname='research' )
连接查询 Join
- 内连接 inner join
- 左(外)连接 left join
- 右(外)连接 right join
SELECT d.dname,e.ename,e.job
FROM emp e INNER JOIN dept d
ON e.deptno=d.deptno
WHERE d.dname='research'
换成left join和right join,看看有什么不同呢?
子查询 subquery
返回结果为一个:
--列出tony所在部门的所有人员
select deptno from emp where ename='tony';
select * from emp where deptno = (select deptno from emp where ename='tony');
多行子查询
select * from emp where job in ('经理','员工');
select * from emp where job in (select distinct job from emp);
SQL的执行顺序
(1) FROM [left_table] 选择表
(2) ON <join_condition> 链接条件
(3) <join_type> JOIN <right_table> 链接
(4) WHERE <where_condition> 条件过滤
(5) GROUP BY <group_by_list> 分组
(6) AGG_FUNC(column or expression),... 聚合
(7) HAVING <having_condition> 分组过滤
(8) SELECT (9) DISTINCT column,... 选择字段、去重
(9) ORDER BY <order_by_list> 排序
(10) LIMIT count OFFSET count; 分页
12. 索引 index
索引是一种排好序的快速查找的数据结构,它帮助数据库高效的进行数据的检索。
分类:
- 单值索引:一个索引只包括一个列,一个表可以有多个列
- 唯一索引:索引列的值必须唯一,但允许有空值;主键会自动创建唯一索引
- 复合索引:一个索引同时包括多列
索引扫描类型:
ALL 全表扫描,没有优化,最慢的方式
index 索引全扫描,其次慢的方式
range 索引范围扫描,常用语<,<=,>=,between等操作
ref 使用非唯一索引扫描或唯一索引前缀扫描,返回单条记录,常出现在关联查询中
eq_ref 类似ref,区别在于使用的是唯一索引,使用主键的关联查询
const/system 单条记录,系统会把匹配行中的其他列作为常数处理,如主键或唯一索引查询,system是const的特殊情况
null MySQL不访问任何表或索引,直接返回结果
优点:
- 索引是数据库优化
- 表的主键会默认自动创建索引
- 每个字段都可以被索引
- 大量降低数据库的IO磁盘读写成本,极大提高了检索速度
- 索引事先对数据进行了排序,大大提高了查询效率
缺点:
索引本身也是一张表,该表保存了主键与索引字段,并指向实体表的记录,所以索引列也要占用空间
索引表中的内容,在业务表中都有,数据是重复的,空间是“浪费的”
虽然索引大大提高了查询的速度,但对数据的增、删、改的操作需要更新索引表信息,如果数据量非常巨大,更新效率就很慢,因为更新表时,MySQL不仅要保存数据,也要保存一下索引文件
随着业务的不断变化,之前建立的索引可能不能满足查询需求,需要消耗我们的时间去更新索引
13. 视图 View
create view 视图名 as SQL语句;
select * from 视图名;
#视图:就是一个特殊的表,缓存上次的查询结果
#好处是提高了SQL的复用率,坏处是占内存无法被优化
#1.创建视图
CREATE VIEW emp_view AS
SELECT * FROM emp WHERE ename LIKE '%a%' #模糊查询,名字里包含a的
#2.使用视图
SELECT * FROM emp_view
14. SQL优化
1. 查询SQL尽量不要使用select *,而是具体字段
2. 避免在where子句中使用or来连接条件
3. 使用varchar代替char
4. 尽量使用数值替代字符串类型
5. 查询尽量避免返回大量数据
6. 使用explain分析你SQL执行计划
7. 是否使用了索引及其扫描类型
索引注意事项
索引并不是越多越好,虽其提高了查询的效率,但却会降低插入和更新的效率
索引可以理解为一个就是一张表,其可以存储数据,其数据就要占空间
再者,索引表的一个特点,其数据是排序的,那排序要不要花时间呢?肯定要
insert或update时有可能会重建索引,如果数据量巨大,重建将进行记录的重新排序,所以建索引需要慎重考虑,视具体情况来定
一个表的索引数最好不要超过5个,若太多需要考虑一些索引是否有存在的必要
索引不适合建在有大量重复数据的字段上
where限定查询的数据
避免在where中对字段进行表达式操作
避免在where子句中使用!=或<>操作符
去重distinct过滤字段要少
where中使用默认值代替null
批量插入性能提升
批量删除优化
伪删除设计
这里的删除只是一个标识,并没有从数据库表中真正删除,可以作为历史记录备查
同时,一个大型系统中,表关系是非常复杂的,如电商系统中,商品作废了,但如果直接删除商品,其它商品详情,物流信息中可能都有其引用。
通过where state=1或者where state=2过滤掉数据,这样伪删除的数据用户就看不到了,从而不影响用户的使用
操作速度快,特别数据量很大情况下
数据库三范式
1NF的定义为:符合1NF的关系中的每个属性都不可再分
2NF在1NF的基础之上,消除了非主属性对于码的部分函数依赖,也就是说,表里的每个字段都要依赖于主键
第一步:找出数据表中所有的码。
第二步:根据第一步所得到的码,找出所有的主属性。
第三步:数据表中,除去所有的主属性,剩下的就都是非主属性了。
第四步:查看是否存在非主属性对码的部分函数依赖
3NF在2NF的基础之上,消除了非主属性对于码的传递函数依赖
就是指没个属性都跟主键有直接关系而不是间接关系
总结:三大范式只是一般设计数据库的基本理念,可以建立冗余较小、结构合理的数据库。如果有特殊情况,当然要特殊对待,数据库设计最重要的是看需求跟性能,需求>性能>表结构。所以不能一味的去追求范式建立数据库。