MySQL自学笔记

索引

索引对MySQL的影响很大,索引设置的好坏直接决定MySQL的查询速度和性能
所谓索引,就是先找到匹配索引的记录,然后再找到对应的数据行(与查询书的目录相似)

建立索引可以在某个字段上建立索引(列上),这样MySQL就会先在索引上面按值进行查询,然后再返回值所在的数据行
(Tip:主键的概念:唯一地标识表中的每一行(可以是多个或一个))

那么如何找到对应的行呢?
这就需要在对某个字段建立索引的时候,在每个节点中除了添加本字段的值,还要添加主键,这样就可以确定唯一的行,快速在表中找到对应的记录(行)

索引的结构
B树索引(准确来说B+树索引)

(插播一下关于B+树的数据结构概念)

B+树

做简单的介绍
平衡多叉搜索树
阶数:一个节点最多可以有多少个孩子,同时也代表树的一个节点有多少路
关键字:节点上的数值就是关键字
度:一个节点可以有多少个子节点
所有的叶子节点都是在同一层的
每个节点存储的是指针+值,指针如果一个节点可以存放三个数据,那么就会存在四个指针,三个数据(但是不会存放具体的数据值)

B树与B+树之间的区别在于,前者直接在关键字中保存数据,后者保存索引只有B+树的叶子节点中才保存数据
聚类索引和非聚类索引的区别在于叶子节点保存的是数据还是其他键。如果是存放的其他键的话需要进行回表的方法找到相对应的数据行。

优点也在于此,这样每个节点不直接存储数据,就可以存储的数据分类多,可以实现矮一些的树,对查找很有利
而B树存储的关键字是带有数据的,加入一个节点为一个4KB的磁盘块,那么如果数据占据了3.8KB其他0.2KB用于指针,那么数据越多,树的高度也就越大了

那么为什么树的高度对性能有所影响呢?
因为树的高度直接影响到了IO的次数以及每次IO的大小

B+树的叶子节点是通过链表的方式将其串联起来的
在查询的过程中B+树一定要查询到叶子节点才能得到值,B树直接在树上找到值
B+树可以出现多个相同的关键字

回到索引上来,索引比整表查询要快很多
首先整表查询一般是通过主键建立索引的,对某个字段建立索引是通过索引字段建树,并将最后的叶子节点上的数据换成主键,先通过字段找到主键,再通过主键找到对应的行,返回想要的值

例如有一张表格
|学生id|学生姓名|年龄|身高
|1|小明|12|177
|2|小玲|11|144
|4|小林|21|133
|3|小光|13|234
|6|小刚|24|45
那么如果设置学生id为主键,对年龄建立索引,就可以快速找到年龄在[12,21]这个区间内的学生姓名,而不用整表遍历

创建普通索引

create index index_name on table(age(length))

创建唯一索引

CREATE UNIQUE INDEX index_name ON table(age(length)) 

创建表结构的时候也可以创建索引(以上面的学生表为例子)

CREATE TABLE table (
	id int(10) NOT NULL,
	age int(10) NOT NULL ,
	name varchar(20) not NULL,
	tall int(10) NOT NULL ,
	PRIMARY KEY (id),
	INDEX index_name (age(length))
)

狠狠地删除索引

DROP INDEX index_name ON table

如果要组合索引
例如想把age和身高作为组合索引

ALTER TABLE article ADD INDEX index_titme_time (age(10), tall(10))

但是由于最左前缀的原则(建立索引按照 (age(10), tall(10)) 这个顺序建立组合索引,单独的查询tall无法使用到索引)
下面用到了索引

SELECT * FROM article WHREE age=12 AND tall=144;

SELECT * FROM article WHREE age=12;

下面没有用到了索引

SELECT * FROM article WHREE tall=144;

在面试的时候可能会有一个问题,问你hash表的过多的hash冲突如何解决,除了rehash之外,还可以将数据结构改为红黑树
在索引上也是相同的,其实索引用树结构之外还可以用hash索引的方法进行查询

hash索引
首先对每个索引列进行hash计算,同时需要保存对应索引的主键在hash表中,如果存在冲突还是会用链表的形式存储
(所以这样的存储结构有个问题,他不存储字段(列)的值,所以一找就找一行)(同时这种方法无法进行排序,所以无法应对范围性的问题,取不了范围)
所以hash表格只适用于一定的业务上
InnoDB有一种特殊的自适应hash索引,是在B树的索引之上再添加hash索引(提供快速查找的能力),在B树上面的节点只有符合规则才会加入到hash表中(热点数据)才会进入hash表中

