Java相关内容:数据库

要想进阶成Java中级开发工程师,有一些东西总是绕不过去的,Java的知识体系里,像IO/NIO/AIO,多线程,JVM,网络编程,数据库,框架等必须有一定了解才行。最近在准备面试,所以对这些东西也做个记录。本篇记录的是数据库相关。

 

数据库基本内容简单回顾(以下问题基于Mysql)

 

1.0 什么是三范式?

1.列不可再分;

2.行需要唯一区分; (一般就是说要设置主键)

3.非主属性只依赖于主属性,而不能依赖于其它非主属性。 (就是找非主键字段只能通过主键来关联,而不是啊三啊四)

 

1.1 事务

1.1.1 事务四大特性

• 事务四大特性(ACID)

原子性(Atomic) :指事务中的操作要么都发生,要么都不发生。  (如转帐扣款加款的两条语句,要么执行,要么不执行)

一致性(Consistency):指如果在执行事务之前数据库是一致的,那么在执行事务之后数据库也还是一致的。(即不会出现修改丢失、脏读、不可重复读、幻读等情况)

隔离性(Isolation):多个事务并发访问时,事务之间是隔离的,一个事务不影响其它事务的运行效果。 (此处有隔离级别的说法)

持久性(Durability):事务提交后,对数据的修改时永久的。及时系统发生故障,也能在不会丢失对数据的修改。一般通过执行前写入日志的方式保证持久性,即使系统崩溃,也能在重启的过程中,通过日志恢复崩溃时处于执行状态的事物。z

 

1.1.2 事务隔离级别

• 事务的并发?事务隔离级别,每个级别会引发什么问题,MySQL默认是哪个级别?

读未提交(Read Uncommitted):最低的隔离级别,什么都不需要做,一个事务可以读到另一个事务未提交的结果。即可能出现脏读,不可重复读,幻读。

读提交(Read Committed):只有在事务提交后,其更新结果才会被其他事务看见。可以解决脏读问题。但是还有不可重复读和幻读问题。

可重复读(Repeated Read):在一个事务中,对于同一份数据的读取结果总是相同的,无论是否有其他事务对这份数据进行操作,以及这个事务是否提交。可以解决脏读、不可重复读,但是无法解决幻读问题。这是Mysql中默认的隔离级别。

串行化(Serialization):事务串行化执行,隔离级别最高,读写分开,牺牲了系统的并发性。可以解决并发事务的所有问题。

- 脏读:又称无效数据的读出,是指在数据库访问中,事务T1将某一值修改,然后事务T2读取该值,此后T1因为某种原因撤销对该值的修改,这就导致了T2所读取到的数据是无效的。
- 不可重复读:是指在数据库访问中,一个事务范围内两个相同的查询却返回了不同数据。这是由于查询时系统中其他事务修改的提交而引起的。比如事务T1读取某一数据,事务T2读取并修改了该数据,T1为了对读取值进行检验而再次读取该数据,便得到了不同的结果。不可重复度因为当执行SELECT 操作时没有获得读锁(read locks)或者SELECT操作执行完后马上释放了读锁。
- 幻读:是指当事务不是独立执行时发生的一种现象,例如第一个事务对一个表中的数据进行了修改,比如这种修改涉及到表中的“全部数据行”。同时,第二个事务也修改这个表中的数据,这种修改是向表中插入“一行新数据”。那么,以后就会发生操作第一个事务的用户发现表中还有没有修改的数据行,就好象发生了幻觉一样。幻读主要由于另一个事务插入导致。

1.2 存储引擎

• MySQL常见的三种存储引擎(InnoDB、MyISAM、MEMORY)的区别?

MySQL中的存储引擎有很多种,可以通过“SHOW ENGINES”语句来查看。下面重点关注InnoDB、MyISAM、MEMORY这三种

1.2.1 引擎区别

不同的存储引擎决定了MySQL数据库中的表可以用不同的方式来存储。我们可以根据数据的特点来选择不同的存储引擎。

INNODB

支持事务,支持外键,行锁,支持主键自增。查表总行数时,全表扫描。缺点是读写效率较差,占用的数据空间相对较大。

