[数据库]数据库面试基本知识点《按模块》

原文链接:https://www.cnblogs.com/wenxiaofei/p/9853682.html

个人记录,仅做学习。。。。。

第一部分 基本概念

1 主键、外键、超键、候选键

超键: 在关系中能唯一标识元祖的属性集称为关系模式的超键。一个属性可以作为一个超键,多个属性组合也可以作为一个超键。超键包含候选键和主键。

候选键: 是最小超键,即没有冗余元素的超键

主键: 数据库表对储存数据对象予以唯一和完整标识的数据列或属性的组合。一个数据列只能有一个主键,且主键的取值不能缺失,即不能为空值(Null)。

外键: 在一个表中存在的另一个表的主键称为此表的外键。

2 为什么用自增列作为主键

  • 如果我们定义了主键(PRIMARY KEY),那么InnoDB会选择主键作为聚集索引。
  • 如果没有显式定义主键,则InnoDB会选择第一个不包含有NULL值的唯一索引作为主键索引
  • 如果也没有这样的一个唯一索引,则InnoDB会选择内置6字节长的ROWID作为隐含的聚集索引(ROWID随着行记录的写入而主键递增,这个ROWID不像ORACL的ROWID那样可引用,是隐含的)
  • 数据记录本身被存于主索引(一颗B+Tree)的叶子节点上。这就要求同一个叶子节点内(大小为一个内存页或磁盘页)的各条数据记录按主键顺序存放,因此每当有一条新的记录插入时,MySQL会根据其主键将其插入适当的节点和位置,如果页面达到装载因子(InnoDB默认为15/16),则开辟一个新的页(节点)
  • 如果使用非自增主键(如身份证号和学号等),由于每次插入主键的值近似于随机,因此每次新纪录都要被插到现有索引页的中间某个位置,此时MySQL不得不为了将新纪录插到合适的位置而移动数据,甚至目标页面可能被回写到磁盘上而从缓存中清掉,此时又要从磁盘上读回来,这增加了很多开销,同时频繁的移动、分页操作造成了大量的碎片,得到了不够紧凑的索引结构,后续不得不通过OPTIMIZE TABLE 来重建表并优化填充页面。

3 触发器的作用?

触发器是一种特殊的存储过程,主要是通过事件来触发而被执行的。它可以强化约束,来维护数据的完整性和一致性,可以跟踪数据库内的操作从而不允许味精许可的更新和变化,可以联级运算(如某表上的触发器包含对另一个表的数据操作,而该操作又会导致该表触发器被触发)。

4 什么是存储过程?用什么来调用?

存储过程是一个预编译的SQL语句,优点是允许模块化的设计,就是说只需创建一次,以后在该程序中就可以调用多次。如果某次操作需要执行多次SQL,使用存储过程比单纯SQL语句执行要快。

调用:
(1) 可以用一个命令对象来调用存储过程
(2) 可以供外部程序调用,比如:Java程序

5 存储过程的优缺点?

优点:
(1)存储过程是预编译过的,执行效率高
(2)存储过程的代码直接存放于数据库中,通过存储过程名直接调用,减少网络通讯
(3)安全性高,执行存储过程需要有一定权限的用户
(4)存储过程可以重复使用,可以减少数据库开发人员的工作量

缺点: 移植性差

6 存储过程与函数的区别与联系

原文链接:https://www.cnblogs.com/karrya/p/11600130.html

函数:
函数与存储过程相似,也是数据库中存储的已命名PL-SQL程序块。
函数的主要特征是它必须有一个返回值,通过return 来指定函数的返回类型。
在函数的任何地方可以通过return expression 语句从函数返回,返回类型必须和声明的返回类型一致。

函数和存储过程的优点

(1)共同使用的代码可以只需要被编写一次,而被需要该代码的任何程序(.net, c++.java,也可以使用DLL库)
(2)这种模块化的方法使得一个复杂的问题、大的程序逐步简化成几个简单的、小的程序部分,进行分别编写,因此程序的结构更加清晰,简单,也容易实现。
(3)可以在各个开发者之间提供处理数据、控制流程、提示信息等方面的一致性。
(4)节省内存空间。它们以一种压缩的形式被存储在外存中,当被调用时才被放入内存进行处理。而且多个用户在调用同一个存储过程或函数时,只需要加载一次即可。
(5)提高数据的安全性和完整性。通过把一些对数据的操作方法放到存储过程或函数中,就可以通过是否授予用户有执行该语句的权限,来限制某些用户对数据库进行这些操作。

函数和存储过程的区别

(1)存储过程 用户在数据库中完成特定操作或者任务(如插入、删除等)函数 用于返回特定的数据。
(2) 存储过程声明用procedure,函数用function。
(3)存储过程不需要返回类型, 函数 必须要返回类型。
(4)存储过程可作为独立的pl-sql执行, 函数不能作为独立的pl-sql执行,必须作为表达式的一部分。
(5)存储过程只能通过out和in/out 来返回值,函数除了ut和in/out 外,还可以使用return返回值
(6)sql语句(DML或SELECT)中不可调用存储过程,而函数可以。

适用场合

(1)如果需要返回多个值和不返回值,就使用存储过程; 如果只需要返回一个值,就使用函数。
(2)存储过程 一般用于执行一个指定的动作, 函数 一般用于计算和返回一个值。

(3)可以在SQL内部调用函数来完成复杂的计算问题,但不能调用存储过程。

存储过程与存储函数的区别和联系

相同点:
(1) 创建语法结构相似, 都可以携带多个传入参数和传出参数
(2) 都是一次编译,多次执行

不同点:
(1)存储过程定义关键字用procedure, 函数定义用function
(2)存储过程中不能用return 返回值, 但函数可以,而且函数中必须有return 子句
(3)执行方式略有不同,存储过程的执行方式用两种(一是使用execute ,二是使用begin和end)。
函数除了存储过程的两种方式外,还可以当作表达式使用,例如放在select中(select f1()from dual)

总结:如果只有一个返回值,用存储函数,否则,一般用存储过程。


7 什么叫视图?游标是什么?

视图:
是一种虚拟的表,具有和物理表相同的功能。
可以对视图进行增、改、查操作,视图通常是有一个表或者多个表的行或列的子集。
对视图的修改会影响基本表,它使得我们获取数据更容易,相比多表查询。

游标:
是对查询出来的结果集作为一个单元来有效的处理。
游标可以定在该单元中的特定行,从结果集的当前行检索一行或多行,可以对结果集当前行做修改。
一般不使用游标,但是需要逐条处理数据的时候,游标显得十分重要。

