数据库相关知识点

体系结构图:

体系介绍:
Client Connectors
接入方。支持很多协议(JDBC、ODBC、.NET、PHP、Python、PERL、C 等)

Management Serveices & Utilities
系统管理和控制工具,mysqldump、 mysql复制集群、分区管理等

Connection Pool
连接池:管理缓冲用户连接、用户名、密码、权限校验、线程处理等需要缓存的需求

SQL Interface
SQL接口:接受用户的SQL命令,并且返回用户需要查询的结果

Parser
解析器,SQL命令传递到解析器的时候会被解析器验证和解析。解析器是由Lex和YACC实现的

Optimizer
查询优化器,SQL语句在查询之前会使用查询优化器对查询进行优化

Cache和Buffer(高速缓存区)
查询缓存,如果查询缓存有命中的查询结果,查询语句就可以直接去查询缓存中取数据

pluggable storage Engines
插件式存储引擎。存储引擎是MySql中具体的与文件打交道的子系统

File System
文件系统,数据、日志(redo,undo)、索引、错误日志、查询记录、慢查询等

数据库三大范式

第一范式:1NF 原子性,列或者字段不能再分,要求属性具有原子性,不可再分解;即是无重复的列。

1NF

属性不可再分,即表中的每个列都不可以再进行拆分。

如下学生信息表(student):

id、name(姓名)、sex_code(性别代号)、sex_desc(性别描述)、contact(联系方式)

primary key(id)

|----|------|----------|----------|-----------------------|
| id | name | sex_code | sex_desc | contact |
| 1 | 张三 | 0 | 男 | 17835201234_山西省运城市xx村 |
| 2 | 李四 | 0 | 男 | 17735204567_山西省吕梁市yy村 |
| 3 | 王五 | 1 | 女 | 18835207890_山西省太原市zz村 |

如果在查询学生表时经常用到学生的电话号,则应该将联系方式(contact)这一列分为电话号(phone)和地址(address)两列,这样才符合第一范式。

修改使表满足1NF后:

|----|------|----------|----------|-------------|-----------|
| id | name | sex_code | sex_desc | phone | address |
| 1 | 张三 | 0 | 男 | 17835201234 | 山西省运城市xx村 |
| 2 | 李四 | 0 | 男 | 17735204567 | 山西省吕梁市yy村 |
| 3 | 王五 | 1 | 女 | 18835207890 | 山西省太原市zz村 |

判断表是否符合第一范式,列是否可以再分,得看需求,如果将电话号和地址分开才能满足查询等需求时,那之前的表设计就是不满足1NF的,如果电话号和地址拼接作为一个字段也可以满足查询、存储等需求时,那它就满足1NF。

第二范式:2NF 唯一性,一张表只说一件事,是对记录的惟一性约束,要求记录有惟一标识,即是属性完全依赖于主键

2NF

第二范式需要确保数据库表中的每一列都和主键相关,而不能只与主键的某一部分相关(主要针对联合键)

如上图所示,同一个订单中可能包含不同的产品,所以主键必须是订单号和产品号联合组成

但是,产品数量、产品折扣、产品价格与"订单号"和"产品号"都相关,但是订单金额和订单时间仅与"订单号"相关,与"产品号"无关,

第三范式:3NF 直接性,数据不能存在传递关系,即每个属性都跟主键有直接关系,而不是间接关系。即是属性不依赖于其他非主属性。

3NF

比如在设计一个订单数据表时,可以将客户编号作为一个外键和订单表建立相应的关系,而不可以在订单表中添加关于客户其他信息(如姓名,电话等)的字段。如下图表就是一个满足第三范式的数据库表

这样在查询订单信息的时候,就可以使用客户编号来引用客户信息表中的信息,也不必在订单信息表中多次输入客户信息的内容,减少了数据臃肿

存储引擎