MYISAM

MyISAM的优势在于占用空间小,处理速度快。缺点是不支持事务,不支持外键,不支持行锁。插入数据时,锁定整个表,查表总行数时,不需要全表扫描。

MEMORY

MEMORY是MySQL中一类特殊的存储引擎。它使用存储在内存中的内容来创建表,而且数据全部放在内存中。这些特性与前面的两个很不同。这样有利于数据的快速处理,提高整个表的效率。值得注意的是,服务器需要有足够的内存来维持MEMORY存储引擎的表的使用。如果不需要了,可以释放内存,甚至删除不需要的表。MEMORY默认使用哈希索引。MEMORY用到的很少,因为它是把数据存到内存中,如果内存出现异常就会影响数据。如果重启或者关机,所有数据都会消失。因此,基于MEMORY的表的生命周期很短,一般是一次性的。

1.2.2 引擎选择

InnoDB:支持事务处理,支持外键,支持崩溃修复能力和并发控制。如果需要对事务的完整性要求比较高(比如银行),要求实现并发控制(比如售票),那选择InnoDB有很大的优势。如果需要频繁的更新、删除操作的数据库,也可以选择InnoDB,因为支持事务的提交(commit)和回滚(rollback)。 

MyISAM:插入数据快,空间和内存使用比较低。如果表主要是用于插入新记录和读出记录,那么选择MyISAM能实现处理高效率。如果系统读多,写少。对原子性要求低。那么MyISAM最好的选择。

MEMORY:所有的数据都在内存中,数据的处理速度快,但是安全性不高。如果需要很快的读写速度,对数据的安全性要求较低,可以选择MEMOEY。它对表的大小有要求,不能建立太大的表。所以,这类数据库只使用在相对较小的数据库表。

注意,同一个数据库也可以使用多种存储引擎的表。如果一个表要求比较高的事务处理,可以选择InnoDB。这个数据库中可以将查询要求比较高的表选择MyISAM存储。如果该数据库需要一个用于查询的临时表,可以选择MEMORY存储引擎。

1.3 mysql锁

• mysql都有什么锁,死锁判定原理和具体场景,死锁怎么解决?• mysql锁,行锁,表锁 ,什么时候发生锁,怎么锁,原理• 有哪些锁(乐观锁悲观锁),select 时怎么加排它锁?

1.3.1 mysql锁类型

MySQL数据库存在多种数据存储引擎,每种存储引擎所针对的应用场景特点都不太一样,为了满足各自特定应用场景的需求,每种存储引擎的锁定机制都是为各自所面对的特定场景而优化设计。MySQL各存储引擎使用了三种类型(级别)的锁定机制:表级锁定,行级锁定和页级锁定。

表级锁:开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低。 行级锁:开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高。 页面锁:开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度一般。

1.3.2 mysql锁使用

MYISAM锁

MyISAM存储引擎,只支持表锁。MyISAM在执行查询语句(SELECT)前,会自动给涉及的所有表加读锁,在执行更新操作 (UPDATE、DELETE、INSERT等)前,会自动给涉及的表加写锁。即MyISAM中读和写是串行的。

InnoDB锁

InnoDB存储引擎,它支持行锁,也支持表锁(Lock table .. read/write),默认情况下是采用行锁。InnoDB实现了以下两种类型的行锁。对于UPDATE、DELETE和INSERT语句,InnoDB会自动给涉及数据集加排他锁;

  • 共享锁(s):又称读锁。允许一个事务去读一行,阻止其他事务获得相同数据集的排他锁。若事务T对数据对象A加上S锁,则事务T可以读A但不能修改A,其他事务只能再对A加S锁,而不能加X锁,直到T释放A上的S锁。这保证了其他事务可以读A,但在T释放A上的S锁之前不能对A做任何修改。

  • 排他锁(X):又称写锁。允许获取排他锁的事务更新数据,阻止其他事务取得相同的数据集共享读锁和排他写锁。若事务T对数据对象A加上X锁,事务T可以读A也可以修改A,其他事务不能再对A加任何锁,直到T释放A上的锁。