8 视图的优缺点

优点:
(1)方便对数据库的访问,因为视图可以有选择性的选择数据库里的一部分
(2)用户通过简单的查询可以从复杂查询里得到结果
(3)维护数据的独立性,试图可以从多个表检索数据
(4)对于相同的数据可产生不同的视图

缺点:
性能:
查询视图时,必须把视图的查询转化成对基本表的查询,如果这个视图是由一个复杂的多表查询所定义,那么就无法更改数据

9 drop, truncate, delete 区别

drop直接删掉表
truncate 删除表中数据,再插入时自增长id又从1开始
delete删除表中数据,可以加where 子句

  • (1) delete 语句执行删除的过程是每次从表中删除一行,并且同时将该行的删除操作作为事务记录在日志中保存以便进行回滚操作。
    truncate table 则一次性的从表中删除所有的数据并不把单独的删除操作记录记入日志保存,删除行是不能恢复的,并且在删除的过程中不会激活与表有关的删除触发器,执行速度快。

  • (2)表和索引所占空间
    当表被truncate 后,这个表和索引所占用的空间会恢复到初始大小
    delete操作不会减少表或索引所占用的空间
    drop语句将表所占用的空间全释放掉

  • (3) 就速度,一般而言,drop > truncate > delete

  • (4)应用范围
    truncate 只能对table,
    delete 可以是table和view

  • (5)truncate 和delete 只删除数据, drop则删除整个表(结构和数据)

  • (6) truncate 是不带where 的delete:只删除数据,而不删除表的结构(定义)
    drop语句将删除表的结构被依赖的约束(constrain),触发器(trigger),索引(index);依赖于该表的存储过程/函数将被保留,但其状态会变为:invalid。

  • (7)delete语句为DML(data maintain Language)
    这个操作将会被放到rollback segment 中,事务提交后才生效,如果有相应的tigger,执行的时候将被触发。

  • (8)truncate、drop是DDL(data define language)
    操作立即生效,原数据不放到rollback segment中, 不能回滚

  • (9)在没有备份情况下,谨慎使用drop与truncate。
    要删除部分数据行采用delete且注意结合where来约束影响范围,回滚段要足够大。
    要删除表用drop
    若想保留表而将表中数据删除,如果与事务无关,用truncate即可实现,如果和事务有关,或想触发trigger,还是用delete。

  • (10)truncate table 表名, 速度快,而且效率高,因为:
    truncate table 在功能上与不带where子句的delete语句相同,二者均删除表中的全部行。
    但truncate table 比delete 速度快,且使用的系统和事务日志资源少
    delete 语句每次删除一行,并在事务日志中为所删除的每行记录一项
    truncate table 通过释放存储表数据所用的数据页来删除数据,并且只在事务日志中记录页的释放。

  • (11) TRUNCATE TABLE 删除表中的所有行,但表结构及其列、约束、索引等保持不变。新行标识所用的计数值重置为该列的种子。如果想保留标识计数值,请改用 DELETE。如果要删除表定义及其数据,请使用 DROP TABLE 语句。

  • (12) 对于由 FOREIGN KEY 约束引用的表,不能使用 TRUNCATE TABLE,而应使用不带 WHERE 子句的 DELETE 语句。由于 TRUNCATE TABLE 不记录在日志中,所以它不能激活触发器。

总结
1、在速度上,一般来说,drop> truncate > delete。
2、在使用drop和truncate时一定要注意,虽然可以恢复,但为了减少麻烦,还是要慎重。
3、如果想删除部分数据用delete,注意带上where子句,回滚段要足够大;
如果想删除表,当然用drop;
如果想保留表而将所有数据删除,如果和事务无关,用truncate即可;
如果和事务有关,或者想触发trigger,还是用delete;
如果是整理表内部的碎片,可以用truncate跟上reuse stroage,再重新导入/插入数据。

10 什么是临时表,临时表什么时候删除?

临时表可以手动删除
DROP TEMPORARY TABLE IF EXISTS temp_tb;

临时表只在当前连接可见,当关闭连接时,MySQL会自动删除表并释放所有空间。
因此在不同的连接中可以创建同名的临时表,并且操作属于本连接的临时表。

创建临时表的语法与创建表语法类似,不同之处是增加关键字 TEMPORARY
如:CREATE TEMPORARY TABLE tmp_table (
NAME VARCHAR (10) NOT NULL,
time date NOT NULL
);
select * from tmp_table;

11 非关系型数据库和关系型数据区别,优势比较?

非关系型数据库的优势:
性能:NOSQL 是基于键值对的,可以想象成表中的主键和值的对应关系,而且不需要经过SQL层的解析,所以性能非常高
可拓展性:同样也是因为基于键值对,数据之间没有耦合性,所以非常容易水平拓展

关系型数据库的优势:

复杂查询:可以用SQL语句方便的在一个表以及多个表之间做非常复杂的数据查询
事务支持:使得对于安全性能很高的数据访问要求得以实现

其它:
(1)对于这两类数据库,对方的优势就是自己弱势,反之亦然
(2)NOSQL 数据库慢慢开始具备SQL数据库的一些复杂查询功能,比如MongoDB
(3)对于事务的支持也可以用一些系统级的原子操作来实现例如乐观锁之类的方法来曲线救国,比如Redis set nx。

12 数据库范式,根据某个场景设计数据表?

目前关系数据库有六种范式:第一范式(1NF)、第二范式(2NF)、第三范式(3NF)、巴斯-科德范式(BCNF)、第四范式(4NF)和第五范式(5NF,又称完美范式)

13 什么是内连接、外连接、交叉连接、笛卡尔积等?

内连接:只连接匹配的行
左外连接: 包含左边表的全部行(不管右边的表中是否存在与他们匹配的行),以及右边表中全部匹配的行
右外连接:包含右边表的全部行(不管左边的表中是否存在与它们匹配的行),以及左边表中全部匹配的行

例如1:
SELECT a.,b. FROM luntan LEFT JOIN usertable as b ON a.username=b.username

例如2:
SELECT a.,b. FROM city as a FULL OUTER JOIN user as b ON a.username=b.username

全外连接:包含左右两个表的全部行,不管另外一边的表中是否存在与它们匹配的行
交叉连接:生成笛卡尔积- 它不使用任何匹配或者选取条件,而是直接将一个数据源中的每个行与另一个数据源的每个行都一一匹配

例如:
SELECT type,pub_name FROM titles CROSS JOIN publishers ORDER BY type