从数据库的体系结构当中,我们可以了解到**存储引擎是MySql中具体的与文件打交道的子系统。**根据不同业务场景,比如说:有的表简单,有的表复杂,有的表根本不用来存储任何长期的数据,有的表需要查询非常快。在我们实际的业务开发中,可能需要用到各种各样的表,不同的表也意味着存储不同类型的数据,数据的处理上也就会存在着差异。针对 MySQL 来说,它提供了很多类型的存储引擎来供我们选择,我们可以根据业务需求来选择不同的存储引擎,最大程度的发挥 MySQL 的强大之处。

1.MyISAM存储引擎

MyISAM 作为 MySQL 中 B+Tree 索引的另一种重要体现形式。

特点:

MyISAM 是非聚集索引;

MyISAM 有一个变量专门来保存整个表的行数,查询count很快(注意不能加任何 where 条件)

MyISAM 支持全文索引;

MyISAM 可以被压缩后进行查询操作,节省空间容量;

MyISAM 支持表级锁(表级锁是MySQL中锁定粒度最大的一种锁,表示对当前操作的整张表加锁),不支持行级锁;

MyISAM 中主键不是必须的;

MyISAM 文件存储方式为.frm文件存储表结构,.MYD文件存储数据内容,.MYI文件存储索引文件。

适用场景:

对事务的完整性没有要求,或以select、insert为主的应用基本都可以选用MYISAM。在Web、数据仓库中应用广泛。

2.InnoDB存储引擎

在 MySQL 5.5 及以后版本后,MySQL 选择使用 InnoDB为默认存储引擎。在创建数据库表时,不指定存储引擎时,使用的就是 InnoDB。如需使用其他存储引擎,可以手动来指定。

特点:

InnoDB 支持事务操作;(每一条SQL都默认封装成事务,自动提交,会影响速度)

InnoDB 支持外键;

InnoDB 是聚集索引(聚簇索引);

InnoDB 不保存表的总条数;

InnoDB 5.7版本之前不支持全文检索;

InnoDB 支持表级锁、行级锁,默认为行级锁;

InnoDB 表必须有主键(如果我们没有明确去指定创建主键索引。它会帮我们隐藏的生成一个 6 byte 的 int 型的索引作为主键索引);

InnoDB 文件存储方式为.frm文件存储表结构,ibd文件存储数据内容。

名词解释:

什么是聚集(簇)索引?

聚簇索引的特点是叶子节点包含了完整的记录行,而非聚簇索引的叶子节点只有所以字段和主键ID。

MySQL 索引采用 B+Tree(不熟悉?来跳转链接了解:MySQL 索引底层为什么选择B+Tree)。InnoDB 和 MyISAM 作为 MySQL 中 B+Tree 索引的两种重要体现形式。

InnoDB 推荐以主键作为索引来组织数据进行存储,它认为主键是一个非常重要的属性。InnoDB 表数据文件本身就是按B+Tree组织的一个索引结构,聚簇索引就是按照每张表的主键来构造一个B+树,叶子节点中存放的就是整张表的数据。

一般建表会用一个自增主键做聚簇索引,没有的话MySQL会默认创建,但是这个主键如果更改代价较高,故建表时要考虑自增ID不能频繁 update 这一点。

(估计你还看不懂,哈哈。那就看看这里你就懂了---->MySQL一张表,比如有id(主键),name,age等字段。我们可以建很多个索引,MySQL除了主键索引外,都是非聚簇索引。即只有我们创建的主键id索引,我们可以叫他id索引,它别名又叫做聚簇索引,(因为只有id索引,叶子节点包含了完整的记录行)理解成一个别名的即可。如果我们再创建一个name索引,它就叫做非聚簇索引,或者辅助索引。)【也可参考:MyISAM 和 InnoDB 的区别 文中介绍的聚簇索引】

我们日常工作中,根据实际情况自行添加的索引都是辅助索引,辅助索引就是一个为了需找主键索引的二级索引,现在找到主键索引再通过主键索引找数据;

MyISAM 和 InnoDB 的区别

区别:

1.InnoDB 支持事务,MyISAM 不支持。对于InnoDB每一条SQL语言都默认封装成事务,自动提交,这样会影响速度,所以最好把多条SQL语言放在begin和commit之间,组成一个事务;