使用方式:
对于普通SELECT语句,InnoDB不会加任何锁;事务可以通过以下语句显式给记录集加共享锁或排他锁。
共享锁(S): SELECT * FROM table_name WHERE ... LOCK IN SHARE MODE
排他锁(X): SELECT * FROM table_name WHERE ... FOR UPDATE

注意:

  • 行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。这些锁统称为悲观锁(Pessimistic Lock)

  • 加过排他锁x的数据行在其他事务中是不能修改数据的,也不能通过for update和lock in share mode锁的方式查询数据,但可以直接通过select …from…查询数据,因为普通查询没有任何锁机制。

  • 间隙锁:当我们用范围条件而不是相等条件检索数据,并请求共享或排他锁时,InnoDB会给符合条件的已有数据记录的 索引项加锁;对于键值在条件范围内但并不存在的记录,叫做“间隙(GAP)”,InnoDB也会对这个“间隙”加锁,这种锁机制就是所谓的间隙锁 (Next-Key锁)

  • InnoDB的行锁是基于索引实现的,如果不通过索引访问数据,InnoDB会使用表锁。 

 

1.4 索引

• 索引类型?• 索引为什么要用B+树,B+树/B-树区别?B+Tree索引/Hash索引区别?• 聚集、非聚集索引区别?

1.4.1 索引分类

Mysql目前主要有以下几种索引类型:全文索引(FULLTEXT),哈希索引(HASH),B+树索引(BTREE),空间数据索引(RTREE)。其中:

  • B+树索引(BTREE)

    是mysql默认的InnoDb引擎使用的索引,也是我们最常见的索引,可以分为普通索引、唯一索引、组合索引。

    普通索引:仅加速查询最基本的索引,没有任何限制,是我们大多数情况下使用到的索引。

    唯一索引:与普通索引类型,不同的是:加速查询 + 列值唯一(可以有null)

    组合索引:将几个列作为一条索引进行检索,使用最左匹配原则。

CREATE INDEX  index_name on user_info(name);
CREATE UNIQUE INDEX unindex_name on user_info(name);

  • 全文索引(FULLTEXT)

    仅可以适用于MyISAM引擎的数据表;仅可作用于CHAR、VARCHAR、TEXT数据类型的列。它的出现是为了解决WHERE name LIKE '%word%' 这类针对文本的模糊查询效率较低的问题。

  • 哈希索引(HASH)

    是Memory引擎上的索引。HASH索引可以一次定位,不需要像树形索引那样逐层查找,因此具有极高的效率。但是,这种高效是有条件的,即只在“=”和“in”条件下高效,且不支持范围查询、排序及组合索引。另外hash索引中的hash码的计算可能存在hash冲突。当出现hash冲突的时候,存储引擎必须遍历整个链表中的所有行指针,逐行比较,直到找到所有的符合条件的行。

  • 空间数据索引(RTREE):

    RTREE在MySQL很少使用,仅支持geometry数据类型,支持该类型的存储引擎只有MyISAM、BDb、InnoDb、NDb、Archive几种。相对于BTREE,RTREE的优势在于范围查找。

聚合索引、非聚合索引区别:

聚集索引:

​ 当给表上了主键,那么表在磁盘上的存储结构就由整齐排列的结构转变成了树状结构,也就是「平衡树」结构,换句话说,就是整个表就变成了一个索引。没错, 再说一遍, 整个表变成了一个索引,也就是所谓的「聚集索引」。 这就是为什么一个表只能有一个主键, 一个表只能有一个「聚集索引」,因为主键的作用就是把「表」的数据格式转换成「索引(平衡树)」的格式放置。

非聚集索引:

​ 非聚集索引和聚集索引一样, 同样是采用平衡树作为索引的数据结构。索引树结构中各节点的值来自于表中的索引字段, 假如给user表的name字段加上索引 , 那么索引就是由name字段中的值构成,在数据改变时, DBMS需要一直维护索引结构的正确性。如果给表中多个字段加上索引 , 那么就会出现多个独立的索引结构,每个索引(非聚集索引)互相之间不存在关联。

二者区别在于, 通过聚集索引可以查到需要查找的数据, 而通过非聚集索引可以查到记录对应的主键值 , 再使用主键的值通过聚集索引查找到需要的数据。

 

1.4.2 索引创建与使用

什么时候应该创建索引:

  1. 表的主键、外键必须有索引;

  2. 数据量较大的表应该有索引;

  3. 经常用做连接查询的字段,需要有索引;

  4. 经常出现在Where子句中的字段,应该建立索引;

  5. 经常用到排序的列上,因为索引已经排序。(单order by)

  6. 经常用在范围内搜索的列上创建索引,因为索引已经排序了,其指定的范围是连续的。(between)

order by:mysql查询只使用一个索引,因此如果where子句中已经使用了索引的话,那么order by中的列是不会使用索引的。
group by :也会用上索引

什么时候会用不上索引:

  1. 如果条件中有or,即使其中有条件带索引也不会使用索引(or可以用union代替);

  2. 对于多列索引,不是使用的第一部分,则不会使用索引(即不符合最左前缀);且复合索引中只要有一列含有NULL值,那么这一列对于此复合索引就是无效的;

  3. like查询是以%开头时不会使用索引(MyISAM的全文索引可以%word%);

  4. 如果列类型是字符串,那一定要在条件中将数据使用引号引用起来,否则不使用索引。

  5. 索引列参与计算也不会使用索引。

  6. NOT IN 、<>、!= 操作也不会使用索引,但<,<=,=,>,>=,BETWEEN,IN是可以用到索引的

通过USE INDEX、IGNORE INDEX、FORCE INDEX可以使用、忽略、强制使用索引

1.4.3 索引原理

​ 索引的目的在于提高查询效率,原理是通过不断的缩小想要获得数据的范围来筛选出最终想要的结果,同时把随机的事件变成顺序的事件,也就是我们总是通过同一种查找方式来锁定数据。但是由于通过磁盘IO读取数据耗费的时间比较多,所以我们希望每次查找数据时把磁盘IO次数控制在一个很小的数量级,最好是常数数量级。那么我们就想到如果一个高度可控的多路搜索树是否能满足需求呢?就这样,b+树应运而生。

​ 如上图,是一颗b+树,关于b+树这里只说一些重点,浅蓝色的块我们称之为一个磁盘块,可以看到每个磁盘块包含几个数据项(深蓝色所示)和指针(黄色所示),如磁盘块1包含数据项17和35,包含指针P1、P2、P3,P1表示小于17的磁盘块,P2表示在17和35之间的磁盘块,P3表示大于35的磁盘块。真实的数据存在于叶子节点即3、5、9、10、13、15、28、29、36、60、75、79、90、99。非叶子节点不存储真实的数据,只存储指引搜索方向的数据项,如17、35并不真实存在于数据表中。

b+树的查找过程

​ 如图所示,如果要查找数据项29,那么首先会把磁盘块1由磁盘加载到内存,此时发生一次IO,在内存中用二分查找确定29在17和35之间,锁定磁盘块1的P2指针,内存时间因为非常短(相比磁盘的IO)可以忽略不计,通过磁盘块1的P2指针的磁盘地址把磁盘块3由磁盘加载到内存,发生第二次IO,29在26和30之间,锁定磁盘块3的P2指针,通过指针加载磁盘块8到内存,发生第三次IO,同时内存中做二分查找找到29,结束查询,总计三次IO。真实的情况是,3层的b+树可以表示上百万的数据,如果上百万的数据查找只需要三次IO,性能提高将是巨大的,如果没有索引,每个数据项都要发生一次IO,那么总共需要百万次的IO,显然成本非常非常高。