14 varchar 和char 的使用场景?

  • (1)char 的长度是不可变的,而varchar的长度是可变的
    定义一个char[10] 和 varchar[10]
    如果存进去的是“csdn”,那么char所占的长度依然为19,除了字符“csdn”外,后面跟6个空格,
    varchar就立马马长度变为4了,去数据的时候,char类型的要用trim()去掉多余的空格,而varchar是不需要的

  • (2)char的存取速度要比varchar要快得多,因为其长度固定,方便程序的存储与查找
    char也为此付出的是空间的代价,因为其长度固定,所以难免会有多余的空格占位符占据空间,可谓是1以空间换取时间效率。
    varchar是1以空间效率为首位。

  • (3)char的存储方式:对英文字符(ASCII)占用1个字节,对汉字占用2个字节
    varchar的存储方式是:对英文字符(ASCII)占用2个字节,对汉字也占用2个字节

  • (4)两者的存储数据都非unicode的字符数据。

15 SQL语言分类

SQL语言共分为四大类:
(1)数据查询语言DQL
(2)数据操纵语言DML
(3)数据定义语言DDL
(4)数据控制语言DCL

  • (1)数据查询语言DQL
    数据查询语言DQL基本机构是由SELECT子句,FROM子句,WHERE子句组成的查询块:
    SELECT
    FROM
    WHERE

  • (2)数据操纵语言DML
    数据操纵语言DML 主要有三种形式:
    一是插入:INSERT
    二是更新:UPDATE
    三是删除:DELETE

  • (3)数据定义语言DDL

数据定义语言DDL用来创建数据库中的各种对象–表、视图、索引、同义词、聚簇等如CREATE TABLE/VIEW/INDEX/SYN/CLUSTER

DDL操作是隐性提交的,不能rollback

  • (4)数据控制语言DCL
    数据控制语言DCL 用来授予或回收访问数据库的某项特权,并控制数据库操纵事务发生的时间及效果,对数据库实行监视等。如:
    一.GRANT :授权
    二.ROLLBACK[WORK] TO [SAVEPOINT]:回退到某一点。
    —回滚:ROLLBACK; 回滚命令使数据库状态回到上次最后提交的状态,其格式为:SQL>ROLLBACK
    三. COMMIT[WORK]:提交

在数据库的插入、删除和修改操作时,只有当事务在提交到数据库时才算完成。
在事务提交前,只有操作数据库的这个人才能有权看到所做的事情,别人自幼在最后提交完成后才可以看到。
提交数据有三种类型:显式提交、隐式提交及自动提交。
一:显式提交
用COMMIT命令直接完成的提交为显式提交。其格式为:
SQL>COMMIT
二:隐式提交
用SQL命令间接完成的提交为隐式提交。这些命令是:
ALTER,ADUIT,COMMIT,CONNECT,CREATE,DISCONNECT, DROP, EXIT, GRANT,NOAUDT,QUIT,REVOKE,RENAME
三. 自动提交
若把AUTOCOMMIT设置为ON,则在插入、修改、删除语句执行后,系统将自动进行提交,这就是自动提交。其格式为:
SQL>SET AUTOCOMMIT ON

16 like % 和 - 的区别

通配符的分类:
% 百分号通配符:表示任何字符出现任意次数(可以是0次)
_ 下划线通配符:表示只能匹配单个字符,不能多也不能少,就是一个字符
like 操作符:LIKE作用是指示mysql后面的搜索模式是利用通配符而不是直接相等匹配进行比较

注意: 如果在使用like操作符时,后面的没有使用通用匹配符效果是和=一致的,SELECT * FROM products WHERE products.prod_name like ‘1000’;
只能匹配的结果为1000,而不能匹配像JetPack 1000这样的结果.

%通配符使用: 匹配以"yves"开头的记录:(包括记录"yves") SELECT FROM products WHERE products.prod_name like ‘yves%’;
匹配包含"yves"的记录(包括记录"yves") SELECT FROM products WHERE products.prod_name like ‘%yves%’;
匹配以"yves"结尾的记录(包括记录"yves",不包括记录"yves ",也就是yves后面有空格的记录,这里需要注意) SELECT * FROM products WHERE products.prod_name like ‘%yves’;

通配符使用: SELECT FROM products WHERE products.prod_name like ‘_yves’; 匹配结果为: 像"yyves"这样记录.
SELECT FROM products WHERE products.prodname like 'yves’; 匹配结果为: 像"yvesHe"这样的记录.(一个下划线只能匹配一个字符,不能多也不能少)

注意事项:

注意大小写,在使用模糊匹配时,也就是匹配文本时,mysql是可能区分大小的,也可能是不区分大小写的,这个结果是取决于用户对MySQL的配置方式.如果是区分大小写,那么像YvesHe这样记录是不能被"yves__“这样的匹配条件匹配的.
注意尾部空格,”%yves"是不能匹配"heyves "这样的记录的.
注意NULL,%通配符可以匹配任意字符,但是不能匹配NULL,也就是说SELECT * FROM products WHERE products.prod_name like '%;是匹配不到products.prod_name为NULL的的记录.

技巧与建议:

正如所见, MySQL的通配符很有用。但这种功能是有代价的:通配符搜索的处理一般要比前面讨论的其他搜索所花时间更长。这里给出一些使用通配符要记住的技巧。

  • 不要过度使用通配符。如果其他操作符能达到相同的目的,应该 使用其他操作符。
  • 在确实需要使用通配符时,除非绝对有必要,否则不要把它们用 在搜索模式的开始处。把通配符置于搜索模式的开始处,搜索起 来是最慢的。
  • 仔细注意通配符的位置。如果放错地方,可能不会返回想要的数.

17 count(*)、count(1)、count(column)的区别

count() 对行的数目进行计算,包含NULL
count(column)对特定的列的值具有的行数进行计算,不包含NULL值
count()还有一种使用方式,count(1)这个用法和count(
)的结果是一样的

性能问题:
(1)任何情况下SELECT COUNT() FROM tablename 是最优选择
(2)尽量减少SELECT COUNT(
) FROM tablename WHERE COL = ‘value’这种查询
(3)杜绝SELECT COUNT(COL) FROM tablename WHERE COL2 = ‘value’的出现
如果表没有主键,那么count(1)比count(*)快。

如果有主键,那么count(主键,联合主键)比count(*)快。

如果表只有一个字段,count(*)最快。

count(1)跟count(主键)一样,只扫描主键。count(*)跟count(非主键)一样,扫描整个表。明显前者更快一些。

18 最左前缀原则

解释一下最左前缀原则: 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 什么是索引?

