一、基本概念
1.主键、外键、超键、候选键
关系:一张表。
元组:表中一行。
属性:表中一列。
主 键:
是表中的一个或多个字段,它的值用来唯一标识表中的某一条记录。一个数据列只能有一个主键,且主键的取值不能缺失,即不能为空值(Null)。
超 键:
在表中能唯一标识元组的属性集。一个属性可以为作为一个超键,多个属性组合在一起也可以作为一个超键。超键包含候选键和主键。
候选键:
没有冗余元素的超键。
外 键:
在一个表中存在的另一个表的主键称此表的外键。
2.为什么用自增列作为主键
如果我们定义了主键(PRIMARY KEY),那么InnoDB会选择主键作为聚集索引。
如果没有显式定义主键,则InnoDB会选择第一个不包含有NULL值的唯一索引作为主键索引。
如果也没有这样的唯一索引,则InnoDB会选择内置6字节长的ROWID作为隐含的聚集索引(ROWID随着行记录的写入而主键递增,这个ROWID不像ORACLE的ROWID那样可引用,是隐含的)。
数据记录本身被存于主索引(一颗B+Tree)的叶子节点上。这就要求同一个叶子节点内(大小为一个内存页或磁盘页)的各条数据记录按主键顺序存放,因此每当有一条新的记录插入时,MySQL会根据其主键将其插入适当的节点和位置,如果页面达到装载因子(InnoDB默认为15/16),则开辟一个新的页(节点)。
如果表使用自增主键,那么每次插入新的记录,记录就会顺序添加到当前索引节点的后续位置,当一页写满,就会自动开辟一个新的页。
如果使用非自增主键(如果身份证号或学号等),由于每次插入主键的值近似于随机,因此每次新纪录都要被插到现有索引页得中间某个位置,此时MySQL不得不为了将新记录插到合适位置而移动数据,甚至目标页面可能已经被回写到磁盘上而从缓存中清掉,此时又要从磁盘上读回来,这增加了很多开销,同时频繁的移动、分页操作造成了大量的碎片,得到了不够紧凑的索引结构,后续不得不通过OPTIMIZE TABLE来重建表并优化填充页面。
综上总结,如果InnoDB表的数据写入顺序能和B+树索引的叶子节点顺序一致的话,这时候存取效率是最高的,也就是下面这几种情况的存取效率最高:
1、使用自增列(INT/BIGINT类型)做主键,这时候写入顺序是自增的,和B+数叶子节点分裂顺序一致;
2、该表不指定自增列做主键,同时也没有可以被选为主键的唯一索引(上面的条件),这时候InnoDB会选择内置的ROWID作为主键,写入顺序和ROWID增长顺序一致;
除此以外,如果一个InnoDB表又没有显示主键,又有可以被选择为主键的唯一索引,但该唯一索引可能不是递增关系时(例如字符串、UUID、多字段联合唯一索引的情况),该表的存取效率就会比较差。
3.什么是存储过程?用什么来调用?
存储过程是事先经过编译并存储在数据库中的一段 SQL 语句的集合。
调用:
1)可以用一个命令对象来调用存储过程。
2)可以供外部程序调用,比如:java程序。
4.存储过程的优缺点?
优点:
1)存储过程只在创建时进行编译,以后每次执行存储过程都不需再重新编译,执行效率高。
2)存储过程的代码直接存放于数据库中,通过存储过程名直接调用,减少网络通讯。
3)安全性高,执行存储过程需要有一定权限的用户。
4)存储过程可以重复使用,可减少数据库开发人员的工作量。
缺点:
随着用户需求的增加会导致数据结构的变化,可移植性和可维护性差。
存储过程与函数的区别
存储过程和函数是事先经过编译并存储在数据库中的一段 SQL 语句的集合。
存储过程和函数的区别在于函数必须有返回值,而存储过程没有。
5.触发器的作用?
触发器是一种特殊的存储过程,主要通过事件的触发而被执行。它可以强化约束,来维护数据的完整性和一致性。可以跟踪数据库内的操作从而不允许未经许可的更新和变化。可以联级运算。如,某表上的触发器上包含对另一个表的数据操作,而该操作又会导致该表触发器被触发。
6.存储过程与触发器的区别
触发器与存储过程非常相似,触发器也是SQL语句集,两者唯一的区别是触发器不能用EXECUTE语句调用,而是在用户执行Transact-SQL语句时自动触发(激活)执行。触发器是在一个修改了指定表中的数据时执行的存储过程。通常通过创建触发器来强制实现不同表中的逻辑相关数据的引用完整性和一致性。由于用户不能绕过触发器,所以可以用它来强制实施复杂的业务规则,以确保数据的完整性。触发器不同于存储过程,触发器主要是通过事件执行触发而被执行的,而存储过程可以通过存储过程名称名字而直接调用。当对某一表进行诸如UPDATE、INSERT、DELETE这些操作时,SQLSERVER就会自动执行触发器所定义的SQL语句,从而确保对数据的处理必须符合这些SQL语句所定义的规则。
7.什么叫视图?游标是什么?
视图:
视图是从一个或几个基本表(或视图)导出的表。它与基本表不同,是一个虚表。可以对视图进行增,改,查,操作,试图通常是有一个表或者多个表的行或列的子集。对视图的修改会影响基本表。它使得我们获取数据更容易,相比多表查询。
游标:
游标是对查询出来的结果集作为一个单元来有效的处理。游标可以定在该单元中的特定行,从结果集的当前行检索一行或多行。可以对结果集当前行做修改。一般不使用游标,但是需要逐条处理数据的时候,游标显得十分重要。
8.视图的优缺点
优点:
1.可以简化用户的操作,使用户将注意力放在关心的数据上。
2.用户通过简单的查询可以从复杂查询中得到结果。
3.视图可从多个表检索数据,维护了数据的独立性。
缺点:
性能:查询视图时,必须把视图的查询转化成对基本表的查询,如果这个视图是由一个复杂的多表查询所定义,那么,那么就无法更改数据。
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 segmen中,事务提交后才生效。如果有相应的 tigger,执行的时候将被触发。
(8) truncate、drop是DLL(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 不记录在日志中,所以它不能激活触发器。
10.什么是临时表,临时表什么时候删除?
临时表只在当前连接可见,当关闭连接时,MySQL会自动删除表并释放所有空间。因此在不同的连接中可以创建同名的临时表,并且操作属于本连接的临时表。
创建临时表的语法与创建表语法类似,不同之处是增加关键字TEMPORARY。
如:
CREATE TEMPORARY TABLE tmp_table (
NAME VARCHAR (10) NOT NULL,
time date NOT NULL
);
select * from tmp_table;
临时表可以手动删除:
DROP TEMPORARY TABLE IF EXISTS temp_tb;
11.关系型数据库和非关系型数据库区别,优势比较?
关系型数据库:指采用了关系模型来组织数据的数据库。
关系模型指的就是二维表格模型,而一个关系型数据库就是由二维表及其之间的联系所组成的一个数据组织。
关系模型中常用的概念:
关系:一张二维表,每个关系都具有一个关系名,也就是表名。
元组:二维表中的一行,在数据库中被称为记录。
属性:二维表中的一列,在数据库中被称为字段。
域:属性的取值范围,也就是数据库中某一列的取值限制。
关键字:一组可以唯一标识元组的属性,数据库中常称为主键,由一个或多个列组成。
关系模式:指对关系的描述。其格式为:关系名(属性1,属性2, … … ,属性N),在数据库中成为表结构。
1.成本:Nosql数据库简单易部署,基本都是开源软件,不需要像使用Oracle那样花费大量成本购买使用,相比关系型数据库价格便宜。
2.查询速度:Nosql数据库将数据存储于缓存之中,而且不需要经过SQL层的解析。关系型数据库将数据存储在硬盘中,自然查询速度慢。
3.存储数据的格式:Nosql的存储格式是key,value形式、文档形式、图片形式等等,所以可以存储基础类型以及对象或者是集合等各种格式。而数据库则只支持基础类型。
4.扩展性:Nosql基于键值对,数据之间没有耦合性,所以非常容易水平扩展。关系型数据库有类似join这样的多表查询机制的限制导致扩展很艰难。
5.持久存储:Nosql不使用于持久存储。海量数据的持久存储,还是需要关系型数据库。
6.数据一致性:非关系型数据库一般强调的是数据最终一致性,不像关系型数据库一样强调数据的强一致性,从非关系型数据库中读到的有可能还是处于一个中间态的数据,
Nosql不提供对事务的处理。
12.数据库范式,根据某个场景设计数据表?
第一范式:不存在非主属性部分依赖于码。
第二范式:非主属性完全依赖与码。
第三范式:非主属性不传递依赖于码。
如何更好地区分三大范式?
第 一范式和第二范式在于有没有分出两张表,第二范式是说一张表中包含了所种不同的实体属性,那么要必须分成多张 表, 第三范式是要求已经分成了多张表,那么一张表中只能有另一张表中的id(主键),而不能有其他的任何信息(其他 的信息一律用主键在另一表查询)。
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所占的长度依然为10,除了字符‘csdn’外,后面跟六个空格,varchar就立马把长度变为4了,取数据的时候,char类型的要用trim()去掉多余的空格,而varchar是不需要的。
2.char的存取数度还是要比varchar要快得多,因为其长度固定,方便程序的存储与查找。
char也为此付出的是空间的代价,因为其长度固定,所以难免会有多余的空格占位符占据空间,可谓是以空间换取时间效率。
varchar是以空间效率为首位。
3.char的存储方式是:对英文字符(ASCII)占用1个字节,对一个汉字占用两个字节。
varchar的存储方式是:对每个英文字符占用2个字节,汉字也占用2个字节。
4.两者的存储数据都非unicode的字符数据。
15.SQL语言分类
- 数据控制(DCL)——Data Control Language
用于执行权限授予和权限收回操作,主要包括GRANT和REVOKE 两条命令。
其中GRANT命令用于给用户或角色授予权限,REVOKE命令则用于收回用户或角色 所具有的权限。 - 数据定义(DDL)——Data Definition Language
用于建立、修改和删除数据库对象。可以使用CRATE TABLE 语句创建表,使用 ALTER TABLE 语句修改表结构,使用DROP TABLE 语句删除表。 - 数据操纵(DML)——Data Manipulation Language
用于改变数据库中的数据,主要包括INSERT、UPDATE和DELETE 3条语句。 - 数据查询(DQL)——Data Query Language
用于检索数据库中的数据,主要是SLECT语句。 - 事务控制(TCL)——Transaction Control Language
用于维护数据的一致性,包括COMMIT、ROLLBACK和SAVEPOINT 3条语句。
16.like %和-的区别
%百分号通配符:表示任意个字符(可以是0次)。
_下划线通配符:表示只能匹配一个字符。
like操作符: LIKE作用是指示mysql后面的搜索模式是利用通配符而不是直接相等匹配进行比较。(like不能匹配NULL)
注意: 如果在使用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"这样的记录.(一个下划线只能匹配一个字符,不能多也不能少)
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.最左前缀原则
最左前缀原则:最左前缀原则就是从最左边开始匹配的原则,mysql会一直向右匹配直到遇到范围查询(>、<、between、like)就停止匹配。
我们创建lname_fname_age多列索引,相当于创建了(lname)单列索引,(lname,fname)组合索引以及(lname,fname,age)组合索引。
二.索引
1.什么是索引?
索引是帮助MySQL高效获取数据的数据结构(有序)。在数据之外,数据库系统还维护者满足特定查找算法的数据结构,这些数据结构以某种方式引用(指向)数据,这种数据结构就是索引。
2.索引的优势和劣势
优势:
1.提高数据检索的效率,降低数据库的IO成本。
2.通过索引列对数据进行排序,降低数据排序的成本,降低CPU的消耗。
劣势:
1.索引也是一张表,该表中保存了主键、索引字段和指向实体类的记录,所以索引也是要占用空间的。
2.虽然索引大大提高了查询效率,同时却也降低更新表的速度,如对表进行INSERT、UPDATE、DELETE。因为更新表时,MySQL 不仅要保存数据,还要保存一下索引文件每次更新添加了索引列的字段,都会调整因为更新所带来的键值变化后的索引信息。
3.索引结构
BTREE 索引 : 最常见的索引类型,大部分索引都支持 B 树索引。
HASH 索引:只有Memory引擎支持 , 使用场景简单 。
R-tree 索引(空间索引):主要用于地理空间数据类型。
Full-text (全文索引) :主要用于全文索引。
4.哪些列适合建立索引、哪些不适合建索引?
适合场景:
(1)在作为主键的列上,强制该列的唯一性和组织表中数据的排列结构;
(2)在经常需要搜索的列上,可以加快搜索的速度;
(3)在经常用在连接的列上(这些列主要是一些外键),可以加快连接的速度;
(4)在经常需要排序的列上,可以利用索引的排序,加快排序查询时间;
(5)在经常使用在WHERE子句中的列上,可以加快条件的判断速度。
(6)在经常需要根据范围进行搜索的列上,因为索引已经排序,其指定的范围是连续的。
不适合场景:
(1)对于那些在查询中很少使用或者参考的列不应该创建索引。
这是因为,既然这些列很少使用到,因此有索引或者无索引,并不能提高查询速度。相反,由于增加了索引,反而降低了系统的维护速度和增大了空间需求。
(2)对于那些只有很少数据值的列也不应该增加索引。
这是因为,由于这些列的取值很少,例如人事表的性别列,在查询的结果中,结果集的数据行占了表中数据行的很大比例,即需要在表中搜索的数据行的比例很大。增加索引,并不能明显加快检索速度。
(3)对于那些定义为text, image和bit数据类型的列不应该增加索引。
这是因为,这些列的数据量要么相当大,要么取值很少。
(4)对于当修改性能远远大于检索性能时,不应该创建索引。
这是因为,修改性能和检索性能是互相矛盾的。当增加索引时,会提高检索性能,但是会降低修改性能。当减少索引时,会提高修改性能,降低检索性能。因此,当修改性能远远大于检索性能时,不应该创建索引。
5.B树结构
BTree又叫多路平衡搜索树。
特点:
1.树中每个节点最多包含m个孩子。
2.除根节点与叶子节点外,每个节点至少有[ceil(m/2)]个孩子。
3.若根节点不是叶子节点,则至少有两个孩子。
4.所有的叶子节点都在同一层。
5.每个非叶子节点由n个key与n+1个指针组成,其中[ceil(m/2)-1] <= n <= m-1 。
以5叉BTree为例,key的数量公式推导[ceil(m/2)-1] <= n <= m-1,所以 2 <= n <=4 。当n>4时,中间节点分裂到父节点,两边节点分裂。
6.B树和B+树的区别
B+树为B树的变种。
B+树与B树的区别:
1.n叉B+树最多含有n个key,而树最多含有n-1个key。
2.B+树的叶子节点保存所有的key信息,依key大小顺序排列。
3.所有的非叶子节点都可以看作是key的索引部分。
4.由于B+树只有叶子节点保存key信息,查询任何key都要从root走到叶子。所以B+树的查询效率更加稳定。
7.数据库为什么使用B+树而不是B树?
1.B+的磁盘读写代价更低。
B+的内部结点并没有指向关键字具体信息的指针。因此其内部结点相对B树更小。如果把所有同一内部结点的关键字存放在同一盘块中,那么盘块所能容纳的关键字数量也越多。一次性读入内存中的需要查找的关键字也就越多。相对来说IO读写次数也就降低了。
2.B+tree的查询效率更加稳定。
由于非终结点并不是最终指向文件内容的结点,而只是叶子结点中关键字的索引。所以任何关键字的查找必须走一条从根结点到叶子结点的路。所有关键字查询的路径长度相同,导致每一个数据的查询效率相当。
3.B+树更便于遍历。
由于B+树的数据都存储在叶子结点中,分支结点均为索引,方便扫库,只需要扫一遍叶子结点即可,但是B树因为其分支结点同样存储着数据,我们要找到具体的数据,需要进行一次中序遍历按序来扫,所以B+树更加适合在区间查询的情况,所以通常B+树用于数据库索引。
4.B+树更适合基于范围的查询。
B树在提高了IO性能的同时并没有解决元素遍历的我效率低下的问题,正是为了解决这个问题,B+树应用而生。B+树只需要去遍历叶子节点就可以实现整棵树的遍历。而且在数据库中基于范围的查询是非常频繁的,而B树不支持这样的操作或者说效率太低。
由于B树的每一个节点都包含key和value,因此经常访问的元素可能离根节点更近,因此访问也更迅速。
区别
红黑树 :增加,删除,红黑树会进行频繁的调整,来保证红黑树的性质,浪费时间
B树也就是B-树:查询性能不稳定,查询结果高度不致,每个结点保存指向真实数据的指针,相比B+树每一层每屋存储的元素更多,显得更高一点。
B+树:B+树相比较于另外两种树,显得更矮更宽,查询层次更浅.
8.Hash索引和B+树索引有什么区别或者说优劣势?
hash索引底层实现原理是hash表。在进行查询时,调用一次hash函数就可以获取到相应的键值,之后通过回表查询获得实际数据.
B+树底层实现原理是多路平衡查找树。对于每一次的查询都是从根节点出发,查询到叶子节点方可以获得所查键值,然后通过判断是否需要回表查询。
区别:
hash索引
1.hash索引进行等值查询更快(一般情况下)但是却无法进行范围查询.因为在hash索引中经过hash函数建立索引之后,索引的顺序与原顺序无法保持一致,不能支持范围查询。
2.hash索引不支持模糊查询以及多列索引的最左前缀匹配,因为hash函数的不可预测,eg:AAAA和AAAAB的索引没有相关性。
3.hash索引任何时候都避免不了回表查询数据。
4.hash索引虽然在等值上查询叫快,但是不稳定,性能不可预测,当某个键值存在大量重复的时候,发生hash碰撞,此时查询效率可能极差。
5.hash索引不支持使用索引进行排序,因为hash函数的不可预测。
B+树
1.B+树的所有节点皆遵循(左节点小于父节点,右节点大于父节点,多叉树也类似)自然支持范围查询。
2.在符合某些条件(聚簇索引,覆盖索引等)的时候可以只通过索引完成查询.不需要回表查加粗样式询。
3.查询效率比较稳定,对于查询都是从根节点到叶子节点,且树的高度较低。
结论
大多数情况下,直接选择B+树索引可以获得稳定且较好的查询速度,而不需要使用Hash索引。
9.B+树在满足聚簇索引和覆盖索引的时候不需要回表查询数据。什么是聚簇索引呢?
聚簇索引:表数据按照索引的顺序来储存的,也就是说索引项的顺序与表中记录的物理顺序一致。在B+树的索引中叶子节点可能储存了当前的key值,也可能储存了当前的key值以及整行的数据,在一张表上最多只能创建一个聚簇索引,因为真实数据的物理顺序只有一种。
非聚簇索引:表数据存储顺序与索引顺序无关,对于非聚簇索引,叶子节点包含索引字段值及指向数据页数据行的逻辑指针.
总结: 聚簇索引是一种稀疏索引,数据页的上一级的索引页储存的是页指针,而不是行指针。非聚簇索引,则是密集索引,在数据页的上一级索引页它为每一个数据行存储一条索引记录。聚集索引和非聚集索引的根本区别是表记录的排列顺序和与索引的排列顺序是否一致。
10.何时使用聚簇索引与非聚簇索引?
在InnoDB中,只有主键索引是聚簇索引,如果没有主键,则挑选一个唯一键建立聚簇索引。如果没有唯一键,则隐式的生成一个键建立索引。
11.什么情况下聚簇索引不需要回表查询?
当查询使用聚簇索引时,在对应的叶子节点,可以获得到整行数据,因此不用再次进行回表查询.
12.非聚簇索引一定会回表查询吗?
不一定。这涉及到查询语句所要求的字段是否全部命中了索引,如果全部命中了索引,那么就不必在进行回表查询了。
eg:假设我们在员工表的年龄上建立了索引,那么当进行select age from employee where age<20的查询时,在索引的叶子节点上,已经包含了age信息,不会再次进行回表查询。
13.联合索引是什么?为什么需要注意联合索引中的顺序?
MySQL可以使用多个字段同时建立一个索引,叫做联合索引。在联合索引中,如果想要命中索引,需要按照建立索引时的字段顺序挨个使用,否则无法命中索引。
- 注意联合索引中的顺序的具体原因为:
MySQL使用索引时需要索引有序,假设现在建立了"name,age,school"的联合索引,那么索引的排序为: 先按照name排序,如果name相同,则按照age排序,如果age的值也相等,则按照school进行排序。
当进行查询时,此时索引仅仅按照name严格有序,因此必须首先使用name字段进行等值查询,之后对于匹配到的列而言,其按照age字段严格有序,此时可以使用age字段用做索引查找,,,以此类推。
因此在建立联合索引的时候应该注意索引列的顺序,一般情况下,将查询需求频繁或者字段选择性高的列放在前面。还可以根据特例的查询或者表结构进行单独的调整。
14.索引分类?
1.单值索引 :即一个索引只包含单个列,一个表可以有多个单列索引。
2. 唯一索引 :索引列的值必须唯一,但允许有空值。
3.复合索引 :即一个索引包含多个列。
15.创建索引时需要注意什么?
要注意字段的使用频率,经常作为条件进行查询的字段比较适合。如果需要建立联合索引的话,还需要考虑联合索引中的顺序。此外也要考虑其他方面,比如防止过多的所有对表造成太大的压力。这些都和实际的表结构以及查询方式有关。
16.如何查看创建的索引有没有被使用到?或者说怎么才可以知道这条语句运行很慢的原因?
MySQL提供了explain命令来查看语句的执行计划。MySQL在执行某个语句之前,会将该语句过一遍查询优化器,之后会拿到对语句的执行计划,其中包含了许多信息。可以通过其中和索引有关的信息来分析是否命中了索引,例如possilbe_key,key,key_len等字段,分别表明此语句可能会使用的索引,实际使用的索引以及使用的索引长度。
17.在哪些情况下该列创建了索引,但是在查询时并没有使用呢?
1.列参与了数学运算或者函数。
2.在字符串like时左边是通配符.类似于’%aaa’。
3.当mysql分析全表扫描比使用索引快的时候不使用索引。
4.当使用联合索引,前面一个条件为范围查询,后面的即使符合最左前缀原则,也无法使用索引。
三、事务
1.什么是事务?
事务是用户定义的一个数据库操作序列,这些操作要么全做,要么全不做,是一个不可分割的工作单位。
2.事务四大特性(ACID):原子性、一致性、隔离性、持久性?
原子性:事务包含的所有操作要么全部成功,要么全部失败回滚。
一致性:事务开始之前和结束之后,数据库的完整性约束没有被破坏。比如A向B转账,不可能A扣了钱,B却没收到。
隔离性:当多个用户并发访问数据库时,比如操作同一张表时,数据库为每一个用户开启的事务,不能被其他事务的操作所干扰,多个并发事务之间要相互隔离。同一时间,只允许一个事务请求同一数据,不同的事务之间彼此没有任何干扰。比如A正在从一张银行卡中取钱,在A取钱的过程结束前,B不能向这张卡转账。
持久性:指一个事务一旦被提交了,那么对数据库中的数据的改变就是永久性的,即便是在数据库系统遇到故障的情况下也不会丢失提交事务的操作。
3.事务
概念:多个事务之间隔离的,相互独立的。但是如果多个事务操作同一批数据,则会引发一些问题,设置不同的隔离级别就可以解决这些问题。
-
存在问题:
1. 脏读:一个事务,读取到另一个事务中没有提交的数据
2. 不可重复读(虚读):在同一个事务中,两次读取到的数据不一样。
3. 幻读:一个事务操作(DML)数据表中所有记录,另一个事务添加了一条数据,则第一个事务查询不到自己的修改。 -
隔离级别:
1. read uncommitted:读未提交
* 产生的问题:脏读、不可重复读、幻读
2. read committed:读已提交 (Oracle)
* 产生的问题:不可重复读、幻读
3. repeatable read:可重复读 (MySQL默认)
* 产生的问题:幻读
4. serializable:串行化
* 可以解决所有的问题 -
注意:隔离级别从小到大安全性越来越高,但是效率越来越低
* 数据库查询隔离级别:
* select @@tx_isolation;
* 数据库设置隔离级别:
* set global transaction isolation level 级别字符串;
- 特别注意:
MySQL默认的事务隔离级别为repeatable-read。
MySQL 支持 4 种事务隔离级别。
事务的隔离级别要得到底层数据库引擎的支持, 而不是应用程序或者框架的支持.
Oracle 支持的 2 种事务隔离级别:READ_COMMITED , SERIALIZABLE。MySQL中默认事务隔离级别是“可重复读”时并不会锁住读取到的行。
事务隔离级别:未提交读时,写数据只会锁住相应的行。
事务隔离级别为:可重复读时,写数据会锁住整张表。
事务隔离级别为:串行化时,读写数据都会锁住整张表。
隔离级别越高,越能保证数据的完整性和一致性,但是对并发性能的影响也越大,鱼和熊掌不可兼得啊。对于多数应用程序,可以优先考虑把数据库系统的隔离级别设为Read Committed,它能够避免脏读取,而且具有较好的并发性能。尽管它会导致不可重复读、幻读这些并发问题,在可能出现这类问题的个别场合,可以由应用程序采用悲观锁或乐观锁来控制。
4.嵌套事务
-
什么是嵌套事务?
嵌套是子事务套在父事务中执行,子事务是父事务的一部分,在进入子事务之前,父事务建立一个回滚点,叫save point,然后执行子事务,这个子事务的执行也算是父事务的一部分,然后子事务执行结束,父事务继续执行。重点就在于那个save point。看几个问题就明了了: -
如果子事务回滚,会发生什么?
父事务会回滚到进入子事务前建立的save point,然后尝试其他的事务或者其他的业务逻辑,父事务之前的操作不会受到影响,更不会自动回滚。 -
如果父事务回滚,会发生什么?
父事务回滚,子事务也会跟着回滚!为什么呢,因为父事务结束之前,子事务是不会提交的,我们说子事务是父事务的一部分,正是这个道理。那么: -
事务的提交,是什么情况?
是父事务先提交,然后子事务提交,还是子事务先提交,父事务再提交?答案是第二种情况,还是那句话,子事务是父事务的一部分,由父事务统一提交。
四、存储引擎
1.MySQL常见的三种存储引擎(MyISAM、InnoDB)的区别?
1.从MySQL5.5.5以后,InnoDB是默认引擎。
2.InnoDB支持事务,MyISAM不支持。事务是一种高级的处理方式,如在一些列增删改中只要哪个出错还可以回滚还原,而MyISAM就不可以了。
3.InnoDB支持外键,MyISAM不支持。
4.InnoDB适合频繁修改以及涉及到安全性较高的应用。MyISAM适合查询以及插入为主的应用。
5.InnoDB不支持FULLTEXT类型的索引。
6.select count() from table时,InnoDB中不保存表的行数,InnoDB需要扫描一遍整个表来计算有多少行,但是MyISAM只要简单的读出保存好的行数即可。注意的是,当count()语句包含where条件时MyISAM也需要扫描整个表。
7.对于自增长的字段,InnoDB中必须包含只有该字段的索引,但是在MyISAM表中可以和其他字段一起建立联合索引。
8.DELETE FROM table时,InnoDB不会重新建立表,而是一行一行的 删除,效率非常慢。MyISAM则会重建表。
2.MySQL存储引擎MyISAM与InnoDB如何选择?
虽然MySQL里的存储引擎不只是MyISAM与InnoDB这两个,但常用的就是两个。
MyISAM与InnoDB选择使用:
1.MyISAM的性能更优,占用的存储空间少。
2.INNODB会支持一些关系数据库的高级功能,如事务功能和行级锁,MyISAM不支持。
3.如果应用程序一定要使用事务,要选择INNODB引擎。但要注意,INNODB的行级锁是有条件的。在where条件没有使用主键时,照样会锁全表。比如DELETE FROM mytable这样的删除语句。
4.如果应用程序对查询性能要求较高,要选择MyISAM了。MyISAM索引和数据是分开的,而且其索引是压缩的,可以更好地利用内存。所以它的查询性能明显优于INNODB。压缩后的索引也能节约一些磁盘空间。MyISAM拥有全文索引的功能,这可以极大地优化LIKE查询的效率。
有人说MyISAM只能用于小型应用,其实这只是一种偏见。如果数据量比较大,这是需要通过升级架构来解决,比如分表分库,而不是单纯地依赖存储引擎。
现在一般都是选用innodb了,主要是MyISAM的全表锁,读写串行问题,并发效率锁表,效率低,MyISAM对于读写密集型应用一般是不会去选用的。
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都会锁全表的。
五、SQL优化
1.查询语句不同元素(where、jion、limit、group by、having等等)执行先后顺序?
select–from–where–group by–having–order by
其中select和from是必须的,其他关键词是可选的。
from:需要从哪个数据表检索数据
where:过滤表中数据的条件
group by:如何将上面过滤出的数据分组
having:对上面已经分组的数据进行过滤的条件
select:查看结果集中的哪个列,或列的计算结果
order by :按照什么样的顺序来查看返回的数据
2.from后面的表关联,是自右向左解析 而where条件的解析顺序是自下而上的。
也就是说,在写SQL语句的时候,尽量把数据量小的表放在最右边来进行关联(用小表去匹配大表),而把能筛选出小量数据的条件放在where语句的最左边 (用小表去匹配大表)。
3.MySQL慢查询怎么解决?
slow_query_log 慢查询开启状态。
slow_query_log_file 慢查询日志存放的位置(这个目录需要MySQL的运行帐号的可写权限,一般设置为MySQL的数据存放目录)。
long_query_time 查询超过多少秒才记录。
4.数据库SQL分析
1.查看SQL执行频率。
MySQL 客户端连接成功后,通过 show [session|global] status 命令可以提供服务器状态信息。show [session|global] status 可以根据需要加上参数“session”或者“global”来显示 session 级(当前连接)的计结果和 global 级(自数据库上次启动至今)的统计结果。如果不写,默认使用参数是“session”。
2.定位低效率执行SQL。
可以通过以下两种方式定位执行效率较低的 SQL 语句。
- 慢查询日志 : 通过慢查询日志定位那些执行效率较低的 SQL 语句,用–log-slow-queries[=file_name]选项启动时,mysqld 写一个包含所有执行时间超过 long_query_time 秒的 SQL 语句的日志文件。具体可以查看本书第 26 章中日志管理的相关部分。
- show processlist : 慢查询日志在查询结束以后才纪录,所以在应用反映执行效率出现问题的时候查询慢查询日志并不能定位问题,可以使用show processlist命令查看当前MySQL在进行的线程,包括线程的状态、是否锁表等,可以实时地查看 SQL 的执行情况,同时对一些锁表操作进行优化。
3.explain分析执行计划。
通过以上步骤查询到效率低的 SQL 语句后,可以通过 EXPLAIN或者 DESC命令获取 MySQL如何执行 SELECT 语句的信息,包括在 SELECT 语句执行过程中表如何连接和连接的顺序。
4.show profile分析SQL。
5.trace分析优化器执行计划。
5.数据库SQL优化
-
1.大批量插入数据。
1.1主键顺序插入。
因为InnoDB类型的表是按照主键的顺序保存的,所以将导入的数据按照主键的顺序排列,可以有效的提高导入数据的效率。如果InnoDB表没有主键,那么系统会自动默认创建一个内部列作为主键,所以如果可以给表创建一个主键,将可以利用这点,来提高导入数据的效率。
1.2关闭唯一性校验。
在导入数据前执行 SET UNIQUE_CHECKS=0,关闭唯一性校验,在导入结束后执行SET UNIQUE_CHECKS=1,恢复唯一性校验,可以提高导入的效率。
1.3手动提交事务。
如果应用使用自动提交的方式,建议在导入前执行 SET AUTOCOMMIT=0,关闭自动提交,导入结束后再执行 SET AUTOCOMMIT=1,打开自动提交,也可以提高导入的效率。 -
2.优化insert语句。
如果需要同时对一张表插入很多行数据时,应该尽量使用多个值表的insert语句,这种方式将大大的缩减客户端与数据库之间的连接、关闭等消耗。使得效率比分开执行的单个insert语句快。 -
3.优化order by语句。
1.通过对返回数据进行排序,也就是通常说的 filesort 排序,所有不是通过索引直接返回排序结果的排序都叫 FileSort 排序。
2.通过有序索引顺序扫描直接返回有序数据,这种情况即为 using index,不需要额外排序,操作效率高。 -
4.优化group by 语句。
由于GROUP BY 实际上也同样会进行排序操作,而且与ORDER BY 相比,GROUP BY 主要只是多了排序之后的分组操作。当然,如果在分组的时候还使用了其他的一些聚合函数,那么还需要一些聚合函数的计算。所以,在GROUP BY 的实现过程中,与 ORDER BY 一样也可以利用到索引。
如果查询包含 group by 但是用户想要避免排序结果的消耗, 则可以执行order by null 禁止排序。
5.优化嵌套查询。
SQL的子查询可以使用SELECT语句来创建一个单列的查询结果,然后把这个结果作为过滤条件用在另一个查询中。使用子查询可以一次性的完成很多逻辑上需要多个步骤才能完成的SQL操作,同时也可以避免事务或者表锁死,并且写起来也很容易。但是,有些情况下,子查询是可以被更高效的连接(JOIN)替代。
6.优化OR条件。
对于包含OR的查询子句,如果要利用索引,则OR之间的每个条件列都必须用到索引 , 而且不能使用到复合索引; 如果没有索引,则应该考虑增加索引。
7.优化分页查询。
一般分页查询时,通过创建覆盖索引能够比较好地提高性能。一个常见又非常头疼的问题就是 limit 2000000,10 ,此时需要MySQL排序前2000010 记录,仅仅返回2000000 - 2000010 的记录,其他记录丢弃,查询排序的代价非常大 。
1.在索引上完成排序分页操作,最后根据主键关联回原表查询所需要的其他列内容。
2.适用于主键自增的表,可以把Limit 查询转换成某个位置的查询 。
6.使用SQL提示。
在SQL语句中加入一些人为的提示。
1.USE INDEX
在查询语句中表名的后面,添加 use index 来提供希望MySQL去参考的索引列表,就可以让MySQL不再考虑其他可用的索引。
create index idx_seller_name on tb_seller(name);
2.IGNORE INDEX
如果用户只是单纯的想让MySQL忽略一个或者多个索引,则可以使用 ignore index 作为 hint 。
explain select * from tb_seller ignore index(idx_seller_name) where name = '小米科技';
3.FORCE INDEX
为强制MySQL使用一个特定的索引,可在查询中使用 force index 作为hint 。
create index idx_seller_address on tb_seller(address);
7.数据库应用优化
- 1.使用连接池
对于访问数据库来说,建立连接的代价是比较昂贵的,因为我们频繁的创建关闭连接,是比较耗费资源的,我们有必要建立 数据库连接池,以提高访问的性能。 - 2.减少对MySQL的访问
2.1避免对数据进行重复检索。
2.2增加cache层。在应用中,我们可以在应用中增加缓存层来达到减轻数据库负担的目的。缓存层有很多种,也有很多实现方式,只要能达到降低数据库的负担又能满足应用需求就可以。因此可以部分数据从数据库中抽取出来放到应用端以文本方式存储, 或者使用框架(Mybatis)提供的一级缓存/二级缓存,或者使用redis数据库来缓存数据 。 - 3.负载均衡。负载均衡是应用中使用非常普遍的一种优化方法,它的机制就是利用某种均衡算法,将固定的负载量分布到不同的服务器上, 以此来降低单台服务器的负载,达到优化的效果。
3.1 利用MySQL复制分流查询。通过MySQL的主从复制,实现读写分离,使增删改操作走主节点,查询操作走从节点,从而可以降低单台服务器的读写压力。
3.2 采用分布式数据库架构。分布式数据库架构适合大数据量、负载高的情况,它有良好的拓展性和高可用性。通过在多台服务器之间分布数据,可以实现在多台服务器之间的负载均衡,提高访问效率。
六、数据库锁
1.mysql锁的级别?
MySQL有三种锁的级别:表级、行级、页级。
表级锁:开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低。
行级锁:开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高。
页面锁:开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度一般。
2.死锁判定原理和具体场景,死锁怎么解决?
死锁判定原理: 是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等竺的进程称为死锁进程。
具体场景:
表级锁不会产生死锁.所以解决死锁主要还是针对于最常用的InnoDB。
死锁的关键在于:两个(或以上)的Session加锁的顺序不一致。
那么对应的解决死锁问题的关键就是:让不同的session加锁有次序。
死锁的解决办法:
1.查出的线程杀死 kill。
SELECT trx_MySQL_thread_id FROM information_schema.INNODB_TRX;
2.设置锁的超时时间。
3.指定获取锁的顺序。
3.有哪些锁(乐观锁悲观锁),select 时怎么加排它锁?
悲观锁:
悲观锁,先获取锁,再进行业务操作。通常所说的“一锁二查三更新”即指的是使用悲观锁。通常来讲在数据库上的悲观锁需要数据库本身提供支持,即通过常用的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中用悲观锁务必要确定走了索引,而不是全表扫描。
乐观锁:
乐观锁,也叫乐观并发控制。先进行业务操作,不到万不得已不去拿锁。它假设多用户并发的事务在处理时不会彼此互相影响,各事务能够在不产生锁的情况下处理各自影响的那部分数据。在提交数据更新之前,每个事务会先检查在该事务读取数据后,有没有其他事务又修改了该数据。如果其他事务有更新的话,那么当前正在提交的事务会进行回滚。乐观锁在数据库上的实现完全是逻辑的,不需要数据库提供特殊的支持。
注意:
乐观锁在不发生取锁失败的情况下开销比悲观锁小,但是一旦发生失败回滚开销则比较大,因此适合用在取锁失败概率比较小的场景,可以提升系统并发性能。
乐观锁还适用于一些比较特殊的场景,例如在业务操作过程中无法和数据库保持连接等悲观锁无法适用的地方。
总结:
悲观锁和乐观锁是数据库用来保证数据并发安全防止更新丢失的两种方法,例子在select … for update前加个事务就可以防止更新丢失。
悲观锁和乐观锁大部分场景下差异不大,一些独特场景下有一些差别,一般我们可以从如下几个方面来判断:
响应速度: 如果需要非常高的响应速度,建议采用乐观锁方案,成功就执行,不成功就失败,不需要等待其他并发去释放锁。’
冲突频率: 如果冲突频率非常高,建议采用悲观锁,保证成功率,如果冲突频率大,乐观锁会需要多次重试才能成功,代价比较大。
重试代价: 如果重试代价大,建议采用悲观锁。
七、其他
复制是指将主数据库的DDL 和 DML 操作通过二进制日志传到从库服务器中,然后在从库上对这些日志重新执行(也叫重做),从而使得从库和主库的数据保持同步。
MySQL支持一台主库同时向多台从库进行复制, 从库同时也可以作为其他从服务器的主库,实现链状复制。
主从复制:
Master 主库在事务提交时,会把数据变更作为时间 Events 记录在二进制日志文件 Binlog 中。
主库推送二进制日志文件 Binlog 中的日志事件到从库的中继日志 Relay Log 。
slave重做中继日志中的事件,将改变反映它自己的数据。
复制优势
主库出现问题,可以快速切换到从库提供服务。
可以在从库上执行查询操作,从主库中更新,实现读写分离,降低主库的访问压力。
可以在从库中执行备份,以避免备份期间影响主库的服务。
1.数据库的主从复制的几种方式:
同步复制:master的变化,必须等待slave-1,slave-2,…,slave-n完成后才能返回。 这样,显然不可取,也不是MySQL复制的默认设置。比如,在WEB前端页面上,用户增加了条记录,需要等待很长时间。
异步复制:如同AJAX请求一样。master只需要完成自己的数据库操作即可。至于slaves是否收到二进制日志,是否完成操作,不用关心,MySQL的默认设置。
半同步复制:master只保证slaves中的一个操作成功,就返回,其他slave不管。 这个功能,是由google为MySQL引入的。
2.数据库主从复制分析的 7 个问题?
问题1:master的写操作,slaves被动的进行一样的操作,保持数据一致性,那么slave是否可以主动的进行写操作?
假设slave可以主动的进行写操作,slave又无法通知master,这样就导致了master和slave数据不一致了。因此slave不应该进行写操作,至少是slave上涉及到复制的数据库不可以写。实际上,这里已经揭示了读写分离的概念。
问题2:主从复制中,可以有N个slave,可是这些slave又不能进行写操作,要它们干嘛?
1.实现数据备份。
类似于高可用的功能,一旦master挂了,可以让slave顶上去,同时slave提升为master。
2.异地容灾。
比如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挂了,某些slave挂了,那么应用程序就要修改了。能不能让应用程序与MySQL的主从复制架构没有什么太多关系呢?
找一个组件,application program只需要与它打交道,用它来完成MySQL的***,实现SQL语句的路由。MySQL proxy并不负责,怎么从众多的slaves挑一个?可以交给另一个组件(比如haproxy)来完成。
这就是所谓的MySQL READ WRITE SPLITE,MySQL的读写分离。
问题4:如果MySQL proxy , direct , master他们中的某些挂了怎么办?
一般都会弄个副,以防不测。同样的,可以给这些关键的节点来个备份。
问题5:当master的二进制日志每产生一个事件,都需要发往slave,如果我们有N个slave,那是发N次,还是只发一次?如果只发一次,发给了slave-1,那slave-2,slave-3,…它们怎么办?
显 然,应该发N次。实际上,在MySQL master内部,维护N个线程,每一个线程负责将二进制日志文件发往对应的slave。master既要负责写操作,还的维护N个线程,负担会很重。可以这样,slave-1是master的从,slave-1又是slave-2,slave-3,…的主,同时slave-1不再负责select。 slave-1将master的复制线程的负担,转移到自己的身上。这就是所谓的多级复制的概念。
问题6:当一个select发往MySQL proxy,可能这次由slave-2响应,下次由slave-3响应,这样的话,就无法利用查询缓存了。
应该找一个共享式的缓存,比如mem***来解决。将slave-2,slave-3,…这些查询的结果都缓存至mam***中。
问题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)。为了满足事务的原子性,在操作任何数据之前,首先将数据备份到一个地方(这个存储数据备份的地方称为UndoLog)。然后进行数据的修改。如果出现了错误或者用户执行了ROLLBACK语句,系统可以利用Undo Log中的备份将数据恢复到事务开始之前的状态。
事务的原子性:
事务包含的所有操作要么全部成功,要么全部失败回滚。
事务中的所有操作,要么全部完成,要么不做任何操作,不能只做部分操作。如果在执行的过程中发生了错误,要回滚(Rollback)到事务开始前的状态,就像这个事务从来没有执行过。
之所以能同时保证原子性和持久化,是因为以下特点:
更新数据前记录Undo log。
为了保证持久性,必须将数据在事务提交前写到磁盘。只要事务成功提交,数据必然已经持久化。
Undo log必须先于数据持久化到磁盘。如果在G,H之间系统崩溃,undo log是完整的, 可以用来回滚事务。
如果在A-F之间系统崩溃,因为数据没有持久化到磁盘。所以磁盘上的数据还是保持在事务开始前的状态。
缺陷:
每个事务提交前将数据和Undo Log写入磁盘,这样会导致大量的磁盘IO,因此性能很低。
如果能够将数据缓存一段时间,就能减少IO提高性能。但是这样就会丧失事务的持久性。因此引入了另外一种机制来实现持久化,即Redo Log。
Redo Log:
原理和Undo Log相反,Redo Log记录的是新数据的备份。在事务提交前,只要将Redo Log持久化即可,不需要将数据持久化。当系统崩溃时,虽然数据没有持久化,但是Redo Log已经持久化。系统可以根据Redo Log的内容,将所有数据恢复到最新的状态。