自适应hash索引
例如:
创建一张表格,用于记录很多个url

create table URL(
	id int unsigned NOT NULL,
	url varchar(255) NOT NULL,
	primary key(id)
);

这时需要对url索引进行查询的话

create index url_index on URL(url);
select id from URL where  url="http://www.baidu.com";

但是如果正常的按照B树对url进行索引,那存储的内容很多,因为url也是本身很长,索引的速度也会很慢
这里的处理方法是建立模拟hash索引,伪hash(pseudo hash)
在原始表中新建一列,url_crc,对该值计算hash值,等查询到crc匹配了之后才会查询身份证
(注意:这里的命名url_crc,是因为此hash是利用crc_32来计算得到的)

create table pseudohash(
	id int unsigned NOT NULL,
	url varchar(255) NOT NULL,
	url_crc int unsigned NOT NULL  default 0,
	primary key(id)
);

创建hash索引

create index hash_url using hash on pseudohash(url_crc);

如果后面不加and,也就是查询的时候只计算hash值是否匹配,则会在出现hash冲突的时候返回多条记录(单纯的hash索引)

SELECT id FROM urlT WHERE url_crc = CRC32('www.blog.youkuaiyun.com')

创建自适应hash索引
所以不会引起hash冲突的查询是把url的常量值加在后面(也就是hash索引加B+树索引)

SELECT  id FROM urlT WHERE url_crc = CRC32('www.blog.youkuaiyun.com') AND url = 'www.blog.youkuaiyun.com';
SELECT  id FROM urlT WHERE url = 'www.blog.youkuaiyun.com' AND url_crc = CRC32('www.blog.youkuaiyun.com');

虽然在面对长字符串的时候hash有出众的查找表现,但是需要在插入和更新的时候维护url_crc这个列
可以通过触发器或者手动维护(这一步的工作可以放在建完表之后)

create trigger pseudo_crc_ins before insert on pseudohash for each row begin set new.url_crc=crc32(new.url);
create trigger pseudo_crc_ins before update on pseudohash for each row begin set new.url_crc=crc32(new.url);

索引的几个关键的知识
1、回表:MySQL会在建表的时候为主键建立索引,如果对另一列创建了一个索引,在依据这个索引进行查询的时候,是先查询主键,再通过主键查到对应的内容,这个过程就是回表(可能产生不必要的IO访问次数,所以有时候建立索引可能也就变慢)
2、覆盖索引:和回表很像,只不过在通过索引查询后需要查找的东西就是主键,那么就不必再通过主键查询了,直接拿来用,就是覆盖查询
3、索引下推:
例如:正常查询name和age,都会先把name过滤出来,给到server层,然后在server层对age进行过滤;也就是先对name进行查询获得结果,再对age进行查询获得结果,这样就出现了两次回表

现在下推的意思是,将过滤任务放在了存储引擎层,server层拿到的是对name和age过滤好的数据(这样可以减少存储引擎(磁盘)与server层之间的IO访问的量),也就是b+树中的节点存放的是元组,有效提高查询效率(让过滤条件更靠近数据)

这里的话就相当于name和age在过滤的时候一起进行,在过滤name的时候会连带age一起过滤,这样就可以避免了两次回表,只要一次回表

4、匹配最左前缀原则:也就是在联合索引的时候,创建索引的顺序,不能直接跳过最开始的前缀,这样不会触发索引
5、匹配列的前缀:在like查询的时候,%abc这种不会调用索引,但是abc%这种会(补充:like abc%就是查找是否有abc前缀的字符串)
6、可以匹配某一列的全部和另一列的部分
类似:

select * from staff where name = 'judy' and age > 25;

7、用前缀索引:在一张表中,如果存在一个字段可能会在不同的记录中重复出现,重复的索引可能会索引到一些记录(多行重复),这时候可以使用前k个字母作为索引(和第5条和第6条可能差不多)

建立索引的原则
1、查询更快,占用内存空间更小(最重要的两点)
2、基数较小的类,不太适合索引,例如性别,只有两类,离散程度很差(或者重复值很多的列)
3、使用短索引,前缀索引,可以left()建立索引,这样索引表占用空间小
4、外键一定要建立索引,关联其他表
原因1:避免子表上有表锁。可以获取索引上的行锁代替表锁。
原因2:避免子表上的全表扫描。假设删除主表中的记录,如果子表的外键没有索引,那么就会全表扫描子表,以确认是否存在子表主键与扫描行相同的记录。
5、频繁更新的字段不好建索引
6、尽量扩展索引,例如有了字段a的索引,想对b字段建立索引,那么可以组成联合索引
7、对text、image和bit不太适合索引