数据库索引,是数据库管理系统中一个排序的数据结构,索引的实现通常使用B数及其变种B+树
在数据之外,数据库系统还维护着满足特定查找算法的数据结构,
这些数据结构以某种方式引用(指向)数据,这样就可以在这些数据结构上实现高级查找算法。这种数据结构,就是索引。

2 索引的作用?

索引作用: 协助快速查询,更新数据表中数据。
为表设置索引是要付出代价的:
一是增加了数据库的存储空间
二是在插入和修改数据时要话费较多的时间(因为索引也要随之变动)

3 索引的优点缺点是什么?

创建索引可以大大提高系统的性能(优点)
(1)通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性
(2)可以大大加快数据的检索速度,这也是创建索引的最主要的原因
(3)可以加速表和表之间的连接,特别是在实现数据的参考完整性方面特别有意义
(4)在使用分组和排序子句进行数据检索时,同样可以显著减少查询中分组和排序的时间
(5)通过使用索引,可以在查询的过程中,使用优化隐藏器,提高系统的性能

增加索引也有许多不利的方面(缺点)
(1)创建索引和维护索引要耗费时间,这种时间随着数据量的增加而增加
(2)索引需要占物理空间,除了数据表占数据空间之外,每一个索引还要占一定的物理空间,如果要建立聚簇索引,那么需要的空间就会更大。
(3)当对表中的数据进行增加、删除和修改的时候,索引也要动态的维护,这样就降低了数据的维护速度。

4 哪些列适合建立索引,哪些不适合建索引?

索引是建立在数据库表中的某些列的上面。在创建索引的时候,应该考虑在哪些列上可以创建索引,哪些列上不能创建索引。

一般来说,应该在这些列上创建索引:
(1)在经常需要搜索的列上,可以加快搜索的速度
(2)在作为主键的列上,强制该列的唯一性和组织表中数据的排列结构
(3)在经常用在连接的列上,这些列主要是一些外键,可以加快连接的速度
(4)在经常需要根据范围进行搜索的列上创建索引,因为索引已经排序,其指定的范围是连续的
(5)在经常需要排序的列上创建索引,因为索引已经排序,这样查询可以利用索引的排序,加快排序查询时间
(6)在经常使用在WHERE子句中的列上面创建索引,加快条件的判断速度

对于有些列不应该创建索引:
(1)对于那些在查询中很少使用或者参考的列不应该创建索引。
这是因为,既然这些列很少使用到,因此有索引或者无索引,并不能提高查询速度。
相反,由于增加了索引,反而降低列系统的维护速度和增大了空间需求

(2)对于那些只有很少数据值的列也不应该增加索引
这是因为,由于这些列的取值很少,例如人事表的性别列,在查询的结果中,结果集的数据行占列表中数据行的很大比例,
即需要在表中搜索的数据行的比例很大。增加索引,并不能明显加快检索速度。

(3)对于那些定义为text,image 和 bit 数据类型的列不应该增加索引
这是因为,这些列的数据量要么相当大,要么取值很少

(4)当修改性能远远大于检索性能时,不应该创建索引
这是因为,修改性能和检索性能是互相矛盾的。
当增加索引时,会提高检索性能,但是会降低修改性能。当减少索引时,会提高修改性能,降低检索性能。
因此,当修改性能远远大于检索性能时,不应该创建索引。

5 什么样的字段适合建索引?

唯一、不为空、经常被查询的字段

6 MySQL B+Tree 和 Hash 索引的区别?

Hash 索引和B+树索引的特点

  • Hash 索引结构的特殊性,其检索效率非常高,索引的检索可以一次定位
  • B+树索引需要从根节点到枝节点,最后才能访问到页节点这样的多次IO访问

为什么不都用Hash索引而使用B+ 树索引?

  • (1)Hash索引仅仅能满足“=” , “IN” 和 “”查询,不能使用范围查询,
    因为经过相应的Hash算法处理之后的Hash值的大小关系,并不能保证和Hash运算前完全一样

  • (2)Hash 索引无法被用来避免数据的排序操作,
    因为Hash值的大小关系并不一定和Hash运算前的键值完全一样

  • (3)Hash索引不能利用部分索引键查询,
    对于组合索引,Hash索引在计算Hash值的时候是组合索引键合并后再一起计算Hash值,而不是单独计算Hash值,
    所以通过组合索引的前面一个或者几个索引键进行查询的时候,Hash索引也无法被利用

  • (4)Hash索引在任何时候都不能避免表扫描,
    由于不同索引键存在相同Hash值,所以即使取满足某个Hash键值的数据的记录条数,也无法从Hash索引中直接完成查询,还是要回表查询数据

  • (5)Hash索引遇到大量的Hash值相等的情况后性能并不一定就会比B+树索引高

补充:

(1)MySQL 中,只有HEAP/MEMORY 引擎才显示支持Hash索引。
(2)常用的InnoDB引擎中默认使用的是B+树索引,它会实时监控表上索引的使用情况,
如果认为建立哈希索引可以提高查询效率,则自动在内存中“自适应哈希索引缓冲区”建立哈希索引(在InnoDB中默认开启自适应哈希索引)
通过观察搜索模式,MySQL会利用index key 的前缀建立哈希索引,
如果一个表几乎大部分都在缓冲池中,那么建立一个哈希索引能够加快等值查询

B+树索引和哈希索引的明显区别是:
(1) 如果是等值查询,那么哈希索引明显有绝对优势,因为只需经过一次算法即可找到相应的键值;
当然了,这个前提是,键值都是唯一的,如果键值不是唯一的,就需要先找到该键所在位置,然后再根据链表往后扫描,直到找到相应的数据;
(2) 如果是范围查询检索,这时候哈希索引毫无用武之地了,
因为原先是有序的键值,经过哈希算法后,有可能变成不连续的了,就没办法再利用索引完成范围查询检索
同理,哈希索引没办法利用索引完成排序,以及like“XXX%” 这样的部分模糊查询(这种模糊查询,其实本质上也是范围查询)
(3) 哈希索引也不支持多列联合索引的最左匹配原则

(4)B+树索引的关键字检索效率比较平均,不像B树那样波动幅度大,在有大量重复键值情况下,哈希索引的效率也是极低的,因为存在所谓的哈希碰撞苏问题

(5) 在大多数场景下,都会有范围查询、排序、分组等查询特征,用B+树索引就可以了

7 B树和B+树的区别

B树,每个节点都存储key和data,所有节点组成这棵树,并且叶子节点指针为null,叶子节点不包含任何关键字信息。

