DDL语言又称为数据定义语言,主要的操作有create、drop、alter、show。
创建一个student数据库
create database if not exists student;
查询该数据库的创建信息
show create database student;
删除数据库
drop database if exists student;
在对数据库中的表进行一系列操作时首先需要指定一个库
use student;
创建表
create table 表名(字段名 字段类型 字段约束 COMMENT "注释");
在student这个库下创建一个grade表
create table grade (id char(20) primary key COMMENT "学生学号",
name varchar(20) not null COMMENT "学生姓名",
age int not null COMMENT "学生年龄",
grade int not null COMMENT "学生成绩");
查询grade表的字段信息
desc grade;
查询grade表的创建信息
show create table grade;
字段约束有五种:
删除grade这个表
drop table grade;
修改表的字段类型:修改grade表的年龄字段类型为char(10)
alter table grade modify age char(10);
修改表的字段名称:修改grade表的id字段为sid字段
alter table grade change id sid char(20);
给grade表添加字段id_card
alter table grade add id_card char(18) unique;
指定字段的添加位置:将card字段添加到name字段的后面
alter table grade add card char(18) unique after name;
删除grade表中的card字段
alter table grade drop card;
修改grade表为information表
alter table grade rename information;
DML又称为数据操作语言,主要操作有insert、delete、update、select。
向grade表中添加一行数据
insert into grade values("001","zhangli","18",98);
给grade表的指定字段插入数据
insert into grade (sid,name,age,grade) values("002","lili","19",97);
给grade表中一次性插入多行数据
insert into grade values("003","manman","18",87),
("004","keke","18",95),
("005","dada","20",76);
将grade表中学号为004的学生的姓名修改为zhangsan
update grade set name="zhangsan" where id="004";
查询grade表中的所有数据
select * from grade;
查询grade表中成绩大于95的学生的信息
select * from grade where grade>95;
去重查询:查询grade表中不同的年龄
select distinct age from grade;
按升序查询grade表中的学生学号和姓名
select id,name from grade order by grade asc;
按降序查询grade表中的学生学号和姓名
select id,name from grade order by grade desc;
删除grade表中学号为002的这一行数据
delete from grade where id="002";
删除grade表中的所有数据
delete from grade;
分组查询:按找年龄对grade表中的学生分组,查询他们的总分
select age,SUM(grade) from grade group by age;
等值查询:查询grade表和stu表中id相等的id。
select grade.id,stu.id from grade,stu where grade.id=stu.id;
求grade表中平均分大于80的学生的平均成绩(当有聚合函数为条件时,条件关键词为having而不是where)
select id,avg(grade) from grade having avg(grade)>80 group by id;
查询grade表和result的所有信息(包含重复的信息)
select * from grade
union all
select *from result;
查询grade表和result的所有信息(不包含重复的信息)
select * from grade
union
select * from result;
在grade表中查询姓李的学生的所有信息
select * from grade where name like "李%";
DCL又称为数据控制语言
grant
给用户授权
revoke
代表回收权限
自主权限管理:管理员可自由分配权限
强制权限管理:权限是固定的,拥有一定等级就拥有相应权限。
存储引擎就是mysql上的一个驱动程序,此部分介绍四种存储引擎:
(1)MyISAM
不支持外键,不支持事务,支持全文索引,特点是表锁设计,对于一些在线分析处理操作速度快。
其索引是由B+树实现的,文件组成是由 myd 存放数据的 ,由myi存放索引的。
(2)InnoDB
支持事务,支持外键,不支持全文索引。
主要是面向在线事务处理方面的应用,特点是行锁设计。
Innodb采用聚集索引的方式。没有主键,没有唯一键,为每一行生产一个6字节的行id,作为主键。索引也是由B+树实现的。
(3)Memory
将数据放在内存中,如果数据库重启或者宕机,表数据就会丢失。
Memory存储引擎非常适合存储一些临时表,默认的是哈希索引,不是B+树索引,varchar()默认是按照char()存储的,浪费内存。
不支持text和BLOB类型。如果数据中有text和BLOB类型,数据库会把这些数字转换到磁盘上。
(4)Archive
只支持INSERT和SELECT操作,使用压缩算法将数据进行压缩后存储,压缩比例一般是1:10,主要提供插入和压缩功能。
简单的来说,索引是一种数据结构,它的目的是为了提高查询数据的效率。
索引就相当于一本书的目录,有了这个目录,我们在书中要查找的内容就会容易很多,否则如果书本内容较多想要查找自己要找的内容无异于大海捞针。
索引分为聚簇索引和非聚簇索引两种,聚簇索引是按照数据存放的物理位置为顺序的,而非聚簇索引就不一样了;聚簇索引能提高多行检索的速度,而非聚簇索引对于单行的检索很快。
MySQL索引的类型:
MYSQL索引的缺点:
虽然索引大大提高了查询速度,同时却会降低更新表的速度,如对表进行INSERT、UPDATE和DELETE。
因为更新表时,MySQL不仅要保存数据,还要保存一下索引文件。建立索引会占用磁盘空间的索引文件。
一般情况这个问题不太严重,但如果在一个大表上创建了多种组合索引,索引文件的会膨胀很快。
索引只是提高效率的一个因素,如果MySQL有大数据量的表,就需要花时间研究建立最优秀的索引,或优化查询语句。
MYSQL索引的优化:
1.何时使用聚集索引或非聚集索引?
只要列中包含有NULL值都将不会被包含在索引中,复合索引中只要有一列含有NULL值,那么这一列对于此复合索引就是无效的。所以我们在数据库设计时不要让字段的默认值为NULL。
3.使用短索引
对串列进行索引,如果可能应该指定一个前缀长度。例如,如果有一个CHAR(255)的列,如果在前10个或20个字符内,多数值是唯一的,那么就不要对整个列进行索引。短索引不仅可以提高查询速度而且可以节省磁盘空间和I/O操作。
4.索引列排序
MySQL查询只使用一个索引,因此如果where子句中已经使用了索引的话,那么order by中的列是不会使用索引的。因此数据库默认排序可以符合要求的情况下不要使用排序操作;尽量不要包含多个列的排序,如果需要最好给这些列创建复合索引。
5.like语句操作
一般情况下不鼓励使用like操作,如果非使用不可,如何使用也是一个问题。like “%aaa%” 不会使用索引而like “aaa%”可以使用索引。
6.不要在列上进行运算
例如:select * from users where YEAR(adddate)<2007,将在每个行上进行运算,这将导致索引失效而进行全表扫描。
事务是一组sql语句的集合,事务有四个特性ACID
A原子性:一个事务的执行被视为一个不可分割的最小单元。事务里面的操作,要么全部成功执行,要么全部失败回滚,不可以只执行其中的一部分。
C一致性:一个事务的执行不应该破坏数据库的完整性约束。
I隔离性:通常来说,事务之间的行为不应该互相影响。然而实际情况中,事务相互影响的程度受到隔离级别的影响。
D持久性:事务提交之后,需要将提交的事务持久化到磁盘。即使系统崩溃,提交的数据也不应该丢失。
事务不隔离会产生什么问题
1)第一类丢失更新:在没有事务隔离的情况下,两个事务都同时更新一行数据,但是第二个事务却中途失败退出, 导致对数据的两个修改都失效了。
例如:
张三的工资为5000,事务A中获取工资为5000,事务B获取工资为5000,汇入100,并提交数据库,工资变为5100,
随后
事务A发生异常,回滚了,恢复张三的工资为5000,这样就导致事务B的更新丢失了。
2)脏读:脏读就是指当一个事务正在访问数据,并且对数据进行了修改,而这种修改还没有提交到数据库中,这时,另外一个事务也访问这个数据,然后使用了这个数据。
例如:
张三的工资为5000,事务A中把他的工资改为8000,但事务A尚未提交。
与此同时,
事务B正在读取张三的工资,读取到张三的工资为8000。
随后,
事务A发生异常,而回滚了事务。张三的工资又回滚为5000。
最后,
事务B读取到的张三工资为8000的数据即为脏数据,事务B做了一次脏读。
3)不可重复读:是指在一个事务内,多次读同一数据。在这个事务还没有结束时,另外一个事务也访问该同一数据。那么,在第一个事务中的两次读数据之间,由于第二个事务的修改,那么第一个事务两次读到的的数据可能是不一样的。这样就发生了在一个事务内两次读到的数据是不一样的,因此称为是不可重复读。
例如:
在事务A中,读取到张三的工资为5000,操作没有完成,事务还没提交。
与此同时,
事务B把张三的工资改为8000,并提交了事务。
随后,
在事务A中,再次读取张三的工资,此时工资变为8000。在一个事务中前后两次读取的结果并不致,导致了不可重复读。
4)第二类丢失更新:不可重复读的特例。有两个并发事务同时读取同一行数据,然后其中一个对它进行修改提交,而另一个也进行了修改提交。这就会造成第一次写操作失效。
例如:
在事务A中,读取到张三的存款为5000,操作没有完成,事务还没提交。
与此同时,
事务B,存储1000,把张三的存款改为6000,并提交了事务。
随后,
在事务A中,存储500,把张三的存款改为5500,并提交了事务,这样事务A的更新覆盖了事务B的更新。
5)幻读:是指当事务不是独立执行时发生的一种现象,例如第一个事务对一个表中的数据进行了修改,这种修改涉及到表中的全部数据行。同时,第二个事务也修改这个表中的数据,这种修改是向表中插入一行新数据。那么,以后就会发生操作第一个事务的用户发现表中还有没有修改的数据行,就好象发生了幻觉一样。
例如:
目前工资为5000的员工有10人,事务A读取所有工资为5000的人数为10人。
此时,
事务B插入一条工资也为5000的记录。
这是,事务A再次读取工资为5000的员工,记录为11人。此时产生了幻读。
四种隔离级别:
1.READ UNCOMMITTED(未提交读):在RU的隔离级别下,事务A对数据做的修改,即使没有提交,对于事务B来说也是可见的,这种问题叫脏读。这是隔离程度较低的一种隔离级别,在实际运用中会引起很多问题,因此一般不常用。
2.READ COMMITTED(提交读):在RC的隔离级别下,不会出现脏读的问题。事务A对数据做的修改,提交之后会对事务B可见,举例,事务B开启时读到数据1,接下来事务A开启,把这个数据改成2,提交,B再次读取这个数据,会读到最新的数据2。在RC的隔离级别下,会出现不可重复读的问题。这个隔离级别是许多数据库的默认隔离级别。
3.REPEATABLE READ(可重复读):在RR的隔离级别下,不会出现不可重复读的问题。事务A对数据做的修改,提交之后,对于先于事务A开启的事务是不可见的。举例,事务B开启时读到数据1,接下来事务A开启,把这个数据改成2,提交,B再次读取这个数据,仍然只能读到1。在RR的隔离级别下,会出现幻读的问题。幻读的意思是,当某个事务在读取某个范围内的值的时候,另外一个事务在这个范围内插入了新记录,那么之前的事务再次读取这个范围的值,会读取到新插入的数据。Mysql默认的隔离级别是RR,然而mysql的innoDB引擎间隙锁成功解决了幻读的问题。
4.SERIALIZABLE(可串行化):可串行化是最高的隔离级别。这种隔离级别强制要求所有事物串行执行,在这种隔离级别下,读取的每行数据都加锁,会导致大量的锁征用问题,性能最差。
事务的实现是基于数据库的存储引擎。不同的存储引擎对事务的支持程度不一样。mysql中支持事务的存储引擎有innoDB和NDB。innoDB是mysql默认的存储引擎,默认的隔离级别是RR,并且在RR的隔离级别下更进一步,通过多版本并发控制(MVCC,Multiversion Concurrency Control )解决不可重复读问题,加上间隙锁(也就是并发控制)解决幻读问题。因此innoDB的RR隔离级别其实实现了串行化级别的效果,而且保留了比较好的并发性能。
事务的隔离性是通过锁实现,而事务的原子性、一致性和持久性则是通过事务日志实现。说到事务日志,不得不说的就是redo和undo。
1.redo log
在innoDB的存储引擎中,事务日志通过重做(redo)日志和innoDB存储引擎的日志缓冲(InnoDB Log Buffer)实现。事务开启时,事务中的操作,都会先写入存储引擎的日志缓冲中,在事务提交之前,这些缓冲的日志都需要提前刷新到磁盘上持久化,这就是DBA们口中常说的“日志先行”(Write-Ahead Logging)。当事务提交之后,在Buffer Pool中映射的数据文件才会慢慢刷新到磁盘。此时如果数据库崩溃或者宕机,那么当系统重启进行恢复时,就可以根据redo log中记录的日志,把数据库恢复到崩溃前的一个状态。未完成的事务,可以继续提交,也可以选择回滚,这基于恢复的策略而定。
在系统启动的时候,就已经为redo log分配了一块连续的存储空间,以顺序追加的方式记录Redo Log,通过顺序IO来改善性能。所有的事务共享redo log的存储空间,它们的Redo Log按语句的执行顺序,依次交替的记录在一起。
2.undo log
undo log主要为事务的回滚服务。在事务执行的过程中,除了记录redo log,还会记录一定量的undo log。undo log记录了数据在每个操作前的状态,如果事务执行过程中需要回滚,就可以根据undo log进行回滚操作。单个事务的回滚,只会回滚当前事务做的操作,并不会影响到其他的事务做的操作。
共享锁和排他锁
MYSQL中的共享锁也叫做读锁和写锁。
表锁和行锁
悲观锁和乐观锁
-悲观锁:
乐观锁:
死锁
多数情况下,可以认为如果一个资源被锁定,它总会在以后某个时间被释放。而死锁发生在当多个进程访问同一数据库时,其中每个进程拥有的锁都是其他进程所需的,由此造成每个进程都无法继续下去。简单的说,进程A等待进程B释放他的资源,B又等待A释放他的资源,这样就互相等待就形成死锁。
虽然进程在运行过程中,可能发生死锁,但死锁的发生也必须具备一定的条件,死锁的发生必须具备以下四个必要条件:
最大限度降低死锁的方法:
创建触发器
CREATE TRIGGER trigger_name trigger_time trigger_event
ON tbl_name FOR EACH ROW trigger_stmt;
trigger_event可以是下述值之一:
注意,trigger_event与以表操作方式激活触发程序的SQL语句并不很类似。
例如,关于INSERT的BEFORE触发程序不仅能被INSERT语句激活,也能被LOAD DATA语句激活。
创建一个单执行语句的触发器
CREATE TABLE account(acct_num INT ,amount DECIMAL(10,2));
CREATE TRIGGER ins_sum BEFORE INSERT ON account
FOR EACH ROW SET @SUM=@SUM+new.amount;
首先创建一个account表,表中有两个字段,分别为:acct_num字段(定义为int类型),amount字段(定义成浮点类型);其次创建一个名为ins_sum的触发器,触发的条件是向数据表account插入数据之前,对新插入的amount字段值进行求和计算。
创建有多个执行语句的触发器
CREATE TRIGGER testref BEFORE INSERT ON test1
FOR EACH ROW BEGIN
INSERT INTO test2 SET a2 = NEW.a1;
DELETE FROM test3 WHERE a3 = NEW.a1;
UPDATE test4 SET b4 = b4 + 1 WHERE a4 = NEW.a1;
END
查看触发器
show triggers;
删除触发器
drop trigger trigger_name;
总结:
对于相同的表,相同的事件只能创建一个触发器,比如对表account创建了BEFORE INSERT触发器
那么如果对表account再次创建一个BEFORE INSERT触发器,MYSQL就会报错,此时,只可以在表account上
创建AFTER INSERT或者BEFORE UPDATE类型的触发器
存储过程
存储过程是一组可编程的函数,是为了完成特定功能的SQL语句集,经编译创建并保存在数据库中,用户可通过指定存储过程的名字并给定参数(需要时)来调用执行。
存储过程的优点: