数据库(Mysql5.7.29)

关系数据理论

问题的提出

将关系模式看做三个元组:R
R:关系名;U:一组属性;F:属性组U上的一组数据依赖。
当且仅当一个关系r满足F时,r称关系模式R的一个关系。
数据依赖:一个表内部属性与属性间的约束关系。其中最重要的是函数依赖(FD)与多值依赖(MVD)
数据冗余。浪费存储空间。
更新异常
插入异常。该插入的数据插不进去。
删除异常。不该删除的数据也删去了。

规范化

函数依赖

定义。设R(U)是一个属性集U上的关系模式,X和Y是U的子集。若对于R(U)的任意一个可能的关系r,r中不可能存在两个元组在X上的属性值相等,而在Y上的属性值不等,则称X函数确定YY函数依赖于X,记作X- >Y。
例:学号->姓名。

X- >Y,Y不包含X,X->Y是非平凡的函数依赖。如(学号,课程编号)->分数。

在关系模式R(U)中,如果X- >Y,并且对于X的任何一个真子集X’,X’不函数依赖于Y,称Y完全函数依赖于X[(学号,课程号)->成绩],若 X- >Y,但Y不完全函数依赖于X,则称Y部分函数依赖于X[(学号,课程号)->所在系]。
如:
数据库(Mysql5.7.29)_第1张图片

范式

1NF:如果一个关系模式R的所有属性都是不可分的基本数据项。

2NF:关系模式R∈1NF,且每一个非主属性都完全函数依赖于R的码,则R∈2NF。

数据库(Mysql5.7.29)_第2张图片
所在系,“宿舍楼”部分函数依赖于码。(不满足2NF)
解决:投影分解法。(满足2NF)
在这里插入图片描述
2NF存在问题:
插入异常:如:新成立一个系还未招收学生,则无法存入。
删除异常。
修改复杂:一个系更改宿舍,该系所有学生都要修改一遍。

原因:
“宿舍楼”传递函数依赖于“学号”,即:非主属性传递函数依赖码。

解决:投影分解法。
在这里插入图片描述
3NF:关系模式R∈1NF,若R中不存在这样的码X、属性组Y及非主属性Z (Z不属于Y),使得X- >Y, Y- >Z, Y- >X,成立,则称R∈3NF。


数据库(Mysql5.7.29)_第3张图片
候选码:(学号,课程)和(学号,导师),不存在非主属性对码的部分函数依赖和传递依赖。

BCNF。关系模式R∈1NF,如果对于R的每个函数依赖X- >Y,且X不包含Y时,X必含有码,那么R∈BCNF。(把三元联系尽量将为二元)。

事务

事务是访问并可能更新各种数据项的一个程序执行单元,也可以说是一组原子性的SQL查询。

案例
银行的数据库有两张表:支票(checking)表和储蓄(savings) 表。现在要从用户Jane的支票账户转移200美元到她的储蓄账户,需要至少三个步骤:
1.检查支票账户的余额高于200美元。
2.从支票账户余额中减200美元。
3.在储蓄账户余额中加200美元。
上述三个步骤的操作必须在一个事务中,任何一个步骤失败,则必须回滚所有的步骤。
START TRANSACTION语句开始一个事务,使用COMMIT提交事务将修改的数据持久保留,或使用ROLLBACK撤销所有的修改。事务SQL的样本如下:

START TRANSACTION;
SELECT balance FROM checking WHERE customer_id = 10233276;
UPDATE checking SET balance = balance - 200.00 WHERE customer_id = 10233276;
UPDATE savings SET balance = balance + 200.00 WHERE customer_id = 10233276;
COMMIT;

原子性(atomicity)。整个事务中的所有操作要么全部提交成功,要么全部失败回滚,对于一个事务来说,不可能只执行其中的一部分操作。

一致性 (consistency)。数据库总是从一个一致性的状态转换到另外一个一致性的状态。
在前面的例子中,即使在执行第三、四条语句之间时系统崩溃,支票账户中也不会损失200美元,因为事务最终没有提交,所以事务中所做的修改也不会保存到数据库中。

隔离性(isolation)。通常来说,一个事务所做的修改在最终提交以前,对其他事务是不可见的。
在前面的例子中,当执行完第三条语句、第四条语句还未开始时,此时有另外一个账户汇总程序开始运行,则其看到的支票账户的余额并没有被减去200美元。

持久性(durability)。一旦事务提交,则其所做的修改就会永久保存到数据库中。此时即使系统崩溃,修改的数据也不会丢失。
持久性是个有点模糊的概念,因为实际上持久性也分很多不同的级别。有些持久性策略能够提供非常强的安全保障,而有些则未必。而且不可能有能做到100%的持久性保证的策略。

隔离级别

-- 设置隔离级别(只改变当前会话)
SET SESSION TRANSACTION ISOLATION LEVEL 隔离级别;

READ UNCOMMITTED (未提交读)。在这个隔离级别,事务中的修改,即使没有提交,对其他事务也都是可见的。事务可以读取未提交的数据,也被称为脏读(Dirty Read)。从性能上来说,不会比其他的级别好太多,但却缺乏其他级别的很多好处,在实际应用中很少使用。

READ COMMITTED (提交读)。大多数数据库系统的默认隔离级别(MySQL不是)。满足隔离性的简单定义:一个事务从开始直到提交之前,所做的修改对其他事务都是不可见的。也叫不可重复读(nonrepeatableread),因为两次执行同样的查询,可能会得到不样的结果。

REPEATABLE READ (可重复读)。解决了脏读的问题,MySQL默认事务隔离级别。保证了在同一个事务中多次读取同样记录的结果是一致的。但无法解决幻读(Phantom Read) 的问题。
幻读,指事务a在读取某个范围内的记录时,事务b在该范围内插入了新的记录,事务a再次读取该范围的记录时,会产生幻行(Phantom Row),即事务b插入的新记录。
InnoDB和XtraDB存储引擎通过多版本并发控制(MVCC,Multiversion Concurrency Control)解决了幻读的问题。

SERIALIZABLE (可串行化)。最高的隔离级别。通过强制事务串行执行,避免了幻读。SERIALIZABLE 会在读取的每一行数据上都加锁,可能导致大量的超时和锁争用的问题。实际应用中很少使用。只有在需要确保数据的一致性且可以接受没有并发的情况下,才考虑使用。
数据库(Mysql5.7.29)_第4张图片
自动提交(AUTOCOMMIT)
MySQL默认采用自动提交(AUTOCOMMIT) 模式。即如果不是显式地开始一个事务,则每个查询都被当作一个事务执行提交操作。
在当前连接中,可以通过设置AUTOCOMMIT变量来启用或者禁用自动提交模式:

-- 查看自动提交
SHOW VARIABLES LIKE 'AUTOCONMIT';
-- 设置(1启用,0禁用)
SET AUTOCOMMIT = 1;

数据库(Mysql5.7.29)_第5张图片

索引介绍

建立索引

索引是一种排好序的快速查找的数据结构

CREATE INDEX 索引名 ON 表名(属性);
CREATE UNIQUE INDEX 索引名 ON 表名(属性);

-- 删除索引
DROP INDEX 索引名 ON 表名;

B+

多分平衡树,存取效率高;既能随机查找、又能顺序查找;增删改操作,保持平衡。
数据库(Mysql5.7.29)_第6张图片

HASH

数据库(Mysql5.7.29)_第7张图片
选择Hash存取方法的规则
如果一个关系的属性主要出现在等值连接条件中或主要出现在等值比较选择条件中,而且满足下列两个条件之一:
关系的大小可预知,而且不变;
关系的大小动态改变,但所选用的数据库管理系统提供了动态Hash存取方法。


存储引擎简介

-- 现在已提供存储引擎:
show engines;
-- 当前默认的存储引擎:
show variables like '%storage_engine%';

数据库(Mysql5.7.29)_第8张图片

索引优化

常见的Join查询

读取顺序

FROM <left table>
ON <join_condition>
<join_type> JOIN <right_table>
WHERE <where_condition>
GROUP BY <group_by_list>
HAVING <having_condition>
SELECT
DISTINCT <select_list>
ORDER BY <order_by_condition>
LIMIT <limit_nunber>

七种连接
数据库(Mysql5.7.29)_第9张图片

-- 1、
SELECT <select_list> 
FROM table1 a INNER JOIN table2 b
ON a.key=b.key;
-- 2、
SELECT <select_list> 
FROM table1 a LEFT JOIN table2 b
ON a.key=b.key;

数据库(Mysql5.7.29)_第10张图片

-- 3、
SELECT <select_list> 
FROM table1 a LEFT JOIN table2 b
ON a.key=b.key
WHERE b.key IS NULL;
-- 4、
SELECT <select_list> 
FROM table1 a RIGHT JOIN table2 b
ON a.key=b.key;
-- 5、
SELECT <select_list> 
FROM table1 a RIGHT JOIN table2 b
ON a.key=b.key
WHERE b.key IS NULL;

数据库(Mysql5.7.29)_第11张图片

-- 6、
SELECT <select_list> 
FROM table1 a OUTER JOIN table2 b
ON a.key=b.key;
--7、
SELECT <select_list> 
FROM table1 a OUTER JOIN table2 b
ON a.key=b.key
WHERE a.key IS NULL
OR
b.key IS NULL;

-- musql 不支持全外连接
SELECT * FROM table1 a LEFT JOIN table2 b on a.key = b.key
UNION
SELECT * FROM table1 a RIGHT table2 b on a.key = b.key;

SELECT * FROM table1 a LEFT JOIN table2 b on a.key = b.key
WHERE b.key is NULL
UNION
SELECT * FROM table1 a RIGHT table2 b on a.key = b.key
WHERE a.ket IS NULL;


数据库(Mysql5.7.29)_第12张图片
数据库(Mysql5.7.29)_第13张图片

索引

索引是一种排好序的快速查找的数据结构。系引本身也很大,不可能全部存储在内存中,因此索引往往以索引文件的形式存储的磁盘上。
优势:提高数据检索的效率,降低数据库的IO成本;降低数据排序的成本,降低了CPU的消耗。

分类

单值索引。一个索引只包含单个列。
唯一索引。索引列的值唯一 ,允许空值。
复合索引。一个索引包含多个列。

基本语法

CREATE INDEX 索引名 ON 表名(属性);
CREATE UNIQUE INDEX 索引名 ON 表名(属性);
ALTER 表名 ADD [UNIQUE ] INDEX [索引名] ON (属性);

-- 删除索引
DROP INDEX 索引名 ON 表名;

-- 查看
SHOW INDEX FROM table_name;

B+索引

数据库(Mysql5.7.29)_第14张图片

需求

需要创建索情况
主键自动建立唯一索引;
频繁作为查询条件的字段应该创建索引;
查询中与其它表关联的字段,外键关系建立索引;
频繁更新的字段不适合创建索引;
Where条件里用不到的字段不创建索引;
查询中统计或者分组字段;
查询中排序的字段,排序字段若通过索引去访问提高排序速度。
需要创建索情况
经常增删改的表;
数据重复且分布平均的表字段。

性能分析

MYSQL瓶颈
CPU:CPU在饱和的时候一般发生在数据装入内存或从磁盘上读取数据时候
IO:磁盘I/0瓶颈发生在装入数据远大于内存容量的时候
服务器硬件的性能瓶颈:top,free,iostat和vmstat来查看系统的性能状态。

Explain。执行计划

EXPLAIN关键字可以模拟优化器执行SQL查询语句,从而知道MySQL是如何处理SQL语句的。分析查询语句或是表结构的性能瓶颈。

Explain+SQL语句

作用

表的读取顺序
数据读取操作的操作类型
哪些索引可以使用
哪些索引被实际使用
表之间的引用
每张表有多少行被优化器查询

使用

在这里插入图片描述
id字段
数据库(Mysql5.7.29)_第15张图片
id相同,读取顺序由上至下。
数据库(Mysql5.7.29)_第16张图片
id不同,id大先读取。
数据库(Mysql5.7.29)_第17张图片
id大先读取; id相同,读取顺序由上至下。

  • select_type字段
    查询的类型,主要是用于区别普通查询、联合查询、子查询等的复杂查询
select_type
SIMPLE(简单的查询,语句中不含子查询或者UNION)
PRIMARY(查询中包含复杂的子部分,最外层的表标记为PRIMARY)
SUBQUERY(SELECT或WHERE列表中包含了子查询,子查询中的表标记)
DERIUED(在FROM列表中包含的子查询标记为DERIVED,MySQL会递归执行这些子查询,把结果放在临时表。)
UNION(若第二个SELECT出现在UNION之后,则第二个SELECT最外层表标记;若UNION包含在FROM子句的子查询中,外层SELECT将被标记为:DERIVED)
UNION RESULT(从UNION表获取结果的SELECT)
  • partitions
    代表分区表中的命中情况,非分区表,该项为null。

  • typt
    访问类型
    从好到坏(常见):system > const > eq_ref > ref > range > index > ALL
    一般来说,至少达到range级别, 最好能达到ref。

    1. system:表只有一行记录(等于系统表),是const类型的特列,平时不会出现。
    2. const:表示通过索引一次就找到了,const用于比较primary key或者unique索引。只匹配一 行数据,所以很快如将主键置于where列表中,MySQL 就能将该查询转换为一个常量。
    3. eq_ref:唯一性索引扫描,对于每个索引键,表中只有一条记录与之匹配。常见于主键或唯一索引扫描。
    4. ref :非唯一性索引扫描,返回匹配某个单独值的所有行。本质上也是一种索引访问,它返回所有匹配某个单独值的行,然而,它可能会找到多个符合条件的行,所以他应该属于查找和扫描的混合体。
    5. range :检索给定范围,使用一个索引来选择行。key 列显示使用了哪个索引一般是在where语句中出现了between、<、>、in等的查询这种范围扫描索引扫描。
    6. index :与ALL区别为index类型只遍历索引树。通常比ALL快。
    7. ALL:全表扫描。
  • possible_ keys
    显示可能应用在这张表中的索引,一个或多个查询涉及到的字段上若存在索引,则该索引将被列出,但不一定被查询实际使用。

  • key
    实际使用的索引。如果为NULL,则没有使用索引。
    查询中若使用了覆盖索引,则该索引仅出现在key列表中

  • key_len
    表示索引中使用的字节数,可通过该列计算查询中使用的索引的长度。在不损失精确性的情况下,长度越短越好key_len显示的值为索引字段的最大可能长度,并非实际使用长度,即key_len是 根据表定义计算而得,不是通过表内检索出的。

  • ref
    显示索引的哪一列被使用了, 如果可能的话,是一个常数。哪些列或常量被用于查找索引列上的值

  • rows
    根据表统计信息及索引选用情况,大致估算出找到所需的记录所需要读取的行数。

  • Extra
    包含重要的额外信息。

    1. Using filesort。说明mysq|会对数据使用一个外部的索引排序,而不是按照表内的索引顺序进行读取。MySQL中无法利用索引完成的排序操作称为“文件排序"。(最左匹配原则)
    2. . Using temporary。使了用临时表保存中间结果,MySQL在对查询结果排序时使用临时表。常见于排序orderby和分组查询groupby。
    3. USING index。表示相应的select操作中使用了覆盖索引(Covering Index),避免访问了表的数据行,效率不错!如果同时出现using where,表明索引被用来执行索引键值的查找;如果没有同时出现usingwhere,表明索引用来读取数据而非执行查找动作。覆盖索引:理解方式一:就是select的数据列只用从索引中就能够取得,不必读取数据行,MySQL可以利用索引返回select列表中的字段,而不必根据索引再次读取数据文件,换句话说查询列要被所建的索引覆盖。
    4. Using where。使用了where。
    5. using join buffer。使用了连接缓存。
    6. impossible where。where子句的值总是false,不能用来获取任何元组。
    7. select tables optimized away。
    8. distinct。

索引优化

索引分析

单表。
双表。左(右)连接,加右(左)表索引。
三表。类似于双表。

尽可能减少Join语句中的NestedLoop的循环总次数;“永远用小结果集驱动大的结果集”。
优先优化NestedLoop的内层循;
保证Join语句中被驱动表上Join条件字段已经被索引;
当无法保证被驱动表的Jgin条件字段被索引且内存资源充足的前提下,不要太吝惜JoinBuffer的设置;

索引失效

  1. 全值匹配
  2. 最佳左前缀法则(索引了多列,指的是查询从索引的最左前列开始并且不跳过索引中的列。)
  3. 不在索引列上做任何操作(计算、函数、(自动or手动)类型转换),会导致索引失效而转向全表扫描。
  4. 不能使用索引中范围条件右边的列(范围以后全失效)。
  5. 尽量使用覆盖索引(只访问索引的查询(索引列和查询列一致)),减少select*。
  6. mysql在使用不等于(!=或者<>)的时候无法使用索引会导致全表扫描。
  7. is null,is not null无法使用索引。
  8. like以通配符开头(’%abc…’)mysq|索引失效会变成全表扫描的操作(利用覆盖索引解决,即查询字段建立了索引)。
  9. 字符串不加单引号索引失效(类型转换)。
  10. 少用or,用它来连接时会索引失效。

查询截取分析

查询优化

小表驱动大表
数据库(Mysql5.7.29)_第18张图片

order by 关键字

ORDER BY子句,尽量使用Index方式排序,避免使用FileSort方式排序。
尽可能在索引列上完成排序操作,遵照索引建的最佳左前缀。
数据库(Mysql5.7.29)_第19张图片

order by 关键字