创建索引的时候需要注意的是一定要注意好大小,比如age和name,name所占用的存储空间大,那么尽可能对存储空间小的字段建立索引,前提是可以达到同样的效果
当where查找的对象与建表的对象的类型相符合,那么可以使用索引,不然无法使用索引(具体的验证,可以用explain加上select语句看possibile_key(索引的名字放在里面)和key(如果会用到索引则与索引名字相等)是否相等)
推荐InnoDB的主键为自增主键,如果主键并不是自增的,那么可能会出现在一个已满的节点上面还想插入一个节点,那么就可能涉及到节点的分裂或者上移,对表的性能会有影响,如果是递增的,那么就可以一直向后插入,不会出现满需要移动的情况

顺序IO和随机IO
MySQL中的顺序IO:这几条记录在磁盘中相邻的,存储在一个数据页或是多个相邻数据页中。可以快速通过索引将数据从磁盘读取到内存中,形成顺序IO
MySQL中的随机IO:在回表的过程中,是按照别的字段进行索引排序的,在叶子节点的部分存储的是主键信息,如果按照字段排序,那么主键很有可能在不相邻的页中,那么就需要根据主键访问更多的数据页,形成随机IO

何时不会用到索引:
1、对索引使用左或者左右模糊匹配,也就是 like %xx 或者 like %xx% 这两种方式都会造成索引失效。原因在于查询的结果可能是多个,不知道从哪个索引值开始比较,于是就只能通过全表扫描的方式来查询。
2、对索引进行函数/对索引进行表达式计算,因为索引保持的是索引字段的原始值,而不是经过函数计算的值,自然就没办法走索引。
3、对索引进行隐式转换相当于使用了新函数。
4、WHERE 子句中的 OR语句,只要有条件列不是索引列,就会进行全表扫描。
5、数据量太大的时候不会用到索引
6、order by的字段不在where中,也就是例如where id < 10 order by ids这样字段就不在where中的字段上进行排序(如果where id < 10 order by id不会再需要排序,那么就会走索引)
7、mysql会一直向右匹配直到遇到范围查询(>、<、between、like)就停止匹配,比如a = 1 and b = 2 and c > 3 and d = 4 如果建立(a,b,c,d)顺序的索引,d是用不到索引的
8、所有的负向索引不会走索引,负向条件有:!=、<>、not in、not exists、not like 等
9、只要列中包含有 NULL 值都将不会被包含在索引中,复合索引中只要有一列含有 NULL值,那么这一列对于此复合索引就是无效的。

查询的时候,= 符号的顺序可以乱序
新版的MySQL支持or的联合索引,所以第三点可以视作没有

常见锁
1、锁的属性来分
一、共享锁:例如读锁,可以允许多个线程读
二、排他锁:例如写锁,修改的时候,不允许其他线程同时占用
2、锁粒度
服务于并发资源
一、行锁:MySQL的行锁是通过索引加载的,也就是说,行锁是加在索引响应的行上的,要是对应的SQL语句没有走索引,则会全表扫描,行锁则无法实现,取而代之的是表锁,此时其它事务无法对当前表进行更新或插入操作。
注意:行锁是对索引加锁,而不是对记录加锁(行),虽然是不同行的数据,但是只要索引值相同,还是不能同时访问的,会发生冲突
行锁的使用场景:并发

二、表锁:MyISAM引擎下有表共享读锁、表独占写锁,共享读顾名思义是可以多个事务一起读相同的资源,独占写锁则是在写的时候会阻塞其他所有事务的的读和写,所以MyISAM不适合做写为主表的引擎,因为写锁后,其它线程不能做任何操作,大量的更新会使查询很难得到锁,从而造成永远阻塞

三、间隙锁:锁定索引记录间隙,确保索引记录的间隙不变。间隙锁也就是锁定字段的间隙,例如字段的值是2、3、5、6,那么间隙锁可以锁住(无穷小,2)(2,3)(3,5)(5,6)(6,无穷大)这些区间,使得无法在这些区间中添加新的字段值

四、页级锁:锁住页(粒度在行锁和表锁之间)锁住相邻的一组记录

五、记录锁:不像行锁一样,记录锁只能锁表中的一行,所以触发的条件字段一定是唯一索引的字段,可以避免脏读,也是就是事务未提交,但是被其他事务读取