2. InnoDB 支持外键,而 MyISAM 不支持。对一个包含外键的InnoDB表转为MYISAM会失败; (外键现在用的也不多,因为它关联性太强,如果要删除一个表,会因为有外键的关联而导致删除失败。通常是通过 table a = table b on a.id = b.id 这种两表关联的方式来间接替代外键作用 )

3.InnoDB是聚集索引,使用B+Tree作为索引结构,数据文件是和(主键)索引绑在一起的;MyISAM是非聚集索引,它也是使用B+Tree作为索引结构,但是索引和数据文件是分离的,索引保存的是数据文件的指针。

4.InnoDB 必须要有主键,MyISAM可以没有主键;InnoDB 如果我们没有明确去指定创建主键索引。它会帮我们隐藏的生成一个 6 byte 的 int 型的索引作为主键索引。

5.InnoDB辅助索引和主键索引之间存在层级关系;MyISAM辅助索引和主键索引则是平级关系。即:InnoDB 如果添加其他辅助索引,辅助索引查询就需要两次查询,先查询到主键,然后再通过主键查询到数据。因此,主键不应该过大,因为主键太大,其他索引也相应都会很大。

  1. InnoDB不保存表的具体行数,执行select count(*) from table时需要全表扫描。而MyISAM用一个变量保存了整个表的行数,执行上述语句时只需要读出该变量即可,速度很快(注意不能加有任何WHERE条件);

7. Innodb不支持全文索引,而MyISAM支持全文索引,在全文索引领域的查询效率上MyISAM速度更快高;(MySQL 5.7 版本以后,InnoDB也支持全文索引了)

8. InnoDB支持表级锁、行级锁,默认为行级锁;而 MyISAM 仅支持表级锁。InnoDB 的行锁是实现在索引上的,而不是锁在物理行上。如果访问未命中索引,也是无法使用行锁,将会退化为表锁

9. Innodb存储文件有frm、ibd,而Myisam是frm、MYD、MYI。【InnoDB 中,.frm文件:保存的是表结构定义描述文件;.ibd文件:保存的是employee表中的数据内容】;【MyISAM中,.frm文件:保存的是表结构定义描述文件,.MYD文件:保存的是数据内容,.MYI文件:保存的是索引内容】(好像是在MySQL 8.0中,.frm 文件已经不存在了,此处以MySQL5.7介绍)

参考:还不了解 MyISAM 和 InnoDB 的区别?看这里就够了_myisam和innodb的区别_扛麻袋的少年的博客-CSDN博客

数据库事务

一个或一组sql语句组成一个执行单元,这个执行单元要么全部执行,要么全部不执行。

事务特性

ACID

原子性:一个事务不可再分割,要么都执行要么都不执行

一致性:一个事务执行会使数据从一个一致状态切换到另外一个一致状态

隔离性:一个事务的执行不受其他事务的干扰

持久性:一个事务一旦提交,则会永久的改变数据库的数据.

事务隔离级别

  • 事务并发问题是如何产生的? - 当多个事务同时操作同一个数据库的相同数据时

    • 事务并发问题

      • 脏读:一个事务读取到了另外一个事务未提交的数据

      • 不可重复读:同一个事务中,多次读取到的数据不一致

      • 幻读:一个事务读取数据时,另外一个事务进行更新,导致第一个事务读取到了没有更新的数据

    • 处理事务并发问题,设置事务隔离级别

      • READ UNCOMMITTED

      • READ COMMITTED:可以避免脏读

      • REPEATABLE READ:可以避免脏读、不可重复读和一部分幻读

      • SERIALIZABLE:可以避免脏读、不可重复读和幻读

    • 注意:隔离级别从小到大安全性越来越高,但是效率越来越低

脏读 不可重复读 幻读
read uncommitted:读未提交
read committed:读已提交 ×
repeatable read:可重复读 × ×
serializable:串行化 × × ×

mysql中默认 第三个隔离级别 repeatable read

oracle中默认第二个隔离级别 read committed

查看隔离级别

select @@tx_isolation;

设置隔离级别

set session|global transaction isolation level 隔离级别;