B+树,所有的叶子节点中包含了全部关键字的信息,及指向含有这些关键字记录的指针,且叶子节点本身依关键字的大小自小而大的顺序链接,所有的非终端节点可以看成是索引部分,节点中仅含有其子树根节点中最大(或最小)关键字。(而B树的非终端节点也包含需要查找的有效信息)。

8 为什么说B+树比B树更适合实际应用中操作系统的文件索引和数据库索引?

  • 1 B+ 的磁盘读写代价更低
    B+的内部节点并没有指向关键字具体信息的指针,因此其内部节点相对B树更小。
    如果把所有同一内部节点的关键字存放在同一盘块中,那么盘块所能容纳的关键字数量也越多。
    一次性读入内存中的查找需要的关键字也就越多。相对来说IO读写次数也就降低了。

  • 2 B+tree 的查询效率更加稳定
    由于非终端结点并不是最终指向文件内容的结点,而只是叶子结点中关键字的索引。
    所以任何关键字的查找必须走一条从根节点到叶子结点的路。
    所有关键字查询的路径长度相同,导致每一个数据的查询效率相当。

9 聚集索引和非聚集索引区别

聚合索引(clustered index)

聚集索引表记录的排列顺序和索引的排列顺序一致,所以查询效率快。
只要找到第一个索引值记录,其余就连续性的记录在物理也一样连续存放。
聚集索引对应的缺点就是修改慢,因为为了保证表中记录的物理和索引顺序一致,在记录插入的时候,会对数据页重新排序。

聚集索引类似于新华字典中用拼音去查找汉字,拼音检索表与索引序列都是按照a~z排列的,就像相同的逻辑顺序与物理顺序一样,当你需要查找a, ai 两个读音的字,或者想一次寻找多个傻(sha)的同音字时, 也许往后翻几页,或紧接着下一行就得到结果了。

非聚合索引(nonclustered index)

非聚集索引 ** 指定了表中记录的逻辑顺序,但是记录的物理和索引不一定一致。**
两种索引都采用B+ 树结构,非聚集索引的叶子层并不和实际数据页相重叠,而采用叶子层包含一个指向表中的记录在数据页中的指针方式。
非聚集索引层次多,不会造成数据重排。

非 聚集索引类似在新华字典上通过偏旁部首来查询汉字,检索表也许是按照横、竖、撇来排列的,但是由于正文是a~z 的拼音顺序,
所以就类似于逻辑地址与物理地址的不对应。
同时适用的情况就在于分组,大数目的不同值,频繁更新的列中,这些情况即不适合聚集索引。

根本区别

聚集索引和非聚集索引的根本区别是表记录的排列顺序和索引的排列顺序是否一致。


第三部分:事务

1 什么是事务?

事务是对数据库中一系列操作进行统一的回滚或者提交的操作,主要用来保证数据的完整性和一致性。

2 事务四大特性(ACID) 原子性、一致性、隔离型、持久性?

  • 原子性(Atomicity)
    原子性是指事务所包含的所有操作要么全部成功,要么全部失败回滚,
    因此事务的操作如果成功就必须要完全应用到数据库,如果操作失败则不能对数据库有任何影响。

  • 一致性(Consistency)
    事务开始前和结束后,数据库的完整性约束没有被破坏。比如A向B转账,不可能A扣了钱,B却没有收到

  • 隔离性(Isolation)
    隔离性是当多个用户并发访问数据库时,比如操作同一张表时,数据库为每一个用户开启的事务,不可能被其他事务的操作所干扰,多个并发事务之间要相互隔离。
    同一时间,只允许一个事务请求同一数据,不同的事务之间彼此没有任何干扰。
    比如A正在从一张银行卡中取钱,在A取钱的过程结束前,B不能向这张卡转账。

  • 持久性 (Durability)
    持久性是指一个事务一旦被提交了,那么对数据库中的数据的改变就是永久性的,
    即便是在数据库系统遇到故障的情况下也不会丢失提交事务的操作。

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

从理论上来说,事务应该彼此完全隔离,以避免并发事务所导致的问题,
然后,那样会对性能产生极大的影响,因此事务必须按顺序运行,
在实际开发中,为了提升性能,事务会以较低的隔离级别运行,事务的隔离级别可以通过隔离事务属性指定。

  • 事务的并发问题
    (1)脏读
    事务A读取了事务B更新的数据,然后B回滚操作,那么A读取到的数据是脏数据

(2)不可重复读
事务A多次读取同一数据,事务B在事务A多次读取的过程中,对数据做了更新并提交,导致事务A多次读取同一数据时,结果导致本事务先后两次读到的数据结果会不一致。

(3)幻读
幻读解决了不重复读,保证了同一个事务里,查询的结果都是事务开始时的状态(一致性)。
例如:事务T1对一个表中所有的行的某个数据项做了从“1” 修改为“2”的操作,
这时事务T2又对这个表中插入了一行数据,而这个数据项的数值还是为“1”并且提交给数据库。
而操作事务T1的用户如果再查看刚刚修改的数据,会发现还有跟没修改的一样,
其实这行是从事务T2中添加的,就好像产生幻觉一样,这就是发生了幻读。

小结:不可重复读和幻读很容易混淆,不可重复读侧重于修改,幻读侧重于新增或删除。
解决不可重复读的问题只需锁住满足条件的行,解决幻读需要锁表。

  • 事务的隔离级别
    (1)读未提交
    另一个事务修改了数据,但尚未提交,而本事务中的SELECT会读到这些未被提交的数据脏读

(2)不可重复读
事务A多次读取同一数据,事务B在事务A多次读取的过程中,对数据作了更新并提交,
导致事务A多次读取同一数据时,结果因此本事务先后两次读到的数据结果会不一致。

(3)可重复读
在同一个事务里,SELECT的结果是事务开始时时间点的状态,
因此,同样的SELECT操作读到的结果会是一致的。
但是,会有幻读现象。

(4)串行化
最高的隔离级别,在这个隔离级别下,不会产生任何异常。
并发的事务,就像事务是在一个个按照顺序执行一样。

特别注意

MySQL默认的事务隔离级别为repeatable-read
MySQL支持4种事务隔离级别
事务的隔离级别要得到底层数据库引擎的支持,而不是程序或框架的支持

Oracle 支持2种事务隔离级别:Read_COMMITED,SERIALIZABLE
SQL 规范所规定的标准,不同的数据库具体的实现可能会有些差异

MySQL中默认事务隔离级别是“可重复读”时并不会锁住读取到的行
事务隔离级别为未提交读时, 写数据只会锁住相应的行
事务隔离级别为可重复读时,写数据会锁住整张表
事务隔离级别为
串行化时
,读写数据都会锁住整张表

