前言:以下相关内容多为图片,参考链接、附上少量文字解释,以便整理脉络,以作复习巩固之用。若需详细了解,请进入原博主链接。如有错误,敬请指出,谢谢。
一、如何设计一个关系型数据库
1、存储管理:数据逻辑关系转换成物理存储关系
一次性的读取多行,以提升IO的效能,减少IO
2、缓存机制:优化执行效率
把取出来的数据块放进缓存里,下次需要的时候直接从内存返回,而不用发生IO
3、SQL解析:解析sql语句
将SQL缓存到缓存里直接解析
4、日志管理:SQL操作需要记录下来,方便数据库的主从同步或者灾难恢复,因此需要日志管理对操作进行记录,如binlog的记录方式。
5、权限划分:多用户管理
提供给用户管理数据的私密空间,权限划分是DBA做的
6、容灾机制:灾难恢复
数据库挂了如何恢复,恢复到什么程度。
7、索引和锁:优化数据查询效率的索引模块和使得数据库支持并发操作的锁模块
提升查询数据的速度以及让数据库支持并发
二、索引模块
关注:主外键、唯一键约束,mysql两种引擎InnoDB、MyISAM
2.1、为什么要使用索引
1、快速查询数据:最简单的方式实现数据查询,即全表扫描,将整张表的数据全部或者分批次加载到内存中。大数据不适用。
2、很多情况下都要避免全表扫描情况的发生,所以数据库引入更高效的机制,即索引。
3、关键信息和查找信息的方式组成索引,通过索引可以大幅提升查询速度。
2.2、什么样的信息能成为索引
主键、唯一键、普通键
注:目的是把记录限定在一定查找范围内的字段
2.3、 索引的数据结构
MySQL数据库索引是通过B+Tree实现
1、生成索引,建立二叉查找树进行二分查找、O(logn)、恶化就不好。或变体等如平衡二叉树、红黑树
2、生成索引,建立B Tree结构进行查找。
3、生成索引,建立B+Tree结构进行查找。
4、生成索引,建立Hash结构进行查找。
注意:树太深,那么IO次数太多,限制查询效率
2.4、 优化索引
参考链接:[平衡二叉树、B树、B+树、B*树 理解其中一种你就都明白了]
关注:用的多的B+树
二叉查找树、平衡二叉树、红黑树
1、影响程序运行速度的瓶颈是IO。
2、如果假定索引块在磁盘中,找索引会先发生一次IO,将数据读入内存中,之后再发生IO继续查找,直到找到。
3、检索深度每增加1,就发生一次IO。平衡二叉树、红黑树等每个节点只能有两个孩子。
4、为了组织起数据块,树的深度很深,IO的次数也会很多,检索性能没法满足优化查询需求。
办法:降低查询的时间复杂度,又降低IO的次数,要让树每个节点能承受的数据多一些
B树,即平衡多路查找树
m阶B树特征:m阶数是一个节点的子节点数目的最大值。
1)根节点至少包括两个孩子。
2)树中每个叶子节点最多含有m个孩子(m>=2)。即>=2 且<=m
3)除根节点和叶节点外,每个节点至少有ceil(m/2)个孩子。ceil向上取整。即>=[m/2]
4)所有叶子节点位于同一层。
5)假设每个非终端节点中包含有n个关键字信息,其中。//不补充了
查找效率和二叉查找树一样,为O(logn)。
B树通过合并、分裂、上移、下移节点保持特征,使树比二叉树矮,数据不断变动后不会变成线性的。
利用B+树
卫星数据: 指索引元素所指向的数据记录,比如数据库中的某一行。
在B-树中,无论非终端结点还是叶子结点都带有卫星数据;
在B+树中只有叶子结点带有卫星数据,其余非终端结点仅仅是索引,没有任何数据关联。
B+树是B树的变体,其定义基本与B树相同,除了:
1)非叶子节点的子树指针与关键字个数相同。(B+树能存储更多的关键字)
2)非叶子节点的子树指针P[i],指向关键值的子树。
3)非叶子节点仅用来索引,数据都保存在叶子节点中。(B+树所有的检索都是从根部开始,检索到叶子节点结束,非叶子节点仅存储索引不存储数据,能存储更多的数据。B+树相对B树更矮。B树的搜索可能在任何一个非叶子节点就终结掉了。)
4)所有叶子节点均有一个链指针指向下一个叶子节点并按大小顺序链接。(支持范围统计,即定位到某个叶子节点便可以从该叶子节点开始横向跨子树统计。)
B+树更适合用来做存储索引,考点
1)B+树的磁盘读取代价更低
(B+树内部结构没有指向关键字具体信息的指针,不存放数据,只存放索引信息。
内部节点相对B树更小。
如果把所有内部节点的关键字存放在同一盘块中,盘块能容纳的关键字数量也越多,一次性读入内存查找的关键字也就越多,相对来说IO读写次数低)。
2)B+树的查询效率更加稳定
(内部节点不是指向文件内容的节点,只是叶子节点中关键字的索引,任何节点的查找必须有一条从叶子节点到根节点的路,所有关键字查询的长度相同,每个数据的查询时间相同,O(logn))。
3)B+树更有利于对数据库的扫描
(B+树只需要遍历叶子节点就可以解决对全部数据的扫描)。
利用Hash
根据Hash函数的运算只需1次定位便能找到需要查询数据所在的头。
Hash索引的查询效率理论上高于B+树索引。
缺点:
1)仅仅能满足“=”,“IN”,不能使用查询范围。
(Hash索引比较的是进行Hash运算后的Hash值,只能用于等值的过滤,不能用于基于范围的查询,因为经过相应的Hash算法处理过的Hash值的大小关系不能保证和Hash运算前的完全一样。)
2)无法被用来避免数据的排序操作。
3)不能利用部分索引键查询。
(对于组合索引,Hash索引在计算Hash值的时候是组合键,将键组合合并后在一起计算Hash值,而不是单独计算Hash值。通过组合索引的前一个或几个索引键进行查询时Hash索引也无法被利用。B+树支持利用组合索引中的部分索引。)
4)不能避免表扫描。
(Hash索引是将索引键通过Hash运算后将运算结果的Hash值和所对应的行指针存放在一个Backet中,不同的索引键具有相同的Hash值,所以取出满足某个Hash键值的数据也无法从Hash索引中直接完成查询,还是需要访问Backet中的数据进行比较。)
5)遇到大量Hash值相等的情况性能并不一定会比B树索引高。
BitMap位图索引
当表中的某个字段只有几种值的时候,在该字段上实现高效统计用位图索引是最佳的选择。
目前很少数据库支持位图索引,已知比较主流的是Oracle。
缺点:
1、锁的密度非常大,当尝试新增或修改数据时,与它在同一个位图的数据操作都会被锁住。
2、因为某行所在的位置顺序会因为数据的添加或者删除而发生改变。不适合高并发的联机事务处理系统,即常见的OLTP系统。
3、而适合并发较少,统计数据较多的OLAP系统。
2.5、 密集索引和稀疏索引的区别
注意:这个知识点有点深
1、密集索引文件中的每个搜索码值都对应一个索引值。
(叶子节点不仅保存键值,还保存了位于同一行记录里的其他列的信息。密集索引决定了表的物理排列顺序,一个表只能有一个物理排列顺序,所以一个表只能创建一个密集索引。)
2、稀疏索引文件只为索引码的某些值建立索引项。
(叶子节点仅保存键位信息和该行数据的地址,有的稀疏索引仅保存键位信息及其主键。定位到叶子节点仍需要地址或主键信息进一步定位到数据。)
MySQL常见的两种的存储引擎:
MyISAM:主键索引、唯一键索引、普通索引其索引均属于稀疏索引
InnoDB:必须有且仅有一个密集索引,密集索引的选取规则如下:
1)若一个主键被定义,则该主键作为密集索引。
2)如果没有主键被定义,该表的第一个唯一非空索引则作为密集索引。
3)若不满足以上条件,innodb内部会生成一个隐藏主键(密集索引)。
4)非主键索引存储相关键位和其对应的主键值,包含两次查找。
(非主键索引即稀疏索引的叶子节点不存储行数据的物理地址,而是存储的该行的主键值,
所以非主键索引包含两次查找,一次查找次级索引自身,再查找主键。)
InnoDB的主键索引和对应的数据是保存在同一个文件、MyISAM的索引和数据是分开存储的
1、InnoDB使用密集索引,将主键组织到一棵B+树中,行数据就存储在叶子节点上。
因为InnoDB的主键索引和对应的数据是保存在同一个文件,检索时在加载叶子节点的数据进入内存时,也加载了对应的数据。
若对稀疏索引进行条件筛选,首先在稀疏索引的B+树中检索该键,获取到主键信息。
然后利用主键在密集索引B+树中再执行一遍检索操作,最终到达叶子节点,获取整行数据。
2、MyISAM均为稀疏索引,稀疏索引的两棵B+树节点结构完全一致,只是存储的内容不一样。
主键索引B+树存储主键,辅助键索引B+树存储辅助键,表数据存储在独立的地方,索引和数据是分开存储的。
两棵B+树的叶子节点都使用地址指向真正的表数据。
对于表数据来说,两个键没有任何差别。通过辅助键检索无需访问主键的索引树。
2.6、 索引模块衍生出来的问题(以MySQL为例)
如何定位并优化慢查询SQL
注意:这个需要经验,不要瞎编,承认只是简单了解就行
1、根据日志定位慢查询sql
慢日志是记录执行的比较慢的SQL
通过慢日志捕获慢sql,进而分析sql为什么慢,然后对它进行调优。
2、使用explain等工具分析SQL
explain关键字放在select查询语句的前面,用于描述MySQL如何执行查询操作,以及MySQL成功返回结果集需要执行的行数。
explain可以分析select语句,知道查询效率低下的原因,从而改进查询。
explain关键字字段:type、extra
3、修改SQL或尽快让SQL走索引
只有DML数据操纵语言(增删改)才会进慢查询语句中,DDL数据定义语言不会进入慢SQL 。
(DQL 数据查询语言 select
DML 数据操纵语言 insert、update、delete
DDL 数据定义语言 crete、drop
DCL 数据控制语言 grant、revoke)
index表示走了索引,all表示全表查询
注:Using temporary会出现在group by情况下
联合索引的最左匹配原则的成因
联合索引:由多列组成的索引
最左匹配原则:
假设有两列A、B,对A设置联合索引(联合键),即将A和B都设置为索引,顺序是A、B。
1、在where语句中调用where A=? and B=?,会走这个索引;
2、 调用where A=?也会走这个索引;
3、 调用where B=?就不走这个索引了。
1、最左匹配非常重要的原则,MySQL会一直向右匹配(=),直到遇到范围查询(>、<、between、like)就停止匹配。
注意:这里是mysql自己会选择优化,当然优化不一定就是最佳。
示例:a=3 and b=4 and c>5 and d=6,
如果建立(a,b,c,d)顺序的索引,d是用不到索引的;
如果建立(a,b,d,c)的索引,则都可以用到,a,b,d的顺序都可以任意调整。
2、=和in可以乱序,比如a=1 and b=2 and c=3建立(a,b,c)索引可以任意顺序,MySQL的查询优化器会帮你优化成索引可以识别的形式。
原因:
MySQL创建联合索引首先会对复合索引最左边即第一个索引字段的数据进行排序,在第一个排序字段的基础上再对后面第二个索引字段进行排序,类似实现了order by 字段1 order by 字段2,第一个字段绝对有序第二个字段无序。因此MySQL用第二个字段进行条件判断是用不到索引的。
注意:上图(col3,col2,col1)联合索引
索引是建立的越多越好吗
不是
1)数据量小的表不需要建立索引,建立会增加额外的索引开销。
2)数据变更需要维护索引,因此更多的索引意味着更多的维护成本。
3)更多的索引意味着需要更多的空间。
三、锁模块
参考链接1:mysql技术内幕–innodb存储引擎图解(超级详细)
参考链接2:《MySQL技术内幕InnoDB存储引擎》学习笔记
注意:
表中某字段带有key的即存在索引,还有联合键作为联合索引情况
3.1、MyISAM和InnoDB关于锁方面的区别
1、MyISAM默认使用表级锁,不支持行级锁;
2、InnoDB默认用的行级锁,也支持表级锁。
注:
1、无论是表锁还是行锁,均分为共享锁share lock(S)和排它锁exclusive lock(X)
共享锁和排它锁的兼容性:
后面的MyISAM、InnoDB支持的锁在行表上的差异并不影响共享锁和排它锁的特性
MyISAM
MyISAM先上读锁后上写锁(被Block)、读锁(不被Block)
1、MyISAM对数据进行select时,自动加上一个表级读锁,表级锁自动锁住整张表;
2、对数据进行增删改时,操作表加上一个表级别的写锁。读锁未被释放时,另外一个Session(数据库客户端一个窗口tab就是一个Session)想要对该表加上一个写锁就会被阻塞(Block),直到所有的读锁都被释放为止。
3、示例:
lock table 表名 read 显示给表加上读锁
unlock tables 释放锁
MyISAM先上写锁后上读锁(被Block)、写锁(被Block)
1、当上了写锁在上读锁时,需要等待写锁的释放。
2、上写锁的同时再上写锁,也被阻塞。
注:
除了可以对insert、update、delete语句上排它锁,也可以对select语句上排它锁。
即增删改操作,自动上 排它锁,但读操作,默认只上 读锁。
那么上排它锁,只需要在select的sql语句后面加上 for update
这样理解MyISAM:
1、加读锁后不能写,但能支持其他读
2、加上写锁后,既不能写也不能读
3、读锁也叫共享锁(S锁),写锁也叫排它锁(X锁)
4、上共享锁后依然支持上共享锁,上排它锁后共享锁和排它锁都不支持。
InnoDB
InnoDB用的二段锁,即加锁和解锁是分成两个步骤。统一解锁
1、先对同一个事务里的一批操作进行加锁,commit后再对事务加上的锁进行统一的解锁。
即:commit操作就相当于解锁unlock
2、注意:MySQL默认是自动提交事务,即commit是自动提交的。
show variables like 'autocommit' 查看默认事务提交设置
set autocommit = 0 设置事务为手动提交,即设置之后没有提交就相当于没有解锁,
若要解锁sql语句后执行 commit;
那么,select上共享锁,在select的sql语句后面加上 lock in share mode;
对比参照前面MyISAM给select上排它锁
InnoDB在SQL没用到索引时走的是表级锁,用到索引时走的时行级锁和gap锁。
即表级锁和索引无关,反之,当不走索引时候,用的就是表级锁
InnoDB的锁默认支持行级锁。
InnoDB对select进行了改进,
在select语句后面加 lock in share mode显示上读锁,不可以上写锁。可以上共享锁。
说明:
上一条专指行级锁,即当前行上读锁,那么其他session中当前行不可以上写锁,可以上读锁。其他行并不影响。
而且也得首先是能支持行级锁的字段才行,若某字段(不支持索引,即没key,或属于联合索引key中部分字段也不行),
看起来where 也像是根据xx条件查询某一行,实际上使用的还是表级锁。
InnoDB除了支持行级锁外,还支持表级意向锁,
意向锁分为意向共享锁IS、意向排它锁IX,作用是在进行表级别操作时不用轮询每一行看有没有上行锁。
各自适用场景
MyISAM适用场景
1)频繁执行全表count语句
(InnoDB不保存表的具体行数,执行count语句重新扫描统计;MyISAM用一个变量保存表的行数,执行count语句只需读出该变量即可)
2)对数据进行增删改的频率不高,查询非常频繁(增删改涉及锁表操作)
3)没有事务
InnoDB适用场景
1)数据增删改查都非常频繁
(增删改时只是某些行被锁,在大多数情况下避免了阻塞)
2)可靠性要求比较高,要求支持事务
数据库锁的分类
1、按锁的粒度划分,可以分为表级锁、行级锁、页级锁。
(BDB引擎使用页级锁,介于表级锁和行级锁,锁定位于同一个存储页的相邻几行数据)
2、按锁级别划分,可分为共享锁和排它锁。
3、按加锁方式划分,可分为自动锁、显式锁。
注:自动锁,增删改就自动上锁,查的话可以显示上锁
4、按操作划分,可分为DML锁、DDL锁。
提示:
DML锁(data locks,数据锁),用于保护数据的完整性;
DDL锁(dictionary locks,字典锁),用于保护数据库对象的结构,如表、索引等的结构定义;
5、按使用方式划分,可分为乐观锁和悲观锁。
1、悲观锁对外界的修改持保守态度,外界指即本系统当前的其他事务和外部系统的事务处理。
全程用排它锁锁定是悲观锁的一种实现。
悲观并发控制是先取锁再访问的保守策略,对数据处理的安全提供了保证。在效率方面处理加锁的机制会产生额外的开销,增加产生死锁的机会;
2、乐观锁认为数据一般情况不会造成冲突,数据提交更新时才会对数据的冲突与否进行检测,发现冲突返回用户错误的信息,让用户决定如何去做。
相对悲观锁对数据进行处理时,乐观锁不会使用事务的锁机制,一般实现乐观锁的方式是记录数据版本。
实现数据版本有两种方式:第一种是使用版本号;第二种是使用时间戳
如更新数据,提交的时候就去判断版本,不是很理解
3.2、数据库事务的四大特性
ACID
Atomic
原子性:事务包含的所有操作要么全部执行,要么全部失败回滚。要么全做,要么全不做。
Consistency
一致性:事务应确保数据库的状态从一个一致状态转变为另外一个一致的状态。以转账为例,A账户+B账户=2000,无论A和B如何转账,转几次账,A和B的钱加起来还是2000。
Isolation
隔离性:多个事务并发执行时一个事务的执行不影响其他事务的执行。
Durability
持久性:一个事务一旦提交,对数据库的修改永久保存在数据库中。
当系统或者介质发生故障时确保已提交事务的更新不能丢失,即对已提交事务的更新能恢复。
一旦一个事务被提交,DBMS保证提供适当冗余,使其耐得住系统的故障。
注:Durability和redo log(InnoDB 引擎层的日志)有关
3.3、事务隔离级别以及各级别下的并发访问问题
下图更新丢失情况示意:
事务并发访问引起的问题以及如何避免?
注:
1、关注RC与RR
2、Oracle默认的隔离级别只解决了脏读的问题。
脏读问题联想到,一边取钱失败,一边存钱不见多
3、MySQL默认隔离级别解决了不可重复读的问题。
重复读问题联想到,一边反复查看存款不一样,一边存钱
4、Serializable直接锁表了,MySQL的RR是怎么避免幻读?看下一节
1)更新丢失 --MySQL所有事务隔离级别在数据库层面上均可避免
2)脏读 --Read-Committed,即RC事务隔离级别以上可以避免
(一个事务读到另一个事务未提交的数据)
(Read-Committed规定事务只能读取其他事务已经提交的数据,不允许读未提交的数据)
查询当前Session的事务隔离级别:
select @@tx_isolation;
设置当前Session的事务隔离级别为read uncommitted:
set session transaction isolation level read uncommitted;
补充:开启事务
start transaction
xxx
commit or rollback
3)不可重复读 --Repeatable-Read,即RR事务隔离级别以上可以避免
(事务A多次读取同一数据,事务B在事务A读取数据时对数据更新并提交,
导致事务A多次读取数据时数据不一致)
注:
简单来说,一次事务内多次单纯读取数据按理结果应该是一样的,出现不一样结果就和现实很矛盾
4)幻读 --Serializable事务隔离级别可避免
(事务A读取与搜索条件相匹配的若干行,事务B以插入或删除行的方式来修改事务A的结果集,导致事务A看起来像出现幻觉一样)
即事务A操作了本来没有的数据
注:
不可重复度侧重于对同一数据的修改,幻读侧重于新增或删除。
事务隔离级别越高,安全性越高,串行化执行越严重,降低数据的并发度。
根据业务的需要设置事务的隔离级别。
Oracle默认为Read-Committed,MySQL默认为Repeatable-Read。
3.4、InnoDB的RR级别下如何避免幻读
表象:在RR级别下,基于伪MVCC(多版本并发控制,读不加锁,读写不冲突)实现的快照读(非阻塞读)来避免使我们看到幻行
内在:next-key锁(行锁+gap锁),这个内容太深了,查资料
提示:
1、RC隔离级别当前读和快照读一样
2、RR隔离级别,快照读有可能得到历史版本,当前读得到最新版本。即RR下创建快照读的时机决定了得到的版本。
RC下没有gap锁无法避免幻读
RR以及Serializable支持gap锁
Gap锁
为什么update、delete、insert也是当前读?
RDMS关系型数据库管理系统由两部分组成,程序实例和存储InnoDB,如下图。
示例:update操作内部包含一个当前读来获取数据的最新版本。
当前读和快照读(非阻塞读)的区分
1、当前读,即加了锁的增删改查语句,不管是共享锁还是排它锁。
当前读:select...lock in share mode、 select...for update、
当前读:update、 delete、 insert
注:
读取的是记录的最新版本,读取之后还需要保证其他并发事务不能修改当前记录,对读取的记录加锁,所以叫当前读。
除了select...lock in share mode对记录加共享锁,其他都加排它锁。
2、快照读:不加锁的非阻塞读,select。
注:
不加锁是在事务隔离级别不为Serializable的前提下。
解释:
1、在Serializable下,由于是串行读,快照读退化成当前读,即select...lock in share mode。
2、快照读是为了提升并发性能,快照读的实现是基于多版本并发控制即MVCC,MVCC是行级锁的一个变种,在很多情况下避免了加锁操作,因此开销更低。
3、基于多版本意味着快照读读到的不一定是数据的最新版本,可能是历史版本。
3.5、RC、RR级别下的InnoDB的非阻塞读如何实现?
1、主要数据行里DB_ROW_ID、DB_TRX_ID、DB_ROLL_PTR字段
DB_TRX_ID字段:
标识最近一次对本行记录做修改,不管是insert或update或delete(都可认为是update),事务的标识符,即最后一次修改本行记录的事务的ID。
DB_ROLL_PTR:
回滚指针,写入回滚段Rollback segment的undo日志记录,如果一行记录被更新,undo log report包含重建该行记录被更新之前内容所必须的信息。
DB_ROW_ID行号:
包含一个随着新行插入而单调递增的行id,由innoDB自动产生聚集索引时,聚集索引会包含行id的值,否则行id不会出现在任何索引中。
注:
InnoDB的表即没有主键也没有唯一键时,InnoDB会自动隐式创建一个的自动递增隐藏主键字段,即DB_ROW_ID。
2、光有这三个字段不足以实现快照读,还需要undo日志。
1、当对记录做了变更操作时,就会成undo记录。
2、undo记录存储的是老版数据,当一个旧事务需要读取数据时,为了读取老版数据,需要顺着undo链找到满足其可见性的记录。
3、undo log主要分为两种,insert undo log和update undo log,
3.1、insert undo log
表示事务对insert新纪录产生的undo log,只在事务回滚时需要,事务提交后就可以立即丢弃。
3.2、update undo log
是事务在对数据delete、update时产生的undo log,不仅在事务回滚时需要,快照读也需要,所以不能随便删除。
只有当数据库使用的快照不涉及该日志记录,对应的回滚日志才会被线程删除。
日志的工作方式:
参考链接:《剑指Java面试-Offer直通车》–数据库
事务对行记录的更新过程。InnoDB在内部做了非常多的工作。具体如何操作请查看相关资料
3、read view
1、read view做可见性判断,
当进行快照读Select时对针对查询出的数据做read review来决定当前事务能看到的是哪个版本的数据,
有可能是最新版本的数据,也有可能是undo log某个版的数据。
2、read review遵循一个可见性算法,
将要修改的数据的DB_TRX_ID与系统其他活跃事务ID做对比,大于等于这些ID,
就通过DB_ROLL_PTR取出undo log上一层的DB_TRX_ID,直到小于这些活跃事务ID为止,
这样保证当前数据版本是当前可见的最稳定版本。
四、关键语法
group by:给定数据列的每个成员,对查询结果进行分组统计,最终得到一个分组汇总表。
对同一张表
1)select子句的列名必须为分组列(group by用到的列)或列函数(count、sum、max、min、avg)
注:列函数中可以用到其他列名,但必须能统计。例如,不可能对一个非数字列累加
2)列函数对于group by子句定义的每个组各返回一个结果
那么非同一张表,如两张表联合
1、列名必须为分组列(group by用到的列)或列函数
2、其他列名可以用于分组列唯一对应的列名,可能不准确。如student_id和studen_name这种关系
order by :根据指定的列对结果集进行排序,默认按照升序(ASC)对记录进行排序,降序使用 DESC 关键字。
having:尤其要注意group by>having顺序
1)通常与group by子句一起使用
注:
在group by后指定过滤的条件,省略group by,having就和where一样。
例 select * from 表名 where id = #
类似select * from 表名 having id = #
2)where过滤行,having过滤组
3)出现在同一sql的顺序:where>group by>having。
统计相关(聚合函数):count求总数、sum求和、max求最大值、min求最小值、avg求平均。
在MySQL数据库中,聚合函数不能出现在where语句中,聚合函数的实现是基于所有数据的基础上,where语句是对数据进行筛选的。
limit 查询前N条记录:limit ?,?
五、数据库范式
参考链接:第一范式,第二范式,第三范式,BCNF范式理解
目前,关系数据库有六种范式:
第一范式(1NF)、 第二范式(2NF)、 第三范式(3NF)、
巴斯-科德范式(BCNF) 、第四范式(4NF)和第五范式(5NF,又称完美范式)。
1NF:每一列都是不可分割的原子数据项。即不可再拆分
2NF:在1NF的基础上所有列完全依赖于主键列。
消除部分函数依赖,全部是完全函数依赖,即不产生局部依赖,一张表只描述一件事情
3NF:在满足 2NF 的基础上, 任何非主列不得传递依赖于主键。
消除传递函数依赖,即表中每一列都直接依赖于主键,而不是通过其它列间接依赖于主键