sql 复制代码
SHOW VARIABLES LIKE 'autocommit';
SHOW ENGINES;

#1.演示事务的使用步骤

#开启事务
SET autocommit=0;
START TRANSACTION;
#编写一组事务的语句
UPDATE account SET balance = 1000 WHERE username='张无忌';
UPDATE account SET balance = 1000 WHERE username='赵敏';

#结束事务
ROLLBACK;
#commit;

SELECT * FROM account;

#2.演示事务对于delete和truncate的处理的区别

SET autocommit=0;
START TRANSACTION;

DELETE FROM account;
ROLLBACK;

#3.演示savepoint 的使用
SET autocommit=0;
START TRANSACTION;
DELETE FROM account WHERE id=25;
SAVEPOINT a;#设置保存点
DELETE FROM account WHERE id=28;
ROLLBACK TO a;#回滚到保存点

SELECT * FROM account;

spring 事务特性

spring 所有的事务管理策略类都继承org.springframework.transaction.PlatformTransactionManager 接口。

java 复制代码
public interface PlatformTransactionManager {
  TransactionStatus getTransaction(TransactionDefinition definition)
  throws TransactionException;
  void commit(TransactionStatus status) throws TransactionException;
  void rollback(TransactionStatus status) throws TransactionException;
}

索引

索引存储在内存中,为服务器存储引擎为了快速找到记录的一种数据结构。索引的主要作用是加快数据查找速度,提高数据库的性能。

优点:

创建唯一性索引,保证数据库表中每一行数据的唯一性

大大加快数据的检索速度,这也是创建索引的最主要的原因

加速表和表之间的连接,特别是在实现数据的参考完整性方面特别有意义。

在使用分组和排序子句进行数据检索时,同样可以显著减少查询中分组和排序的时间。

索引的分类(必会)

普通索引:最基本的索引,它没有任何限制。

唯一索引:与普通索引类似,不同的就是索引列的值必须唯一,但允许有空值。如果是组合索引,则列值的组合必须唯一。

主键索引:它是一种特殊的唯一索引,用于唯一标识数据表中的某一条记录,不允许有空值,一般用 primary key 来约束。

联合索引(又叫复合索引):多个字段上建立的索引,能够加速复合查询条件的检索。

全文索引:老版本 MySQL 自带的全文索引只能用于数据库引擎为 MyISAM 的数据表,新版本 MySQL 5.6 的 InnoDB 支持全文索引。默认 MySQL 不支持中文全文检索,可以通过扩展 MySQL,添加中文全文检索或为中文内容表提供一个对应的英文索引表的方式来支持中文。

索引的底层实现原理参考MySQL数据库------索引机制及其优化_mysql 索引优化机制_至,若春和景明的博客-CSDN博客

MySql优化

优化索引

索引设计原则

索引的设计需要遵循一些已有的原则, 这样便于提升索引的使用效率, 更高效的使用索引.

对查询频次较高, 且数据量比较大的表, 建立索引.

索引字段的选择, 最佳候选列应当从where子句的条件中提取, 如果where子句中的组合比较多, 那么应当挑选最常用, 过滤效果最好的列的组合.

使用唯一索引, 区分度越高, 使用索引的效率越高.

索引并非越多越好, 如果该表赠,删,改操作较多, 慎重选择建立索引, 过多索引会降低表维护效率.

使用短索引, 提高索引访问时的I/O效率, 因此也相应提升了Mysql查询效率.

如果where后有多个条件经常被用到, 建议建立符合 索引, 复合索引需要遵循最左前缀法则, N个列组合而成的复合索引, 相当于创建了N个索引.

复合索引命名规则 index_表名_列名1_列名2_列明3

比如:create index idx_seller_name_sta_addr on tb_seller(name, status, address)

避免索引失效

如果在查询的时候, 使用了复合索引, 要遵循最左前缀法则, 也就是查询从索引的最左列开始, 并且不能跳过索引中的列.

尽量不要在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索引而进行全表扫描

应尽量避免在 where 子句中使用 != 或 <> 操作符,否则将引擎放弃使用索引而进行全表扫描。