隔离级别越高,越能保证数据的完整性和一致性,但是对并发性能的影响也越大,鱼和熊掌不可兼得啊
对于多数应用程序,可以优先考虑把数据库系统的隔离级别设为Read Committed,它能够避免脏读取,而且具有较好的并发性能。
尽管它会导致不可重复读、幻读这些并发问题,在可能出现这类问题的个别场合,可以由应用程序采用悲观锁或乐观锁来控制。

4 嵌套事务

什么是嵌套事务?
嵌套是子事务套在父事务中执行,子事务是父事务的一部分,
在进入子事务之前,父事务建立一个回滚点,叫save point
然后执行子事务,这个子事务的执行也算是父事务的一部分,
然后子事务执行结束,父事务继续执行。
重点就在于那个save point

看几个问题就明白啦~~~~

如果子事务发生回滚,会发生什么?
父事务会回滚到进入子事务之前建立的save point,然后尝试其他的事务或者其他的业务逻辑,
父事务之前的操作不会受到影响,更不会自动回滚。

如果父事务回滚,会发生什么?
父事务回滚,子事务也会跟着回滚!!
为什么呢?因为父事务结束之前,子事务是不会提交的,我们说子事务是父事务的一部分,正是这个道理。

那么?
事务的提交,是什么情况?
是父事务先提交,然后子事务提交,还是子事务先提交,父事务再提交?
答案是第二种情况,
还是那句话,子事务是父事务的一部分,由父事务统一提交。


第四部分 存储引擎

1 MySQL常见的两种存储引擎(InnoDB,MyISAM)的区别?

  • (1)InnoDB支持事务, MyISAM不支持,这一点非常之重要。
    事务是一种高级的处理方式,如在一些列增删改中只要哪个出错还可以回滚还原,而MyISAM就不可以了。

  • (2)MyISAM适合查询以及插入为主的应用

  • (3)InnoDB适合频繁修改及涉及到安全性较高的应用。

  • (4)InnoDB支持外键,MyISAM不支持。

  • (5)从MySQL5.5.5 以后,InnoDB是默认引擎。

  • (6)InnoDB不支持FULLTEXT类型的索引

  • (7)InnoDB中不保存表的行数,
    如select count() from table 时,InnoDB需要扫描一遍整个表来计算有多少行
    但是MyISAM只要简单的读出保存好的行数即可。
    注意的是,当count()语句包含where条件时MyISAM也需要扫描整个表

  • (8)对于自增长的字段,InnoDB中必须包含只有该字段的索引,
    但是在MyISAM表中可以和其他字段一起建立联合索引。

  • (9)DELETE From table时,InnoDB不会重新建立表,而是一行一行的删除,效率非常慢。
    MyISAM则会重建表。

  • (10)InnoDB支持行锁。(某些情况下还是锁整表,如 update table set a=1 where user like ‘%lee%’。

2 MySQL 存储引擎MyISAM与InnoDB如何选择?

MySQL有多种存储引擎,每种存储引擎有各自的优缺点,可以择优选择使用:MyISAM、InnoDB、MERGE、MEMORY(HEAP)、BDB(BerkeleyDB)、EXAMPLE、FEDERATED、ARCHIVE、CSV、BLACKHOLE。

虽然MySQL里的存储引擎不只是MyISAM与InnoDB这两个,但常用的就是两个。

关于MySQL 数据库提供的两种存储引擎,MyISAM与InnoDB选择使用:
(1)InnoDB会支持一些关系数据库的高级功能,如事务功能和行级锁,MyISAM不支持

如果你的应用程序一定要使用事务,毫无疑问你要选择InnoDB引擎。
但是要注意,InnoDB的行级锁是有条件的。在where条件没有使用主键时,照样会锁全表。
比如 delete from table 这样的删除语句。

如果你的应用程序对查询性能要求较高,就要使用MyISAM了。
MyISAM索引和数据是分开的,而且其索引是压缩的,可以更好的利用内存,所以它的查询性能明显优于InnoDB。
压缩后的索引也能节约一些磁盘空间。MyISAM拥有全文索引的功能,这可以极大的优化LIKE查询的效率。

有人说MyISAM只能用于小型应用,其实这是一种偏见,
如果数据量比较大,这是需要通过升级架构来解决,比如分表分库,而不是单纯的依赖存储引擎。
现在一般都选用InnoDB了,主要是MyISAM的全表锁,读写串行问题,并发效率锁表,效率低,
MyISAM对于读写密集型应用一般不会去选用的。

MEMORY存储引擎
MEMORY 是MySQL中一类特殊的存储引擎,它使用存储在内存中的内容来创建表,而且数据全部放在内存中。这些特性与前面的两个很不同。

每个基于MEMORY存储引擎的表实际对应一个磁盘文件,该文件的文件名与表名相同,类型为frm类型。
该文件中只存储表的结构,而其数据文件,都是存储在内存中,这样有利于数据的快速处理,提高整个表的效率。
值得注意的是,服务器需要有足够的内存来维持MEMORY存储引擎的表的使用。
如果不需要了,可以释放内存,甚至删除不需要的表。

MEMORY默认使用哈希索引。速度比使用B型树索引快。当然如果你想用B型树索引,可以在创建索引时指定。

注意 MEMORY用到的很少,因为它是把数据存到内存中,如果内存出现异常就会影响数据。
如果重启或者关机,所有的数据都会消失,因此,基于MEMORY的表的生命周期很短,一般是一次性的。

3 MySQL的MyISAM 与InnoDB两种搜索引擎在事务,锁级别,各自的使用场景?

  • 事务处理方面
    **MyISAM:**强调的是性能,每次查询具有原子性,其执行速度比InnoDB类型更快,但是不提供事务支持
    **InnoDB:**提供事务支持事务,外部键等高级数据库功能。
    具有事务(commit)、回滚(rollback)和崩溃修复能力(crash recovery capabilities)的事务安全transaction-safe (ACID compliant))型表

  • 锁级别
    **MyISAM:**只支持表级锁,用户在操作MyISAM表时,select,update,delete,insert语句都会给表自动加锁,
    如果加锁以后的表满足insert并发的情况下,可以在表的尾部插入新的数据
    **InnoDB:**支持事务和行级锁,是innoDB最大的特色。行锁大幅度提高了多用户并发操作的可能。
    但是InnoDB的行锁,只是在WHERE的主键是有效的,非主键的WHERE都会锁全表的。


第五部分 优化

