赞
踩
第一范式(1NF)的要求确保每个列都是原子的,不可再分。换句话说,每个列中的数据不能是多个值或多个数据项的集合
第二范式(2NF)在满足第一范式的基础上,确保每个非主键列完全依赖于整个主键而不是部分主键。
举例:考虑一个存储图书订单的表格,其中包含订单ID、图书ID、图书名称和图书作者。如果我们将订单ID和图书ID作为联合主键,那么图书名称和图书作者只依赖于图书ID,而不是整个联合主键。为了符合第二范式,应该将图书名称和图书作者移到一个单独的表格中,并使用图书ID作为主键。
在该项目中,我负责员工登录和人脸考勤功能的开发和优化。以下是我在SQL语句优化方面所采取的措施:
么?
Mysql 默认的事务隔离级别是可重复读(Repeatable Read)
幻读与新增或删除操作有关,涉及到数据范围的变化。
不可重复读与更新操作有关,涉及到同一数据的多次读取时的数据变化
一般情况下,我们创建的表类型是InnoDB。
不重启MySQL,如果新增一条记录,id是8;
重启,ID是6;因为InnoDB表只把自增主键的最大ID记录在内存中,如果重启,已删除的最大ID会丢失。
如果表类型是MyISAM,重启之后,最大ID也不会丢失,ID是8;
⑴ 原子性(Atomicity)
原子性是指事务包含的所有操作要么全部成功,要么全部失败回滚,这和前面两篇博客介绍事务的功能是一样的概念,因此事务的操作如果成功就必须要完全应用到数据库,如果操作失败则不能对数据库有任何影响。
⑵ 一致性(Consistency)
一致性是指事务必须使数据库从一个一致性状态变换到另一个一致性状态,也就是说一个事务执行之前和执行之后都必须处于一致性状态。
拿转账来说,假设用户A和用户B两者的钱加起来一共是5000,那么不管A和B之间如何转账,转几次账,事务结束后两个用户的钱相加起来应该还得是5000,这就是事务的一致性。
⑶ 隔离性(Isolation)
隔离性是当多个用户并发访问数据库时,比如操作同一张表时,数据库为每一个用户开启的事务,不能被其他事务的操作所干扰,多个并发事务之间要相互隔离。
⑷ 持久性(Durability)
持久性是指一个事务一旦被提交了,那么对数据库中的数据的改变就是永久性的,即便是在数据库系统遇到故障的情况下也不会丢失提交事务的操作。
char的长度是固定的,varchar的长度的可变的;
char占用的空间比varchar大,但是char的效率比varchar的效率高;
(1)内存中占有的字节数不同
单精度浮点数在内存中占有4个字节;
双精度浮点数在内存中占有8个字节;
(2)有效数字位数不同
单精度浮点数有效数字8位;
双精度浮点数有效数字16位;
(3)在程序中处理速度不同
一般来说,CPU处理单精度浮点数的速度比双精度浮点数的速度快
如果不声明,默认小数是double类型,如果想用float,要进行强转;
常见错误:
1.float f = 1.3;会编译报错,正确的写法是float f = (float)1.3;或者float a = 1.3f;(f或F都可以不区分大小写)
2.java中3*0.1==0.3将会返回什么?true还是false?
答:返回false,因为浮点数不能完全精确的表示出来,一般会损失精度;
解决方案:
double a = 3 * 0.1;
double b = 0.3;
double epsilon = 1e-10; // 定义一个很小的误差范围
boolean result = Math.abs(a - b) < epsilon;
System.out.println(result); // 输出true
3.java中float f = 3.4;是否正确?
答:不正确。因为3.4是双精度浮点数,将双精度赋给单精度属于向下转型,会造成精度损失,因此需要强制类型转换float=(float)3.4;或者写成float f = 3.4f;
主键约束:在表的定义中,将主键列指定为主键,并对其应用主键约束。主键约束要求主键列的值是唯一且不为空的。当尝试插入或更新数据时,数据库会检查主键的唯一性,并阻止插入重复的主键值。
唯一索引:数据库会为主键列创建唯一索引。唯一索引是一种数据结构,它确保索引列的值是唯一的。当插入或更新数据时,数据库会检查唯一索引,如果发现重复的主键值,则拒绝插入或更新操作
自增主键:在许多情况下,数据库使用自增主键来保证主键的唯一性。自增主键是指主键列的值是自动递增生成的。数据库会自动为每个新插入的行分配一个唯一的主键值,确保不会出现重复的主键。
数据库设计时就要考虑效率和优化问题
设计合理的表关联与约束
选择合适的主键生成策略
数据库视图是数据库中的虚拟表格或虚拟查询结果集,它是基于一个或多个数据库表的查询定义而创建的。
存储过程是一个预编译的SQL语句,优点是允许模块化的设计,就是说只需要创建一次,以后在该程序中就可以调用多次。如果某次操作需要执行多次SQL,使用存储过程比单纯SQL语句执行要快。
1)like 以%开头,索引无效;当like前缀没有%,后缀有%时,索引有效;
2)or 语句前后没有同时使用索引。当 or 左右查询字段只有一个是索引,该索引失效,只有左右查询字段均为索引时,才会生效;
3)在索引列上使用 IS NULL 或 IS NOT NULL操作。最好给列设置默认值。
4)对索引字段进行计算操作、字段上使用函数。
1、查询重复的单个字段(group by)
select 重复字段A, count() from 表 group by 重复字段A having count() > 1
2、查询重复的多个字段(group by)
select 重复字段A, 重复字段B, count() from 表 group by 重复字段A, 重复字段B having count() > 1
唯一索引(Unique Index):唯一索引要求被索引的列的值在整个表中是唯一的。它可以确保被索引的列不包含重复的值,并提供了数据的唯一性约束。唯一索引可以加速查找和避免重复数据的插入。
主键索引(Primary Key Index):主键索引是一种特殊的唯一索引,它将表中的主键列与索引关联。主键索引要求主键列的值在整个表中是唯一的,且不允许为空。主键索引可以提供快速的主键查找和对表的高效访问。
非唯一索引(Non-Unique Index):非唯一索引允许被索引的列包含重复的值。它可以加速查找和范围查询,但允许重复值的存在。非唯一索引适用于经常进行查找和排序的列。
聚集索引(Clustered Index):聚集索引决定了表中数据的物理存储顺序。一个表只能有一个聚集索引,它通常与主键或唯一索引关联。聚集索引可以加速基于索引列的查找和范围查询。
辅助索引(Secondary Index):辅助索引(也称为非聚集索引)是基于非主键列创建的索引。它可以加速非主键列的查找和范围查询。表可以有多个辅助索引。
全文索引(Full-Text Index):全文索引用于对文本字段进行全文搜索。它可以提供高效的文本搜索和匹配功能,支持关键字搜索和相关性排序。
区分度不高的字段不适合做索引,因为索引页是需要有开销的,需要存储的,不过这类字段可以做联合索引的一部分。
内连接,显示两个表中有联系的所有数据;
左链接,以左表为参照,显示所有数据,右表中没有则以null显示
右链接,以右表为参照显示数据,,左表中没有则以null显示**
1)基于内存;
2)单线程减少上下文切换,同时保证原子性;
3)IO多路复用;
4)高级数据结构(如 SDS、Hash以及跳表等)。
基于内存:Redis是基于内存的,内存的读写速度非常快;
上下文切换:单线程避免了不必要的上下文切换和竞争条件;
IO多路复用:底层采用NIO(非阻塞IO),NIO采用IO多路复用技术,一个线程通过多路复用器处理多个连接
数据库:Redis是一款基于键值对的、线程安全的NoSQL数据库;
内存读写性能:它在内存中读写性能非常高,每秒可以处理超过百万次的读写操作。
服务端线程安全,客户端线程不安全:Redis服务端是线程安全的,永远只有主线程一个线程进行读写,不需要任何的同步机制。Redis客户端层面线程不安全,要引入原子指令(例如INCR是给数值原子性加1)、分布式锁、lua脚本保证Redis的原子操作。
CPU不是瓶颈:Redis在内存中读写性能非常高,CPU不是Redis的瓶颈,无需使用多线程。
担心加锁影响性能:多线程情况下,想实现线程安全必须加锁,加锁将极大地影响性能。
内存:因为读写在内存中进行,内存大小会影响Redis性能。可以通过加内存、读写分离优化性能。
网络带宽:网络 IO是Redis最大瓶颈,也就是客户端和服务端之间的网络传输延迟。Redis6.0引入了网络IO多线程模型,提高了性能瓶颈。
Redis主要提供了5种数据结构:字符串(string)、哈希(hash)、列表(list)、集合(set)、有序集合(zset)。
Redis还提供了Bitmap、HyperLogLog、Geo类型,但这些类型都是基于上述核心数据类型实现的。5.0版本中,Redis新增加了Streams数据类型,它是一个功能强大的、支持多播的、可持久化的消息队列。
string可以存储字符串、数字和二进制数据,除了值可以是String以外,所有的键也可以是string,string最大可以存储大小为2M的数据。
list保证数据线性有序且元素可重复,它支持lpush、blpush、rpop、brpop等操作,可以当作简单的消息队列使用,一个list最多可以存储2^32-1个元素
hash的值本身也是一个键值对结构,最多能存储2^32-1个元素。
set是无序不可重复的,它支持多个set求交集、并集、差集,适合实现共同关注之类的需求,一个set最多可以存储2^32-1个元素
zset是有序不可重复的,它通过给每个元素设置一个分数来作为排序的依据,一个zset最多可以存储2^32-1个元素。
set与zset
的区别为有序无序、底层存储结构、zset底层使用不使用红黑树
不完全满足ACID特性:Redis只满足隔离性和持久性,不满足原子性和一致性。
原子性:事务的所有操作,要么全部成功,要么全部失败。Redis不满足原子性,单个 Redis 命令的执行是原子性的,但事务失败后无法回滚。
一致性:事务前后,数据库的约束没有被破坏,保持前后一致。Redis连约束这个概念都没有。
隔离性:操作同一资源的并发事务之间相互隔离,不会互相干扰。Redis满足隔离性,因为redis server是单线程的,串行化执行事务,肯定是满足隔离性的。
持久性:事务的结果最终一定会持久化到数据库,宕机等故障也无法影响。Redis在开启aof并指定立刻持久化命令时,满足持久性。rdb模式会丢失部分数据,不满足持久性。
缓存穿透:查询数据不存在
1)缓存空值
2)key 值校验,如布隆筛选器 ref 分布式布隆过滤器(Bloom Filter)详解(初版)
缓存击穿:缓存过期,伴随大量对该 key 的请求
1)互斥锁
2)热点数据永不过期
3)熔断降级
缓存雪崩:同一时间大批量的 key 过期
1)热点数据不过期
2)随机分散过期时间
Redis 通过主从加集群架构,实现读写分离,主节点负责写,并将数据同步给其他从节点,从节点负责读,从而实现高并发。
答案很简单,因为 Redis 是单线程的,所以 Redis 提供的 API 也是原子操作。
但我们业务中常常有先 get 后 set 的业务常见,在并发下会导致数据不一致的情况。
如何解决
1)客户端加锁;
2)使用 Lua 脚本实现 CAS 操作。
先删缓存后写 DB
产生脏数据的概率较大(若出现脏数据,则意味着再不更新的情况下,查询得到的数据均为旧的数据)。
比如两个并发操作,一个是更新操作,另一个是查询操作,更新操作删除缓存后,查询操作没有命中缓存,先把老数据读出来后放到缓存中,然后更新操作更新了数据库。于是,在缓存中的数据还是老的数据,导致缓存中的数据是脏的,而且还一直这样脏下去了。
先写 DB 再删缓存
产生脏数据的概率较小,但是会出现一致性的问题;若更新操作的时候,同时进行查询操作并命中,则查询得到的数据是旧的数据。但是不会影响后面的查询。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。