六、临建锁(Next-Key Lock):行锁和间隙锁组合起来就叫Next-Key Lock,防止幻读

事务

拥有四种属性
1、A(原子性) 2、C(一致性) 3、I(隔离性) 4、D(持久性)
事务的隔离级别:
1、未提交读(可能出现脏读、不可重复读、幻读)
2、提交读(可能出现不可重复读、幻读)
3、可重复读(可能出现幻读)
4、串行化(只有在可以接收不可并发的情况下使用)

那么这四个特性是依据什么保证的?
1、原子性:undo log保证的,事务要么全部完成,要么全部不完成,所以需要对没有完成的事务进行回滚
2、一致性:业务上的一致性由其他三个特性来保证的
3、隔离性:MVCC+锁保证,防止多个事务并发执行时由于交叉执行而导致数据的不一致
4、持久性:内存+redo log来保证的,修改记录的时候,内存修改数据,这时候与磁盘数据不一致,同时redo log也存放修改命令例如update,在持久化到磁盘的时候,将redo log的命令执行到磁盘改变原来数据,也可以用于恢复数据(在MySQL服务器集群的时候,需要bin log来维持主从同步,所以redo log也可以对bin log进行写的操作,如果将事务持久化到bin log成功,那么在redo log中就会有一条commit记录)

Tip:脏读:事务没有提交的时候其他事务都可以看见,事务可以读取未提交的数据,那么如果之前的事务回滚了,值就变成了脏数据(在内存中修改了还未及时刷入磁盘的数据)
不可重复读:一个事务读取相同的数据,不一定与事务开始的时候一致(其他事务可能在其中改变了值,并提交)
幻读:虽然可重复读可以让事务反复读取,虽然锁住了事务的需要读的变量,但是允许添加(insert)所以有可能别的事务插入了数据,产生幻读

引申:死锁的四个必要条件:1、互斥条件 2、持有并等待条件 3、不可剥夺条件(非抢占) 4、环路等待

对于数据库可能存在两个事务同时更新(update)数据,互相持有对方想要获得的锁,那么很有可能产生死锁
innoDB的有死锁检测和死锁超时的机制来防止死锁
除了超时机制,innoDB还通过将持有最少行级排他锁的事务进行回滚(也就是行级别的锁,且一个事务对资源上排他锁则其他资源需要等待该事务释放锁才能使用)

多版本的并发控制(MVCC)

并发下,读写请求会被锁阻塞,MVCC就是不用加锁的情况下应对并发的

在MVCC并发控制中,读操作可以分成两类:快照读 (snapshot read)与当前读 (current read),这样就与写操作不会相互冲突
快照读:利用版本号,不用加锁(所以不保证是最新的内容,有可能有事务同时在写)
当前读:需要读最新的,所以需要加锁,保证表格中为最新的内容

MVCC需要的隔离等级是可重复读、提交读,原因:1、未提交读总是读取最新的数据行(因为他对于未提交的事务对数据行版本的改变也会记录),与事务版本的数据行会不一致;2、串行化则会对所有的行都进行加锁操作

MVCC会创建两个隐藏字段,一个保存行的创建时间trx_id,一个保存行的过期时间roll_pointer(这里的时间是系统版本号,而非真正时间)
trx_id:存储修改的事务id(最近修改的事务id)
roll_point:对聚簇索引如果进行了修改,都会把老版本写入undo log中。自身存储指针,指向聚簇索引的老版本记录的位置
每次开启一个新的事务,就会让版本号递增
每次对数据库做改动(除了insert之外)都会记录undo log,每次改变记录,都会用roll_point将其版本串联起来,形成版本链
insert:undo log中只有事务回滚的时候需要,事务提交之后就会被抛弃
update:不仅回滚的时候需要,快照读的时候也需要

进行快照读的时候会出现读视图(read view)用于记录当前活跃的事务(未提交的事务)
由于事务的id是自增的,索引在read view会存放一个事务id的范围,可以获取最大最小的事务id
当前有个事务id = 10和事务id = 13对某个记录同时进行操作,那么如果id = 10的事务希望重复读,就会读取记录的快照,这时候访问undo log,如果undo log中第一条数据的事务id = 11,那么说明该id = 11的事务是在id = 10事务生成read view之后才生成的,所以不能读,就会继续向下走链表(版本链),发现下一个id = 9;那么说明在当前事务生成read view之前id = 9就已经提交了,所以可以读(解决了不可重复读的问题和幻读问题)
当trx_id(版本链中的事务id)在m_ids(read view中活跃的事务id列表)中,或者大于m_ids列表中最大的事务id的时候,这个版本就不能被访问