1 查询语句不同元素(where, join,limit,group by等)执行先后顺序?

  • 查询用到的关键词主要包含六个,并且他们的顺序依次为select–from–where–group by – having – order by

其中select 和 from 是必须的,其他关键词是可选的,这六个关键字的执行顺序并不是一样的,按照下面顺序来执行:

(1)from : 需要从哪个数据表中检索数据
(2)where:过滤表中的数据
(3)group by:如何将上面过滤出的数据分组
(4)having:对上面已经分组的数据进行过滤的条件
(5)select:查看结果集中的哪个列,或列的计算结果
(6)order by:按照什么样的顺序来查看返回的数据

2 from 后面的表关联,是自右向左解析,而where条件的解析顺序是自下而上的

也就是说,在写SQL语句的时候,尽量把数据量小的表放在最右边来进行关联(用小表去匹配大表),
而把能筛选出小量数据的条件放在where语句的最左边(用小表去匹配大表)

3 使用explain优化sql和索引?

对于复杂、效率低的sql语句,我们通常是使用explain sql来分析sql语句,这个语句我们可以打印出,语句的执行。这样方便我们分析,进行优化。

**table:**显示这一行的数据是关于哪张表的

**type:**这是重要的列,显示连接使用来何种类型。从最好到最差的连接类型为const、eq_reg、ref、range、index和ALL

**all:**full table scan; MySQL将遍历全表以找到匹配的行

index: index scan; index 和all的区别在于index类型只遍历索引

**range:**索引范围扫描,对索引的扫描开始于某一点,返回匹配值的行,常见于between等查询。

**ref:**非唯一性索引扫描,返回匹配某个单独值的所有行,常见于使用非唯一索引即唯一索引的非唯一前缀进行查找

**eq_ref:**唯一性索引扫描,对于每个索引键,表中只有一条记录与之匹配,常用于主键或者唯一索引扫描

**const,system:**当MySQL对某查询某部分进行优化,并转为一个常量时,使用这些访问类型。如果将主键置于where列表中,MySQL就能将该查询转化为一个常量。

**possible_keys:**显示可能应用在这张表中的索引。如果为空,没有可能的索引。可以为相关的域从where语句中选择一个合适的语句

**key:**实际使用的索引。如果为NULL,则没有使用索引。很少的情况下,MySQL会选择优化不足的索引。这种情况下,可以在SELECT语句中使用USE INDEX(indexname)来强制使用一个索引或者用IGNORE INDEX
(indexname)来强制MySQL忽略索引

**key_len:**使用的索引的长度。在不损失精确性的情况下,长度越短越好

**ref:**显示索引的哪一列被使用了。如果可能的话,是一个常数

rows: MySQL认为必须检查的用来返回请求数据的行数

Extra: 关于MySQL如何解析查询的额外信息。

3 MySQL慢查询怎么解决?

  • slow_query_log
    慢查询开启状态
  • slow_query_log_file
    慢查询日志存放的位置(这个目录需要MySQL的运行账号的可写权限,一般设置为MySQL的数据存放目录)
  • long_query_time
    查询超过多少秒才记录

第六部分 数据库锁

  • MySQL 都有什么锁?
    MySQL有三种锁的级别:页级、表级、行级

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

  • 什么情况下会造成死锁?
    死锁 : 是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去,此时称系统处于死锁状态或者系统产生了死锁,这些永远在互相等待的进程称为死锁进程。

表级锁不会产生死锁,所以产生死锁主要还是在针对于最常用的InnoDB。

死锁的关键在于: 两个(或以上)的Session 加锁的顺序不一致。
那么对应的解决死锁问题的关键就是: 让不同的session加锁有次序。

死锁的解决办法?
(1)查出的线程杀死Kill
SELECT trx_MySQL_thread_id FROM information_schema.INNODB_TRX;

(2)设置锁的超时时间
InnoDB行锁的等待时间,单位秒。可在会话级别设置,RDS实例该参数的默认值为50(秒)
生产环境不推荐使用过大的 innodb_lock_wait_timeout参数值
该参数支持在会话级别修改,方便应用在会话级别单独设置某些特殊操作的行锁等待超时时间,如下:
set innodb_lock_wait_timeout=1000; —设置当前会话 Innodb 行锁等待超时时间,单位秒。

(3)指定获取锁的顺序

2 有哪些锁(乐观锁悲观锁),select时怎么加排他锁?

  • 悲观锁(Pession Lock)
    悲观锁特点:先获取锁,再进行业务操作。
    即“悲观”的认为获取锁是非常有可能失败的,因此要先确保获取锁成功再进行业务操作。
    通常所说的一锁二查三更新 即指的使用悲观锁。
    通常来讲在数据库上的悲观锁需要数据库本身提供支持,即通过常用的select… for update 操作来实现悲观锁。
    当数据库执行select… for update时会获取被select中的数据库的行锁,因此其他并发执行的select… for update如果试图选中同一行则会发生排斥(需要等待行锁被释放),因此达到锁的效果。
    select… for update获取的行锁会在当前事务结束时自动释放,因此必须在事务中使用。

补充

不同的数据库对select… for update的实现和支持都是有所区别的
oracle支持select… for update no wait, 表示如果拿不到锁立即报错,而不是等待,MySQL就没有no wait 这个选项。

MySQL 还有个问题是select… for update语句执行中所有扫描过的行都会被锁上,这一点很容易造成问题。因此如果在MySQL中用悲观锁 务必要确定了索引,而不是全表扫描。

  • 乐观锁(Optimistic Lock)
    乐观锁,也叫乐观并发控制,它假设多用户并发的事务在处理时不会彼此影响,各事务能够在不产生锁的情况下处理各自影响的那部分数据。在提交数据更新之前,每个事务会先检查该事务读取数据后,有没有其他的事务又修改了该数据。如果其他事务有更新的话,那么当前正在提交的事务会进行回滚。

乐观锁的特点是先进行业务操作,不到万不得已不去拿锁。 即“乐观” 的认为拿锁多半是会成功的,因此在进行完业务操作需要实际更新数据的最后一步去拿一下锁就好。
乐观锁在数据库伤的实现完全是逻辑的,不需要数据库提供特殊的支持。

** 一般的做法是在需要锁的数据上增加一个版本号,或者时间戳。**

注意

乐观锁在不发生取锁失败的情况下开销比悲观锁小,但是一旦发生失败回滚开销则比较大,因此适合用在取锁失败概率比较小的场景,可以提升系统并发性能