不做列运算where age + 1 = 10,任何对列的操作都将导致表扫描,它包括数据库教程函数.计算表达式等, 都会是索引失效.

查询 like,如果是 '%aaa' 也会造成索引失效.

应尽量避免在 where 子句中使用 or 来连接条件,如果一个字段有索引,一个字段没有索引,将导致引擎放弃使用索引而进行全表扫描

Sql语句调优

根据业务场景建立复合索引只查询业务需要的字段,如果这些字段被索引覆盖,将极大的提高查询效率.

多表连接的字段上需要建立索引,这样可以极大提高表连接的效率.

where条件字段上需要建立索引, 但Where条件上不要使用运算函数,以免索引失效.

排序字段上, 因为排序效率低, 添加索引能提高查询效率.

优化insert语句: 批量列插入数据要比单个列插入数据效率高.

优化order by语句: 在使用order by语句时, 不要使用select *, select 后面要查有索引的列, 如果一条sql语句中对多个列进行排序, 在业务允许情况下, 尽量同时用升序或同时用降序.

优化group by语句: 在我们对某一个字段进行分组的时候, Mysql默认就进行了排序, 但是排序并不是我们业务所需的, 额外的排序会降低效率. 所以在用的时候可以禁止排序, 使用order by null禁用.

select age, count(*) from emp group by age order by null

尽量避免子查询, 可以将子查询优化为join多表连接查询.

合理的数据库设计

根据数据库三范式来进行表结构的设计。设计表结构时,就需要考虑如何设计才能更有效的查询, 遵循数据库三范式:

第一范式:数据表中每个字段都必须是不可拆分的最小单元,也就是确保每一列的原子性;

第二范式:满足一范式后,表中每一列必须有唯一性,都必须依赖于主键;

第三范式:满足二范式后,表中的每一列只与主键直接相关而不是间接相关(外键也是直接相关),字段没有冗余。

注意:没有最好的设计,只有最合适的设计,所以不要过分注重理论。三范式可以作为一个基本依据,不要生搬硬套。有时候可以根据场景合理地反规范化:

A:保留冗余字段。当两个或多个表在查询中经常需要连接时,可以在其中一个表上增加若干冗余的字段,以 避免表之间的连接过于频繁,一般在冗余列的数据不经常变动的情况下使用。

B:增加派生列。派生列是由表中的其它多个列的计算所得,增加派生列可以减少统计运算,在数据汇总时可以大大缩短运算时间, 前提是这个列经常被用到, 这也就是反第三范式。

C:分割表。

数据表拆分:主要就是垂直拆分和水平拆分。

水平切分:将记录散列到不同的表中,各表的结构完全相同,每次从分表中查询, 提高效率。

垂直切分:将表中大字段单独拆分到另外一张表, 形成一对一的关系。

D: 字段设计

表的字段尽可能用NOT NULL

字段长度固定的表查询会更快

把数据库的大表按时间或一些标志分成小表

相关推荐
bug菌¹几秒前
滚雪球学Oracle[2.5讲]:数据库初始化配置
数据库·oracle·数据库初始化·初始化配置
一休哥助手7 分钟前
Redis 五种数据类型及底层数据结构详解
数据结构·数据库·redis
翔云12345615 分钟前
MVCC(多版本并发控制)
数据库·mysql
代码敲上天.32 分钟前
数据库语句优化
android·数据库·adb
盒马盒马1 小时前
Redis:zset类型
数据库·redis
静听山水1 小时前
mysql语句执行过程
数据库·mysql
虽千万人 吾往矣1 小时前
golang gorm
开发语言·数据库·后端·tcp/ip·golang
mariokkm2 小时前
Django一分钟:在Django中怎么存储树形结构的数据,DRF校验递归嵌套模型的替代方案
数据库·django·sqlite
Wang's Blog3 小时前
Redis: 集群环境搭建,集群状态检查,分析主从日志,查看集群信息
数据库·redis
容器( ु⁎ᴗ_ᴗ⁎)ु.。oO3 小时前
MySQL事务
数据库·mysql