MVCC解决的是读写冲突
方法:读操作只读取该事务开始前的数据库快照
解决问题如下:
1、并发读-写时:可以做到读操作不阻塞写操作,同时写操作也不会阻塞读操作
2、解决脏读、幻读、不可重复读等事务隔离问题,但不能解决上面的写-写 更新丢失问题
(解决脏读:不会出现读取其他未提交的事务对数据的改变值;解决幻读:不会理会是否insert数据;解决不可重复度:不会再一个事务中出现数据前后不一致)

因此有了下面提高并发性能的组合拳:
MVCC + 悲观锁:MVCC解决读写冲突,悲观锁解决写写冲突
MVCC + 乐观锁:MVCC解决读写冲突,乐观锁解决写写冲突

存储引擎

innoDB
聚簇索引(索引和数据放在一起)
底层索引的实现是B+树,且叶子节点存放的是索引和数据
innodb 的引擎四大特性为:插入缓冲,二次写,自适应哈希和预读。
用于处理大量短期的事务,默认的隔离等级是可重复读,通过间隙锁策略防止幻读

基于聚簇索引:对主键的查询性能很高,且二级索引(非主键索引必须要包含主键列),所以要求主键尽可能的小

innoDB下不同隔离级别的查询:
1、RC隔离级别+where无索引,也就是在无索引状态下的where,这时,where没有索引进行过滤就会遍历所有的表中的值,所以引擎也会给表中所有的值加上排他锁
2、RC隔离级别+where唯一索引,对于表内的某一个字段建立索引,得到两个索引表,一张是索引字段+主键,另一张则是完整的表。先用where对字段进行查询,给索引表上的记录(行)加上排他锁,再通过主键找到完整表中的数据并对记录(行)进行加锁
3、RC隔离级别+where普通索引, 也就是对普通索引来说的