乐观锁还适用于一些比较特殊的场景,例如在业务操作过程中无法和数据库保持连接等悲观锁无法适用的地方。

  • 总结
    悲观锁和乐观锁是数据库用来保证数据并发安全防止更新丢失的两种方法,
    例子在select… for update前加个事务就可以防止更新丢失。
    悲观锁和乐观锁大部分场景下差异不大,一些独特场景下有一些差别,一般从如下几个方面来判断:
    (1)响应速度
    如果需要非常高的响应速度,建议采用乐观锁方案,成功就执行,不成功就失败,不需要等待其他并发去释放锁

(2)冲突频率
如果冲突频率非常高,建议采用悲观锁,保证成功率,如果冲突频率大,乐观锁要多次尝试才能成功,代价比较大。

(3)重试代价
如果重试代价大,建议采用悲观锁。


第七部分 主从复制及高并发

1 数据库的三种主从复制方式

  • (1)同步复制
    所谓的同步复制,意思是master的变化,必须等待slave1,slave2…slaven 完成后才能返回。
    这样,显然不可取,也不是MySQL复制的默认设置。
    比如,在WEB前端页面上,用户增加了条记录,需要等待很长时间。

  • (2)异步复制
    如同AJAX请求一样,master只需完成自己的数据库操作即可。
    至于slaves是否收到二进制日志,是否完成操作,不用关心MySQL的默认设置。

  • (3)半同步复制
    master 只保证slaves中的一个操作成功,就返回,其他slave不管。
    这个功能,是由google 为MySQL引入的。

2 数据库主从复制分析的7个问题

问题1 :master的写操作,slaves被动的进行一样的操作,保持数据一致性,那么slave是否可以主动的进行写操作?

假设slave可以主动的进行写操作,slave又无法通知master,这样就导致了master和slave数据不一致。
因此slave不应该进行写操作,至少是slave上涉及到复制的数据库不可写。
实际上,这里已经揭示了读写分离的概念。

问题2 : 主从复制中,可以有N个slave,可是这些slave又不能进行写操作,要他们干嘛?

实现数据备份
类似于高可用的功能,一旦master挂了,可以让slave顶上去,同时slave提升为master。
异地融灾
比如master在北京,地震挂了,那么在上海的slave还可以继续
主要用于实现scale out, 分担负载,可以将度的任务分散到slaves上

【很可能的情况是,一个系统的读操作远远多余写操作,因此写操作发向master,读操作发向slaves进行操作。】

问题3:主从复制中有master,slave1,slave2,…等等这么多MySQL数据库,那比如一个JAVA WEB应用到底应该连接哪个数据库?

我们在应用程序中可以这样,insert/delete/update这些更新数据库的操作,用connection(for master)进行操作,select用connection(for slaves) 进行操作。
那我们的应用程序还要完成怎么从slaves选择一个来执行select,例如简单的轮询算法。
这样的话,相当于应用程序完成了SQL语句的路由,而且与MySQL的主从复制框架非常关联,一旦master挂了,某些slaves挂了,那么应用程序就要修改了。

能不能让应用程序与MySQL的主从复制架构没有太多关系呢?
找一个组件,application program 只需要跟它打交道,用它来完成MySQL的代理,实现SQL语句的路由。

MySQL proxy 并不负责,怎么从众多的slaves挑一个?
可以交给另一个组件,比如haproxy 来完成。

这就是所谓的MySQL READ WRITE SPLITE, MySQL的读写分离。

问题四:如果MySQL proxy , direct , master他们中的某些挂了怎么办?

总统一般都会弄个副总统,以防不测。同时,可以给这些关键的节点来个备份。

问题五: 当master的二进制日志每产生一个事件,都需要发往slave,如果我们有N个slave,那是发N次,还是只发一次?如果只发一次,发给了slave-1,那slave-2,slave-3,…它们怎么办?

显然,应该发N次。
实际上,在MySQL master 内部,维护多个线程,每一个线程负责将二进制日志文件发往对应的salve。
master 既要负责写操作,还得维护N个线程,负担会很重。
可以这样,salve 是master的从, slave1 又是 slave2, slave3 的主,同时slave1 不再负责select。
slave1将master的复制线程的负担,转移到自己的身上。

这就是所谓的多级复制的概念。

问题6:当一个select发往MySQL proxy,可能这次由slave-2响应,下次由slave-3响应,这样的话,就无法利用查询缓存了

应该找一个共享式的缓存,比如memcache来解决。
将slave2, slave3…这些查询的结果都缓存至memcache中。

问题7:随着应用的日益增长,读操作很多,我们可以扩展slave,但是如果master满足不了写操作了,怎么办呢?

scale on ?更好的服务器? 没有最好的,只有更好的,太贵了。。。
scale out ? 主从复制架构已经满足不了。
可以分库【垂直拆分】,分表【水平拆分】。

3 MySQL高并发环境解决方案

MySQL高并发环境解决方案:分库, 分表, 分布式, 增加二级缓存…

需求分析:互联网单位每天大量数据读取、写入,并发性高
现有解决方式:水平分库分表,由单点分布到多点数据库中,从而降低单点数据库压力
集群方案:解决DB宕机带来的单点DB 不能访问问题
读写分离策略:极大限度提高了应用中Read数据的速度和并发量,无法解决高写入压力

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

Undo Log:
Undo Log 是为了实现事务的原子性,在MySQL 数据库 InnoDB存储引擎中,还用了Undo Log 来实现多版本并发控制(简称:MVCC)

事务的原子性(Atomicity)事务中的所有操作,要么全部完成,要么不做任何操作,不能只做部分操作。
如果在执行的过程中发生了错误,要回滚(RollBack)到事务开始前的状态,就好像这个事务从来没有执行过。

原理Undo Log 的原理很简单,为了满足事务的原子性,在操作任何数据之前,首先将数据备份到一个地方(这个存储数据备份的地方称为UndoLog)。然后进行数据的修改。
如果出现了错误或者用户执行了ROLLBACK语句,系统可以利用Undo Log中的备份将数据恢复到事务开始之前的状态。

**缺陷:**每个事务提交前将数据和UndoLog写入磁盘,这样会导致大量的磁盘IO,因此性能很低。
如果能够将数据缓存一段时间,就能减少IO提高性能,但是这样就会丧失事务的持久性。
因此引入了另外一种机制来实现持久化,即Redo Log。

Redo Log
原理和Undo Log相反, Redo Log 记录的是新数据的备份。在事务提交前,只要将Redo Log 持久化即可,不需要将数据持久化。
当系统崩溃时,虽然数据没有持久化,但是 Redo Log 已经持久化,系统可以根据Redo Log的内容,将所有数据恢复到最新的状态。

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