b+树性质

  1. 通过上面的分析,我们知道IO次数取决于b+树的高度h,假设当前数据表的数据为N,每个磁盘块的数据项的数量是m,则有h=㏒(m+1)N,当数据量N一定的情况下,m越大,h越小;而m = 磁盘块的大小 / 数据项的大小,磁盘块的大小也就是一个数据页的大小,是固定的,如果数据项占的空间越小,数据项的数量越多,树的高度越低。这就是为什么每个数据项,即索引字段要尽量的小,比如int占4字节,要比bigint8字节少一半。这也是为什么b+树要求把真实的数据放到叶子节点而不是内层节点,一旦放到内层节点,磁盘块的数据项会大幅度下降,导致树增高。当数据项等于1时将会退化成线性表。

  2. 当b+树的数据项是复合的数据结构,比如(name,age,sex)的时候,b+数是按照从左到右的顺序来建立搜索树的,比如当(张三,20,F)这样的数据来检索的时候,b+树会优先比较name来确定下一步的所搜方向,如果name相同再依次比较age和sex,最后得到检索的数据;但当(20,F)这样的没有name的数据来的时候,b+树就不知道下一步该查哪个节点,因为建立搜索树的时候name就是第一个比较因子,必须要先根据name来搜索才能知道下一步去哪里查询。比如当(张三,F)这样的数据来检索时,b+树可以用name来指定搜索方向,但下一个字段age的缺失,所以只能把名字等于张三的数据都找到,然后再匹配性别是F的数据了, 这个是非常重要的性质,即索引的最左匹配特性。

1.4.4 b+树、b树

二者的特点如下:

b树:

  1. 关键字集合分布在整颗树中;

  2. 任何一个关键字出现且只出现在一个结点中;

  3. 搜索有可能在非叶子结点结束;

  4. 其搜索性能等价于在关键字全集内做一次二分查找;;

b+树:

b+树,是b树的一种变体,查询性能更好。m阶的b+树的特征:

  1. 有n棵子树的非叶子结点中含有n个关键字(b树是n-1个),这些关键字不保存数据,只用来索引,所有数据都保存在叶子节点(b树是每个关键字都保存数据)。

  2. 所有的叶子结点中包含了全部关键字的信息,及指向含这些关键字记录的指针,且叶子结点本身依关键字的大小自小而大顺序链接。

  3. 所有的非叶子结点可以看成是索引部分,结点中仅含其子树中的最大(或最小)关键字。

  4. 通常在b+树上有两个头指针,一个指向根结点,一个指向关键字最小的叶子结点。

  5. 同一个数字会在不同节点中重复出现。

b+树对比b树的查询优势:

  1. b+树的中间节点不保存数据,所以磁盘页能容纳更多节点元素,更“矮胖”;

  2. b+树查询必须查找到叶子节点,b树只要匹配到即可不用管元素位置,因此b+树查找更稳定(并不慢);

  3. 对于范围查找来说,b+树只需遍历叶子节点链表即可,b树却需要重复地中序遍历;(基于范围查询是很普遍的)

关于二分查找和二叉树的理解:
(1)二分查找:即折半查找,优点是比较次数少,查找速度快,平均性能好;其缺点是要求待查表为有序表,且插入删除困难
(2)二叉查找树,它或者是一棵空树,或者若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值;
若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值; 它的左、右子树也分别为二叉排序树。
(3)平衡二叉树:避免数据全部在一端时的情况,强制转成平衡的。

1.5 sql优化

• MySQL慢查询怎么解决?使用explain优化sql和索引?• 查询语句不同元素(where、jion、limit、group by、having等等)执行先后顺序

1.5.1 explain介绍

explain后得到的结果主要有:id、select_type、table、type、possible_keys、key、key_len、rows、Extra。

需要强调rows是explain的核心指标,绝大部分rows小的语句执行一定很快。所以优化语句基本上都是在优化rows。

另一个explain的重要指标是type,一般要求达到range以上,最好能达到ref。