groupby实质是先排序后进行分组,遵照索引建的最佳左前缀.
当无法使用索引列,增大max_length_for _sort_data 参数的设置+增大sort_buffer_size参数的设置。
where高于having,能写在where限定的条件就不要去having限定了。

慢查询日志

MySQL的慢查询日志是MySQL提供的一种日志记录,用来记录在MySQL中响应时间超过阈值的语句,具体指运行时间超过long_query_time值的SQL,则会被记录到慢查询日志中。
long_query_time的默认值为10, 意思是运行10秒以上的语句。

默认情况下,MySQL数据库没有开启慢查询日志,一般不建议启动该参数, 因为开启慢查询日志会或多或少带来一定的性能影响。慢查询日志支持将日志记录写入文件。

-- 查看
SHOW VARIABLES LIKE '%slow_query_log%';
-- 开启(关闭0)
set global slow_query_log=1;
-- 默认时间查看
SHOW VARIABLES LIKE 'long_query_time%';
-- 修改时间(从新连接可看到变化)
set global long_query_time=3;
-- 查看慢sql
show global status like '%Slow_queries%';

set global slow_query_log=1开启对当前数据库生效,MySQl重启后失效。

更改配置文件(永久生效)

slow_query_log=1;
slow_query_log_file=/var/ib/mysql/filename.log
long_query_ime=3;
log_output=FILE

mysqldumpslow。日志分析工具
如:得到返回记录集最多的10个SQL
mysqldumpslow -s r -t 10 /var/ib/mysql/atguigu-slow.log

数据库(Mysql5.7.29)_第20张图片

show Profile

是mysq|提供可以用来分析当前会话中语句执行的资源消耗情况。可以用于SQL的调优的测量。
默认情况下,参数处于开启状态,并保存最近15次的运行结果。

-- 查看开关状态
Show variables like 'profiling';

-- 查看sql
show profiles;

出现如下数据项(性能下降):
converting HEAP to MyISAM 查询结果太大,内存都不够用了往磁盘上搬了。
Creating tmp table 创建临时表
Copying to tmp table on disk 把内存中临时表复制到磁盘。
locked

锁是计算机协调多个进程或线程并发访问某一资源的机制。
锁的分类
从对数据操作的类型(读\写)
从对数据操作的粒度分:表锁(偏读)、行锁(偏写)。

-- 加锁
lock table 表名 read(write),[表名2 read(write)];
-- 查看表的锁信息 
show open tables;
-- 解锁
unlock tables;

表锁

偏向MyISAM存储引擎,开销小,加锁快;无死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低。

MyISAM在执行查询语句(SELECT)前,会自动给涉及的所有表加读锁,在执行增删改操作前,会自动给涉及的表加写锁。

结论:
对MyISAM表进行操作:
1、对MyISAM表的读操作(加读锁),不会阻塞其他进程对同一表的读请求,但会阻塞对同一表的写请求。只有当读锁释放后,
才会执行其它进程的写操作。
2、对MyISAM表的写操作(加写锁),会阻塞其他进程对同一表的读和写操作,只有当写锁释放后,才会执行其它进程的读写操作。
即。读锁会阻塞写,但是不会堵塞读。而写锁则会把读和写都堵塞。

行锁

偏向InnoDB存储引擎,开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高。
InnoDB与MyISAM的最大不同有两点:1、支持事务(TRANSACTION);2、采用了行级锁

-- 查看数据库事务隔离级别
show variables like 'tx_isolation';

无索引(索引失效)行锁升级为表锁

间隙锁。用范围条件而不是相等条件检索数据,并请求共享或排他锁时,InnoDB会给 符合条件的已有数据记录的索引项加锁;对于键值在条件范围内但并不存在的记录,叫做“间隙(GAP)”,这种锁机制就是所谓的间隙锁(Next-Key锁) 。
[危害]
当锁定一一个范围键值之后,即使某些不存在的键值也会被无辜的锁定,而造成在锁定的时候无
法插入锁定键值范围内的任何数据。

查看行锁情况

show status like 'innodb_row_lock%'; 

参数说明
Innodb_row_lock_current_waits:当前正在等待锁定的数量;
Innodb_row_lock_time:从系统启动到现在锁定总时间长度;
Innodb_row_lock_time_avg:每次等待所花平均时间;
Innodb_row_lock_time_max:从系统启动到现在等待最常的一次所花的时间;
Innodb_row_lock_waits:系统启动后到现在总共等待的次数。

你可能感兴趣的:(数据库)