InnoDB存在缓存池(这是对于读请求来说的,也就是想要从磁盘中读出数据页
存在的意义就是在于快速的IO读写,将热点的读写页放入缓存池中,如果命中,就会很节约IO时间,且缓存池是按页缓存的,所以在读取的时候可以保证按照页读取
管理缓存池的方法是LRU算法,但是也和正常LRU有区别
1、分为两块,新页(热数据)+老页(冷数据),如果真正被读取到才会加入新页的头部,如果没有被读取到,则会比新页中的数据更早淘汰,这样可以有效防止预读失败
2、当某一个SQL语句,要批量扫描大量数据时,可能导致把缓冲池的所有页都替换出去,导致大量热数据被换出,MySQL性能急剧下降,这就是缓冲池污染。例如当全表扫描的时候,如果用原始LRU就会将里面数据做个大换血,但是原本的热点数据就消失了。这里的过程是先将页添加到老页中,然后将老页中的页拿出来做比较,符合就加入结果,不符合就算,这时候被系统读到了,所以会将他放入新页中。这里可以设置老页的时间,只有满足超过这个时间并且被访问,才会加入到新页中。避免了扫描带来的换血

InnoDB优化写请求(这是对于写请求来说
1、如果想要写的页在缓存池中,那么命中该页,并执行写操作,再在redo log中更新,然后定期刷磁盘,而不是每次刷磁盘,能够降低磁盘IO,提升MySQL的性能。(内存和磁盘的一致性问题:1、读取的时候会命中内存页;2、缓存池中如果淘汰了,那么会将脏页刷回磁盘;3、数据库崩溃依旧可以redo log恢复)
2、对于写的优化来说,每次需要写的时候,并不需要立即将页读取到缓冲池中,可以先在change buffer中更新,之后如果未来读到了这个页的数据,在从磁盘缓存到缓冲池上,将数据合并merge(也就是将redo log上的更新内容写入对应的页上),目的还是为了减少IO次数

在写的过程中可能面临的问题是写进了buffer pool中,如果宕机了,则会消失,需要redo log来恢复内存

redo log和bin log之间的异同
1、redo log用于崩溃恢复数据;bin log用于主从复制和恢复
2、redo log在innoDB中实现;bin log在任何存储引擎中都有实现
3、redo log在大小是固定的,所以写的时候是循环写,会顶替掉原来的写的内容;bin log则是追加日志的方式,全量写
更新数据的流程:
4、redo log是物理日志,记录的是如何修改页;bin log是逻辑日志,保存的是修改的逻辑原语

  1. 取数据
  2. 判断是否在内存中(不在就去取,或者直接在change buffer中写)
  3. 写新的行数据
  4. 写入内存中
  5. pointA(服务器在这之前的时间点崩溃,这个时候redolog 和 binlog都没有任何记录,事务还未提交,不会造成任何影响)
  6. 提交给redo log(prepare阶段)
  7. pointB(服务器在这之前的时间点崩溃,再次启动的时候redo log里处于prepare状态的记录,这个时候需要检查binlog是否完整包含此条redo log的更新内容,发现binlog中还未包含此事务变更,则丢弃此次变更)
  8. 写入bin log
  9. pointC(服务器在这之前的时间点崩溃,与pointB相似,只不过bin log这时候写入了(如果发现bin log和redo log都写完了,那么事务可以提交))
  10. 提交事务处于commit阶段
  11. pointD(服务器在这之前的时间点崩溃,binlog中和数据库中均含有此事务的变更,直接从redo log里恢复)
  12. 结束

MyISAM
非聚簇索引(索引和数据分离,分两个文件)
MyISAM底层索引实现也是B+树的结构,但是在叶子节点处存放的不是具体的数据,而是地址,找到对应的地址之后,在磁盘中找到对应的块数据

慢查询

可能导致慢查询的原因
1、查询没有命中索引
2、load不需要的数据列
3、数据量太大
解决的方法
1、先分析语句,看是否存在额外的数据,查询多余的行并抛弃或加载不需要的列
2、分析语句执行计划explain,修改语句,尽量走索引
3、语句无法优化,表过大,可以考虑垂直或水平分表

MySQL的分表和分库

分库的思想和微服务的思想相似,例如将不同的需求分为不同的数据库存储数据
(例如 ,订单表、积分表、商品表部署到不同的机器上)
目的:单机的MySQL可能会将磁盘充满,拆成不同的数据库有利于减少磁盘的压力

分表则是将一个完整的表,垂直或者水平分为不同的表
目的:当数据过大的时候查询也会出现压力,如果查询没有命中,可能会产生数据库的崩溃;如果命中了,由于数据量的激增依旧会导致B+树的高度的增加,导致查询速度变慢。有利于实现高并发下的访问

分库的做法:
1、垂直分库:例如原本一个单机表中存放的是很多业务的数据库,将用户信息表,订单表,积分表这类分为不同的库
2、水平分库:将表的数据量进行拆分,比如主键是用户ID,那么可以用range的方法,将每一段的用户存放在一个数据库下

分表的做法:(与分库类似)
1、垂直分表:将字段进行拆分(字段就是列)例如将用户的基本信息放入一个表中,用户的详细信息放到另一个表格中,这样实现访问用户基本信息与详细信息分离
2、水平分表:将记录进行拆分(记录就是行)例如将用户ID进行分段(range)将用户的某一段放到一个表中,另一段用户放入另一个表中

水平分表分库的策略
1、range范围,例如对用户ID进行range范围划分,(0,1000)/(1001,2000)划分为两张表(优点:不需要数据迁移,方便划分;缺点:有可能有一部分段为活跃用户,那么会经常访问,也就是热点问题,那么并发情况下,压力还是在一张表下)
2、hash取模划分,例如将用户的的ID取模,放到一个表中,模几,就有几张表(优点:不会出现热点问题;缺点:如果数据需要扩容,也就是需要扩容到多个表(例如8张表),那么原来取模的数就要变成8,但是之前取模的值就可能出现改变,所以数据的迁移不方便)
3、range+hash(计算机最喜欢合并方法),例如先将一个大订单表的订单ID利用range的方法划分为多个订单库,再将一个订单库中的订单利用hash划分为不同的表

group by和聚合函数

聚合函数的意思是对一组值执行计算并返回单一的值。
常见的聚合函数有
1、求个数/记录数/项目数等:count()
2、求某一列平均数 :avg()
3、求总和,总分等:sum() --必须为数字列
4、求最大值,最高分,最高工资等:max()
5、求最小值,最低分,最低工资等:min()

除了 COUNT 以外,聚合函数忽略空值。
聚合函数经常与 SELECT 语句的 GROUP BY 子句一同使用。
所有聚合函数都具有确定性。任何时候用一组给定的输入值调用它们时,都返回相同的值。
标量函数:只能对单个的数字或值进行计算。主要包括字符函数、日期/时间函数、数值函数和转换函数这四类。

(持续更新中)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值