其它重点列的简单解释如下:

  • select_type:表示 SELECT 的类型,常见的取值有

    • SIMPLE:简单表,即不使用表连接或者子查询、• PRIMARY:主查询,即外层的查询、​• UNION:UNION 中的第二个或者后面的查询语句、​• SUBQUERY:子查询中的第一个 SELECT。

  • table:输出结果集的表。

  • rows:扫描行的数量。

  • type:表示表的连接类型,性能由好到差的连接类型为

    • system(表中仅有一行,即常量表)• const(单表中最多有一个匹配行,例如 primary key 或者 unique index)• eq_ref(对于前面的每一行,在此表中只查询一条记录,简单来说,就是多表连接中使用 primary key 或者 unique index)• ref(与 eq_ref 类似,区别在于不是使用 primary key 或者 unique index,而是使用普通的索引)• ref_or_null(与 ref 类似,区别在于条件中包含对 NULL 的查询)• index_merge(索引合并优化)• unique_subquery(in的后面是一个查询主键字段的子查询)• index_subquery(与 unique_subquery 类似,区别在于 in 的后面是查询非唯一索引字段的子查询)• range (单表中的范围查询)• index(对于前面的每一行,都通过查询索引来得到数据)• all(对于前面的每一行,都通过全表扫描来得到数据)

  • possible_keys:表示查询时,可能使用的索引。

  • key:表示实际使用的索引。

  • key_len:索引字段的长度。

  • Extra:执行情况的说明和描述。

1.5.2 慢查询优化

  1. 先运行看看是否真的很慢,注意设置SQL_NO_CACHE

  2. where条件单表查,锁定最小返回记录表。这句话的意思是把查询语句的where都应用到表中返回的记录数最小的表开始查起,单表每个字段分别查询,看哪个字段的区分度最高。

  3. explain查看执行计划,是否与1预期一致(从锁定记录较少的表开始查询)

  4. order by limit 形式的sql语句让排序的表优先查

  5. 了解业务方使用场景

  6. 加索引时参照建索引的几大原则

  7. 观察结果,不符合预期继续从1分析

可以参考:https://tech.meituan.com/2014/06/30/mysql-index.html

1.6 数据库崩溃恢复

• 数据库崩溃时事务的恢复机制(REDO日志和UNDO日志)?

InnoDB拥有内部恢复机制,假如数据库崩溃了,InnoDB通过从最后一个时间戳开始运行日志文件,来尝试修复数据库。大多数情况下会修复成功,而且整个过程是透明的。即InnoDB实现了一套完善的崩溃恢复机制,保证在任何状态下(包括在崩溃恢复状态下)数据库挂了,都能正常恢复,这个是与文件系统最大的差别。

崩溃恢复:用户修改了数据,并且收到了成功的消息,然而对数据库来说,可能这个时候修改后的数据还没有落盘,如果这时候数据库挂了,重启后,数据库需要从日志中把这些修改后的数据给捞出来,重新写入磁盘,保证用户的数据不丢。这个从日志中捞数据的过程就是崩溃恢复的主要任务,也可以成为数据库前滚。当然,在崩溃恢复中还需要回滚没有提交的事务,提交没有提交成功的事务。由于回滚操作需要undo日志的支持,undo日志的完整性和可靠性需要redo日志来保证,所以崩溃恢复先做redo前滚,然后做undo回滚

- redo日志:现代数据库都需要写redo日志,例如修改一条数据,首先写redo日志,然后再写数据。在写完redo日志后,就直接给客户端返回成功。
- undo日志:数据库还提供类似撤销的功能,当你发现修改错一些数据时,可以使用rollback指令回滚之前的操作。这个功能需要undo日志来支持。
- innodb_fast_shutdown:这个默认值=1,表示在MySQL关闭的时候,仅仅把日志和数据刷盘。= 0。这个表示在MySQL关闭的时候,执行slow shutdown,不但包括日志的刷盘,数据页的刷盘,还包括数据的清理(purge),ibuf的合并,buffer pool dump以及lazy table drop操作。 = 2时表示关闭的时候,仅仅日志刷盘,其他什么都不做,就好像MySQL crash了一样。 这个参数值越大,MySQL关闭的速度越快,但是启动速度越慢,相当于把关闭时候需要做的工作挪到了崩溃恢复上。

恢复方法:

一旦确定MySQL因为InnoDB表损坏无法启动时,就可以按照以下5步进行修复:
1.编辑/etc/my.cnf文件,加入如下行:
innodb_force_recovery = 4
2.这时就可以重新启动数据库了,在innodb_force_recovery配置的作用,所有的插入与更新操作将被忽略;
3.导出所有的数据表;
4.关闭数据库并删除所有数据表文件及目录,再运行 mysql_install_db来创建MySQL默认数据表;
5.在/etc/my.cnf中删除innodb_force_recovery这一行,再启动MySQL(这时MySQL正常启动);
6.从第3步备份的文件中恢复所有的数据。

innodb_force_recovery可以设置为1-6,大的数字包含前面所有数字的影响。当设置参数值大于0后,可以对表进行select,create,drop操作,但insert,update或者delete这类操作是不允许的。 
1(SRV_FORCE_IGNORE_CORRUPT):忽略检查到的corrupt页。
2(SRV_FORCE_NO_BACKGROUND):阻止主线程的运行,如主线程需要执行full purge操作,会导致crash。
3(SRV_FORCE_NO_TRX_UNDO):不执行事务回滚操作。
4(SRV_FORCE_NO_IBUF_MERGE):不执行插入缓冲的合并操作。
5(SRV_FORCE_NO_UNDO_LOG_SCAN):不查看重做日志,InnoDB存储引擎会将未提交的事务视为已提交。
6(SRV_FORCE_NO_LOG_REDO):不执行前滚的操作。

 

1.7 主从复制

• 数据库的读写分离如何实现?• 主从复制,主从复制分析的 7 个问题、主从复制

原理:

复制过程中一个服务器充当主服务器,而一个或多个其它服务器充当从服务器。mysql复制基于主服务器在二进制日志(binlog)中跟踪所有对数据库的更改(更新、删除等等)。因此,要进行复制,必须在主服务器上启用二进制日志。每个从服务器从主服务器接收主服务器已经记录到的二进制日志,获取日志信息更新。通过设置在Master上的binlog,使其处于打开状态;Slave通过一个I/O线程从Master上读取binlog,然后传输到Slave的中继日志(relaylog)中,然后使用SQL线程读取中继日志,并应用到自身数据库中,从而实现主从数据同步功能。

即mysql主从复制需要三个线程:
1. 主:binlog线程——记录下所有改变了数据库数据的语句,放进master上的binlog中;
2. 从:io线程——在使用start slave 之后,负责从master上拉取 binlog 内容,放进 自己的relay log中;
3. 从:sql执行线程——执行relay log中的语句;

 

1.8 读写分离

方式1:通过MyCAT 实现读写分离

方式2:通过MaxScale实现读写分离 

 

1.9 分库分表

• 数据库优化,最左原则啊,水平分表,垂直分表

基础概念

  • 分表,能够解决单表数据量过大带来的查询效率下降的问题;

  • 分库,面对高并发的读写访问,当数据库master服务器无法承载写操作压力时,不管如何扩展slave服务器,此时都没有意义。此时,则需要通过数据分库策略,提高数据库并发访问能力。

  • 优点,分库、分表技术优化了数据存储方式,有效减小数据库服务器的负担、缩短查询响应时间。

  • 数据分库、分表存储场景条件

    • 关系型数据库

    • 主从架构(master-slave)

    • 单表数据量在百万、千万级别

    • 数据库面临极高的并发访问

  • 分库、分表实现策略

    • 关键字取模,实现对数据访问进行路由

 

1.10 union/union all?

UNION在进行表链接后会筛选掉重复的记录,

UNION ALL只是简单的将两个结果合并后就返回,

从效率上说,UNION ALL 要比UNION快很多,所以,如果可以确认合并的两个结果集中不包含重复的数据的话,那么就使用UNION ALL。

-- mysql实现full join:
select * from t1 left join t2 on t1.id = t2.id
union 
select * from t1 right join t2 on t1.id = t2.id;

 

还有就是写SQL了

#补充今日去面试的sql面试题,有兴趣的可以试试


1. 有tb_student表,数据如下:
name    course        score
张三    语文        71
李四    语文        81
王五    数学        90
李四    数学        85
王五    语文        75
张三    数学        72
(1) 写一条sql按学生的总成绩,从高到低排名
(2) 写一条sql查询所有课程都大于80的学生名字

2. 有tb_score表,数据如下
name    course        score
张三       语文            71
王五       数学            75
张三       语文            71
(1) 写sql去除表中信息相同的冗余数据


#常用MYSQL内置方法:

-- 零、将查询结果连接:CONCAT
SELECT CONCAT(CURDATE(), ',', CURDATE());

-- 一、将查询结果合并: UNION, UNION ALL (允许重复)
SELECT DATE_SUB(CURDATE(), INTERVAL 3 DAY)
UNION ALL
SELECT DATE_ADD(NOW(), INTERVAL 3 DAY);

-- 二.格式化时间: DATE_FORMAT
SELECT DATE_FORMAT(CURDATE(), '%Y-%m-%d');
SELECT DATE_FORMAT(now(), '%Y-%m-%d %H:%i:%S');

-- 三.时间加减: DATE_SUB, DATE_ADD

-- 2.1当前日期减三个天,三月,三年
SELECT DATE_SUB(CURDATE(), INTERVAL 3 DAY)
UNION ALL
SELECT DATE_SUB(CURDATE(), INTERVAL 3 MONTH)
UNION ALL
SELECT DATE_SUB(CURDATE(), INTERVAL 3 YEAR);

-- 2.2 当前时间加三个天,三月,三年
SELECT DATE_ADD(NOW(), INTERVAL 3 DAY)
UNION ALL
SELECT DATE_ADD(NOW(), INTERVAL 3 MONTH)
UNION ALL
SELECT DATE_ADD(NOW(), INTERVAL 3 YEAR);

-- 2.3 两个时间相差多少秒,分,时,日,月,年
select TIMESTAMPDIFF(WEEK,'2018-07-30','2018-09-14')
UNION ALL
select TIMESTAMPDIFF(DAY,'2018-07-30','2018-09-14')
UNION ALL
select TIMESTAMPDIFF(MONTH,'2018-07-30','2018-09-14')


-- 三、将查询结果用逗号相连: GROUP_CONCAT
SELECT GROUP_CONCAT(column1) FROM tbl

-- 四、

-- >将查询结果合并后用逗号相连:
SELECT
  GROUP_CONCAT(tmpConcatName) AS concatName
FROM
  (
    SELECT
      DATE_SUB(CURDATE(), INTERVAL 3 DAY) AS tmpConcatName
    UNION ALL
    SELECT
      DATE_ADD(NOW(), INTERVAL 3 DAY)
  ) AS tmpTbl

-- >将查询结果格式化并合并后用逗号相连:
SELECT
  GROUP_CONCAT(tmpConcatName) AS concatName
FROM
  (
    SELECT
      DATE_FORMAT(DATE_SUB(CURDATE(), INTERVAL 3 DAY), '%Y-%m-%d' ) AS tmpConcatName
    UNION ALL
    SELECT
      DATE_FORMAT(DATE_ADD(CURDATE(), INTERVAL 3 DAY), '%Y-%m-%d' ) AS tmpConcatName
  ) AS tmpTbl


-- 五、字符串操作
select LOWER('RGFRG')--大写字母变为小写字母
select UPPER('ggfgrt')--小写字母变为大写字母
select LTRIM()--去掉左侧字符空格
select RTRIM()--去掉字符串右侧空格
select LEFT(Title,5)from News--从某列中左侧起截取多少长度的字符串
select RIGHT(Title,5)from News--从某列中右侧起截取多上长度的字符串
select SUBSTRING(Title,3,5) from News--从某一列中第几个字符开始截取几个字符
select REVERSE (Title) from News --翻转某一列
select CHARINDEX('中国',Title)from News --查询目标内容在指定区域有没有出现以及出现位置
select REPLACE(Title,'中国','美国')from News--替换字符串。例搜索关键字并明显标注
select STUFF(Title,3,4,'chine') from News
-- 六、其他函数
select CEILING (RAND()*10)--随机生成-1之间的数字,可以以乘以的方式增大随机数范围
select LEN('chine')--取字符串长度
select GETDATE()--获取当前时间
select YEAR(sbirthday)from student--取时间年份
select month(sbirthday)from student--取日期时间月份
select day(sbirthday)from student3--取时间天
select datepart(yy,sbirthday)from student4-- yy,mm,dd分别代表年月日
select CAST ('123'as int)--转换字符串

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章