前言:
- 跨专业学习的博主要做一个较为完整、系统的知识框架 巩固归纳现在/未来要用到的知识面
- 第一个整理是关于数据库的
- 春宵苦短 少女前进吧!
这里归纳了SQL常见操作句式和数据库系统常见面试问题
常⽤sql句式
- 增加一个列 Alter table tabname add column col type
- 添加主键: Alter table tabname add primary key(col)
- 创建索引:create [unique] index idxname on tabname(col….)
- 删除索引:drop index idxname
- 多列索引:ALTER TABLE people ADD INDEX lname_fname_age (lame,fname,age)
- 选择:select * from table1 where 范围
- 插入:insert into table1(field1,field2) values(value1,value2)
- 删除:delete from table1 where 范围
- 更新:update table1 set field1=value1 where 范围
- 查找:select * from table1 where field1 like ’%value1%’ —like的语法很精妙,查资料!
- 排序:select * from table1 order by field1,field2 [desc]
- 总数:select count as totalcount from table1
文章目录
- 常⽤sql句式
- 一、基本概念
- 1. SQL语言包括哪些类型?
- 2. 主键、外键、超键、候选键
- 4. 触发器【trigger】的作用
- 5. 事前触发和事后触发有何区别?语句级触发和行级触发有何区别?
- 6. 维护数据库的完整性和一致性,你喜欢用触发器还是自写业务逻辑?why?
- 7. 你可以用什么来确保表格里的字段只接受特定范围里的值?
- 8. 什么是存储过程【Procedure】?用什么来调用?有哪些优缺点?
- 10. 什么叫视图【View】?游标【Cursor】是什么?
- 11. drop、truncate、 delete区别
- 12. 什么是临时表【TEMPORARY TABLE 】,临时表什么时候删除?
- 13. 内连接、外连接、交叉连接、笛卡尔积?
- 14.varchar和char的使用场景?
- 15. like %和-的区别
- 16. count(*)、count(1)、count(column)的区别
- 二、数据存储与索引【Indexing】
- 1.什么是索引?
- 2. Mysql各种索引区别:
- 4. 聚集索引和非聚集索引区别?
- 5. 索引的作用?它的优点缺点是什么?
- 6. 哪些列适合建立索引、哪些不适合建索引?索引失效情况
- 7.MySQL B+Tree索引和Hash索引的区别?
- 8. B树和B+树的区别【树型结构】【多路搜索树】
- 9.为什么说B+比B树更适合实际应用中操作系统的文件索引和数据库索引?
- 三、Query Evaluation/优化
- 1. 查询语句不同元素(where、jion、limit、group by、having等等)执行先后顺序?
- 3. MySQL慢查询怎么解决?
- 4. 数据库的优化
- 四、数据库设计
- 1. 数据库范式【NORMAL FORMS】,根据某个场景设计数据表?
- 2. 设计数据库应注意哪些问题
- 五、事务管理 Transaction Management
- 1) Overview:事务 | 并发控制
- 1. 事务【Transaction】四大特性【ACID】
- 2. 并发控制参数:事务隔离级别【Isolation level】,每个级别会引发什么问题
- 3.mysql 高并发环境解决方案?
- 2) 锁【并发控制】
- 1. mysql都有什么锁,死锁判定原理和具体场景,死锁怎么解决?
- 2.有哪些锁(乐观锁悲观锁),select 时怎么加排它锁?
- 3) 崩溃恢复 Crash Recovery
- 1. 数据库崩溃时事务的恢复机制(REDO日志和UNDO日志)?
- 六、存储引擎
- 1.MySQL常见的三种存储引擎(InnoDB、MyISAM、MEMORY)的区别?
- 3.MySQL的MyISAM与InnoDB两种存储引擎在事务、锁级别,各自的适用场景?
- 七、比较 / NoSQL/主从复制
- 1. 了解NoSQL【**Not Only SQL**】
- 2. 非关系型数据库和关系型数据库区别,优势比较?
- 3. 数据库的主从复制:【数据库备份的日常机制】
- 参考资料
【三级标题为常见问题,四级标题为补充知识】
一、基本概念
1. SQL语言包括哪些类型?
- 数据定义DDL:Create Table,Alter Table,Drop Table, Create/Drop Index, …
- CREATE TABLE/VIEW/INDEX/SYN/CLUSTER
- DDL操作是隐性提交的!不能rollback
- 数据操纵DML:Select ,insert,update,delete
- 插入:INSERT
- 更新:UPDATE
- 删除:DELETE
- 数据控制DCL:grant,revoke;授予或回收访问数据库的某种特权,并控制数据库操纵事务发生的时间及效果,对数据库实行监视
- 命令:
- GRANT:授权。
- ROLLBACK [WORK] TO [SAVEPOINT]:回退到某一点。回滚—ROLLBACK;回滚命令使数据库状态回到上次最后提交的状态。其格式为:SQL>ROLLBACK;
- COMMIT [WORK]:提交。
- 在数据库的插入、删除和修改操作时,只有当事务在提交到数据库时才算完成。在事务提交前,只有操作数据库的这个人才能有权看到所做的事情,别人只有在最后提交完成后才可以看到。
- 提交数据有三种类型:显式提交、隐式提交及自动提交。下面分别说明这三种类型。
- 显式提交用COMMIT命令直接完成的提交为显式提交。其格式为:SQL>COMMIT;
- 隐式提交用SQL命令间接完成的提交为隐式提交。这些命令是:ALTER,AUDIT,COMMENT,CONNECT,CREATE,DISCONNECT,DROP,EXIT,GRANT,NOAUDIT,QUIT,REVOKE,RENAME。
- 自动提交若把AUTOCOMMIT设置为ON,则在插入、修改、删除语句执行后,系统将自动进行提交,这就是自动提交。其格式为:SQL>SET AUTOCOMMIT ON;
2. 主键、外键、超键、候选键
- 超键 Superkey:在关系中能唯一标识元组的属性集称为关系模式的超键。一个属性可以为作为一个超键,多个属性组合在一起也可以作为一个超键。超键包含候选键和主键。
- 候选键 Candidate Key:是最小超键,即没有冗余元素的超键
- 主键 Primary Key:数据库表中对储存数据对象予以唯一和完整标识的数据列或属性的组合。一个数据列只能有一个主键,且主键的取值不能为空值(Null)
- 外键 Foreign Key:在一个表中存在的另一个表的主键称此表的外键
3. 主键和外键的区别
- 主键在本表中是唯一的、不可为空的,外键可以重复可以唯空
- 外键和另一张表的主键关联,不能创建对应表中不存在的外键
4. 触发器【trigger】的作用
- 触发器是一种特殊的存储过程,主要是通过事件来触发而被执行的。describes actions to be taken when certain situations arise
- 可以强化约束,来维护数据的完整性和一致性
- 可以跟踪数据库内的操作从而不允许未经许可的更新和变化
- 可以联级运算
5. 事前触发和事后触发有何区别?语句级触发和行级触发有何区别?
- **事前/事后**触发器运行于触发事件发生之前/之后,如表的插入、更新、删除之前/之后
通常事前触发器可以获取事件之前和新的字段值
- **语句级**触发器可以在语句执行前或后执行,而**行级触发**在触发器所影响的每一行触发一次
6. 维护数据库的完整性和一致性,你喜欢用触发器还是自写业务逻辑?why?
1. 使用**约束**,如主键,外键,非空字段等来约束,这样做效率最高,也最方便
2. 使用**触发器**,它可以保证无论什么业务系统访问数据库都可以保证数据的完整新和一致性。触发器是针对每一行的;对增删改非常频繁的表上切记不要使用触发器,因为它会非常消耗资源
3. 最后考虑的是**自写业务逻辑**,但这样做麻烦,编程复杂,效率低下。
7. 你可以用什么来确保表格里的字段只接受特定范围里的值?
- **Check限制**,它在数据库表格里被定义,用来限制输入该列的值
- **触发器【不建议用】**也可被用来限制数据库表格里的字段能够接受的值,但是要求触发器在表格里被定义,可能会在某些情况下影响到性能。
8. 什么是存储过程【Procedure】?用什么来调用?有哪些优缺点?
- **存储过程:**一个预编译的SQL语句,优点是允许模块化的设计,只需创建一次,以后在程序中就可以调用多次,比单纯SQL语句执行要快。存储过程不允许执行return语句,但是可以通过out参数返回多个值,存储过程一般是作为一个独立的部分来执行,
- **调用:**1)可以用一个命令对象来调用存储过程;2)可以供外部程序调用,如java程序
- 优缺点:
- 优点:
- 类似于封装,简化操作,执行效率高
- 不用反复建立一系列处理步骤,保证了数据的完整性,减少数据库开发人员的工作量
- 通过存储过程能够使没有权限的用户在控制之下间接地存取数据库,从而确保数据的安全
- 简化对变动的管理,安全;
- 当SQL语句有变动时,可以只修改数据库中的存储过程而不必修改代码;
- 减少网络传输,在客户端调用一个存储过程当然比执行一串SQL传输的数据量要小;
- 存储过程是一个编译过的代码块,速度快,性能高;
- 缺点:
- SQL本身是一种结构化查询语言,但不是OO的,本质上还是过程化的,面对复杂的业务逻辑,过程化的处理会很吃力
- 存储过程的编写比基本SQL语句复杂,需要较高的技能
- 可能没有创建存储过程的权限
- 移植性差
9. 存储过程与函数的区别??
10. 什么叫视图【View】?游标【Cursor】是什么?
- **视图:**是一种虚拟的表,有一个表或者多个表的行或列的子集,具有和物理表相同的功能。可以对视图进行增,删,改,查操作,对视图的修改会影响基本表。它使得我们获取数据更容易,相比多表查询。
- 注意以下几种情况不能对视图进行插入、更新、删除的操作:
- 视图列中含有统计函数的情况
- 视图使用了GROUP BY /HAVING,DISTINCT,UNION语句的情况
- 视图定义时使用了子查询的情况
- 对视图的修改涉及到了多个基础表的数据
- **游标:**是对查询出来的结果集作为一个单元来有效的处理。游标可以定在该单元中的特定行,从结果集的当前行检索一行或多行。可以对结果集当前行做修改。一般不使用游标,但是需要逐条处理数据的时候,游标显得十分重要。
- 游标的作用
- 在操作mysql的时候,我们知道MySQL检索操作返回一组称为结果集的行。这组返回的行都是与 SQL语句相匹配的行(零行或多行)。使用简单的 SELECT语句,例如,没有办法得到第一行、下一行或前 10行,也不存在每次一行地处理所有行的简单方法(相对于成批地处理它们)。有时,需要在检索出来的行中前进或后退一行或多行。这就是使用游标的原因。
- 游标(cursor)是一个存储在MySQL服务器上的数据库查询,它不是一条 SELECT语句,而是被该语句检索出来的结果集。在存储了游标之后,应用程序可以根据需要滚动或浏览其中的数据。游标主要用于交互式应用,其中用户需要滚动屏幕上的数据,并对数据进行浏览或做出更改。
- 视图的优缺点
- 优点:
- 对数据库的访问,因为视图可以有选择性的选取数据库里的一部分。
- 用户通过简单的查询可以从复杂查询中得到结果。
- 维护数据的独立性,试图可从多个表检索数据。
- 对于相同的数据可产生不同的视图。
- 缺点:
- 性能差:查询视图时,必须把视图的查询转化成对基本表的查询,如果这个视图是由一个复杂的多表查询所定义,那么,那么就无法更改数据
- 修改限制:当用户试图修改试图的某些信息时,数据库必须把它转化为对基本表的某些信息的修改,对于简单的试图来说,这是很方便的,但是,对于比较复杂的试图,可能是不可修改的。
- 视图的使用场景
- 权限控制的时候。当用户需要查询未授权的数据表且又需要部分数据表的部分列进行逻辑处理,不希望用户访问表中某些含敏感信息的列。
- 关键信息来源于多个复杂关联表,可以创建视图提取我们需要的信息,简化操作;
11. drop、truncate、 delete区别
- **drop【DDL】**直接删掉表
- 操作不能回滚,被依赖的约束(constrain)触发器(trigger)索引(index)也会被删除,所有的DML触发器也不会被触发
- **truncate【DDL】【Tabel】**保留表(结构及其列、约束、索引)而删除所有数据
- 再插入时自增长id又从1开始
- 操作立即生效,原数据不放到rollback segment中,不能回滚,也不会触发这个表上触发器
- **delete【DML】【Tabel、View】**删除表中部分数据,可以加where字句
- 放到rollback segement中,事务提交(commmit)之后才生效/回滚(rollback)撤销删除
- 如果有相应的trigger,执行的时候将被触发
- 具体区别:
- 表和索引所占空间。当表被TRUNCATE 后,这个表和索引所占用的空间会恢复到初始大小,而DELETE操作不会减少表或索引所占用的空间。drop语句将表所占用的空间全释放掉。
- 速度一般而言,drop > truncate > delete
- 应用范围:TRUNCATE 只能对TABLE;DELETE可以是table和view
- 在没有备份情况下,谨慎使用 drop 与 truncate。要删除部分数据行采用delete且注意结合where来约束影响范围。回滚段要足够大
- Truncate table速度快,而且效率高,因为truncate table 在功能上与不带 WHERE 子句的 DELETE 语句相同:二者均删除表中的全部行,但 TRUNCATE TABLE 比 DELETE 使用的系统和事务日志资源少。DELETE 语句每次删除一行,并在事务日志中为所删除的每行记录一项。TRUNCATE TABLE 通过释放存储表数据所用的数据页来删除数据,并且只在事务日志中记录页的释放。
- 对于由 FOREIGN KEY 约束引用的表,不能使用 TRUNCATE TABLE,而应使用不带 WHERE 子句的 DELETE 语句。由于 TRUNCATE TABLE 不记录在日志中,所以它不能激活触发器。
12. 什么是临时表【TEMPORARY TABLE 】,临时表什么时候删除?
- 因此在不同的连接中可以创建同名的临时表,并且操作属于本连接的临时表。创建临时表的语法与创建表语法类似,不同之处是增加关键字TEMPORARY,如:CREATE TEMPORARY TABLE tmp_table (NAME VARCHAR (10) NOT NULL, …)
- 可以手动删除:DROP TEMPORARY TABLE IF EXISTS temp_tb,临时表只在当前连接可见
- 当关闭连接时,MySQL会自动删除表并释放所有空间
13. 内连接、外连接、交叉连接、笛卡尔积?
- **内连接:**保证两个表中所有的行都要满足连接条件
- **外连接【左、右、全】:**某些不满条件的列也会显示出来,也就是说,只限制其中一个表的行,而不限制另一个表的行。分左连接、右连接、全连接(mysql不支持)三种。
- 左外连接【left join】: 包含左边表的全部行(不管右边的表中是否存在与它们匹配的行),以及右边表中全部匹配的行:SELECT a.,b. FROM luntan LEFT JOIN usertable as b ON a.username=b.username
- 右外连接【right join】: 包含右边表的全部行(不管左边的表中是否存在与它们匹配的行),以及左边表中全部匹配的行:select A.c1,B.c2 from A right join B on A.c3 = B.c3
- 全外连接【full join】: 包含左、右两个表的全部行,不管另外一边的表中是否存在与它们匹配的行:select A.c1,B.c2 from A full join B on A.c3 = B.c3
- 其他:
- 交叉连接: 生成笛卡尔积——它不使用任何匹配或者选取条件,而是直接将一个数据源中的每个行与另一个数据源的每个行都一一匹配,例如:SELECT type,pub_name FROM titles CROSS JOIN publishers ORDER BY type【结果=内连接查询,但效率不同,内连接查询效率更高】
- 相关子查询是一种包含子查询的特殊类型的查询。查询里包含的子查询会用到外部查询的值。 SELECT * FROM A WHERE A.id IN(SELECT B.aId FROM B WHERE B.name=A.name)
- 自连接(特殊的内连接)、交叉连接、hash join、merge join、nest loop(cluster join)、index join
14.varchar和char的使用场景?
- char的长度是不可变的,varchar的长度是可变的
- 定义一个char[10]和varchar[10]:如果存进去的是‘csdn’,那么char所占的长度依然为10,除了字符‘csdn’外,后面跟六个空格,varchar就立马把长度变为4了,取数据的时候,char类型的要用trim()去掉多余的空格,而varchar是不需要的。
- char的存取数度还是要比varchar要快得多,因为其长度固定,方便程序的存储与查找。
- char也为此付出的是空间的代价,因为其长度固定,所以难免会有多余的空格占位符占据空间,可谓是以空间换取时间效率。varchar是以空间效率为首位。
- char的存储方式是:对英文字符(ASCII)占用1个字节,对一个汉字占用两个字节。varchar的存储方式是:对每个英文字符占用2个字节,汉字也占用2个字节。
- 两者的存储数据都非unicode的字符数据
15. like %和-的区别
- %百分号通配符:表示任何字符出现任意次数(可以是0次).
- %通配符使用:匹配以"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"这样的记录.(一个下划线只能匹配一个字符,不能多也不能少)
- like操作符:LIKE作用是指示mysql后面的搜索模式是利用通配符而不是直接相等匹配进行比较.
- 注意:如果在使用like操作符时,后面的没有使用通用匹配符效果是和=一致的
- SELECT * FROM products WHERE products.prod_name like ‘1000’;只能匹配的结果为1000,而不能匹配像JetPack 1000这样的结果.
- 注意事项:
- 注意大小写
- 注意尾部空格,"%yves"是不能匹配"**heyves "**这样的记录的
- 注意NULL,%通配符可以匹配任意字符,但是不能匹配NULL,也就是说SELECT * FROM products WHERE products.prod_name like '%;是匹配不到products.prod_name为NULL的的记录
16. count(*)、count(1)、count(column)的区别
- **count(*)**对**行的数目**进行计算,包含NULLcount(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’ 的出现。
4. 如果表没有主键,那么count(1)比count(*)快。如果有主键,那么count(主键,联合主键)比count(*)快。如果表只有一个字段,count(*)最快。count(1)跟count(主键)一样,只扫描主键。count(*)跟count(非主键)一样,扫描整个表。明显前者更快一些。
二、数据存储与索引【Indexing】
普遍使用B+Tree做索引,但在实现上又根据聚簇索引和非聚簇索引而不同
1.什么是索引?
- 数据库索引,是数据库管理系统中一个**排序的数据结构,**建立在数据库表中的某些列的上面
- 索引的实现:Hash表 & 变种B+树
- 在数据之外,数据库系统还维护着满足特定查找算法的数据结构,这些数据结构以某种方式引用(指向)数据,这样就可以在这些数据结构上实现高级查找算法
2. Mysql各种索引区别:
- 普通索引:最基本的索引,没有任何限制
- 唯一索引:与"普通索引"类似,不同的就是:索引列的值必须唯一,但允许有空值
- 主键索引:它是一种特殊的唯一索引,不允许有空值
- 全文索引:仅可用于 MyISAM 表,针对较大的数据,生成全文索引很耗时好空间。
- 组合索引:为了更多的提高mysql效率可建立组合索引,遵循”最左前缀“原则。
3. 最左前缀原则
- **多列/组合索引**:ALTER TABLE people ADD INDEX lname_fname_age (lame,fname,age)
- 为了提高搜索效率,我们需要考虑运用多列索引,由于索引文件以B-Tree格式保存,所以我们不用扫描任何记录,即可得到最终结果。注:在mysql中执行查询时,只能使用一个索引,如果我们在lname,fname,age上分别建索引,执行查询时,只能使用一个索引,mysql会选择一个最严格(获得结果集记录数最少)的索引
- 最左前缀原则:就是**最左优先**,我们建立了一个以(a,b,c)为组合的索引,那么将会得到:a, ab,abc三种索引。若我们按列“b”进行查找,或者按列(bc)查找,都不会使用到索引,只有以上三种索引可以使用
4. 聚集索引和非聚集索引区别?
- 聚合索引(clustered index):
- 实现方式中B+Tree的叶子节点上的data就是数据本身,key为主键
- **表记录的排列顺序和索引的排列顺序一致,**所以查询效率快,只要找到第一个索引值记录,其余就连续性的记录在物理也一样连续存放。
- 按照数据的物理存储进行划分的,导致聚簇索引必须是唯一的。聚集索引可以帮助把很大的范围,迅速减小范围。但是查找该记录,就要从这个小范围中Scan了
- 对应的缺点就是修改慢,因为为了保证表中记录的物理和索引顺序一致,在记录插入的时候,会对数据页重新排序。
- E.G. 【聚集索引类似于新华字典中用拼音去查找汉字,拼音检索表于书记顺序都是按照a~z排列的,就像相同的逻辑顺序于物理顺序一样,当你需要查找a,ai两个读音的字,或是想一次寻找多个傻(sha)的同音字时,也许向后翻几页,或紧接着下一行就得到结果】
- 非聚合索引(nonclustered index):
- B+Tree的叶子节点上的data,并不是数据本身,而是数据存放的地址
- **指定了表中记录的逻辑顺序,**但是记录的物理和索引不一定一致,两种索引都采用B+树结构,非聚集索引的叶子层并不和实际数据页相重叠,而采用叶子层包含一个指向表中的记录在数据页中的指针方式。
- 把一个很大的范围,转换成一个小的地图,然后你需要在这个小地图中找你要寻找的信息的位置,最后通过这个位置,再去找你所需要的记录。
- 非聚集索引层次多,不会造成数据重排
- E.G. 【类似在新华字典上通过偏旁部首来查询汉字,检索表也许是按照横、竖、撇来排列的,但是由于正文中是a~z的拼音顺序,所以就类似于逻辑地址于物理地址的不对应。】
- 根本区别:表记录的排列顺序和与索引的排列顺序是否一致
- 聚集索引一个表只能有一个,而非聚集索引一个表可以存在多个
- 聚集索引存储记录是物理上连续存在,而非聚集索引是逻辑上连续,物理存储并不连续
- 聚集索引查询数据速度快,插入数据速度慢;非聚集索引反之
5. 索引的作用?它的优点缺点是什么?
- 索引作用/使用索引原因:协助快速查询、更新数据库表中数据
- 索引的优缺点?
- **优点:**创建索引可以大大提高系统的性能,
- 可以大大加快数据的检索速度,这也是创建索引的最主要的原因。
- 通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性。
- 可以加速表和表之间的连接,特别是在实现数据的参考完整性方面特别有意义。
- 在使用分组和排序子句进行数据检索时,可以显著减少查询中分组和排序的时间。
- 通过使用索引,可以在查询的过程中,使用优化隐藏器,提高系统的性能。
- 缺点:
- 创建索引和维护索引要耗费时间,这种时间随着数据量的增加而增加。
- 索引需要占物理(储存)空间,除了数据表占数据空间之外,每一个索引还要占一定的物理空间,如果要建立聚簇索引,那么需要的空间就会更大。
- 【一个表有过多索引需要有什么样的性能考虑?】当对表中的数据进行**增加、删除和修改的时候,**要花费较多的时间,索引也要动态的维护,这样就降低了数据的维护速度
6. 哪些列适合建立索引、哪些不适合建索引?索引失效情况
- 什么样的字段适合建索引
- 唯一、不为空的字段
- 经常被作查询选择的字段
- 经常作表连接的字段
- 经常出现在order by, group by, distinct 后面的字段
- 建议建索引的情况:
- 基于一个范围的检索,一般查询**返回结果集小于表中记录数的30%**宜采用;
- 基于非唯一性索引的检索
- 在经常需要搜索的列上,可以加快搜索的速度
- 在作为主键的列上,强制该列的唯一性和组织表中数据的排列结构
- 在经常用在连接的列上,这些列主要是一些外键,可以加快连接的速度
- 在经常需要根据范围进行搜索的列上创建索引,因为索引已经排序,其指定范围是连续的
- 在经常需要排序的列上创建索引,因为索引已经排序,这样查询可以利用索引的排序,加快排序查询时间
- 在经常使用在WHERE子句中的列上面创建索引,加快条件的判断速度。
- 不建议建索引的情况:
-
表记录比较少,例如一两千条甚至只有几百条记录的表,没必要建索引,让查询做全表扫描就好了。至于多少条记录才算多,我个人的经验是以2000作为分界线,记录数不超过 2000可以考虑不建索引,超过2000条可以酌情考虑索引。
-
对于那些只有很少数据值的列也不应该增加索引。这是因为,由于这些列的取值很少,例如人事表的性别列,在查询的结果中,结果集的数据行占了表中数据行的很大比例,即需要在表中搜索的数据行的比例很大。增加索引,并不能明显加快检索速度
-
索引的选择性较低。所谓索引的选择性(Selectivity),是指不重复的索引值(也叫基数,Cardinality)与表记录数(#T)的比值:
Index Selectivity = Cardinality / #T
显然选择性的取值范围为(0, 1],选择性越高的索引价值越大。
-
对于那些在查询中很少使用或者参考的列不应该创建索引
-
对于那些定义为text, image和bit数据类型的列不应该增加索引。这是因为,这些列的数据量要么相当大,要么取值很少
-
当修改性能远远大于检索性能时,不应该创建索引。这是因为,修改性能和检索性能是互相矛盾的。当增加索引时,会提高检索性能,但是会降低修改性能;反之。
7.MySQL B+Tree索引和Hash索引的区别?
Hash索引
- Hash索引结构的特殊性,其检索效率远高于BTree索引【前题是键值唯一,如何太多相等hash值就不一定】,索引的检索可以一次定位
B+树索引
- B+树索引需要从根节点到枝节点,最后才能访问到页节点这样多次的IO访问
- 可以用在**=,>,>=,<,<=和between【范围查询、排序、分组等查询特征】**,而且还可以用于like操作符,只要它的查询条件是一个不以通配符开头的常量
- 为什么不都用Hash索引而使用B+树索引?
- Hash索引仅仅能满足对等条件“=”,“IN”,“<=>”查询,不能使用范围查询
- 如果是范围查询检索,这时候哈希索引就毫无用武之地了,因为原先是有序的键值,经过哈希算法后,有可能变成不连续的了,就没办法再利用索引完成范围查询检索;
- 同理,哈希索引没办法利用索引完成排序,以及like ‘xxx%’ 这样的部分模糊查询(这种部分模糊查询,其实本质上也是范围查询);
- 联合索引中,Hash索引不能利用部分索引键查询
对于联合索引中的多个列,Hash是要么全部使用,要么全部不使用,并不支持BTree支持的联合索引的最左前缀【联合索引的前面一个或几个索引键】
- Hash索引无法避免数据的排序操作
由于Hash索引中存放的是经过Hash计算之后的Hash值,而且Hash值的大小关系并不一定和Hash运算前的键值完全一样,所以数据库无法利用索引的数据来避免任何排序运算。
- Hash索引任何时候都不能避免表扫描
- Hash索引是将索引键通过Hash运算之后,将Hash运算结果的Hash值和所对应的行指针信息存放于一个Hash表中,由于不同索引键存在相同Hash值,所以即使满足某个Hash键值的数据的记录条数,也无法从Hash索引中直接完成查询,还是要通过访问表中的实际数据进行比较,并得到相应的结果。
- Hash索引遇到大量Hash值相等的情况后性能并不一定会比BTree高【哈希碰撞】
- 对于选择性比较低的索引键,如果创建Hash索引,那么将会存在大量记录指针信息存于同一个Hash值相关联。这样要定位某一条记录时就会非常麻烦,会浪费多次表数据访问,而造成整体性能低下
- 文件索引和数据库索引为什么使用B+树?
- 文件与数据库都是需要较大的存储,也就是说,它们都不可能全部存储在内存中,故需要存储到磁盘上,索引存在磁盘上
- 索引,则为了数据的快速定位与查找,那么索引的结构组织要尽量减少查找过程中磁盘I/O的存取次数,因此B+树相比B树更为合适
- 数据库系统巧妙利用了局部性原理与磁盘预读原理,将一个节点的大小设为等于一个页,这样每个节点只需要一次I/O就可以完全载入,而红黑树这种结构,高度明显要深的多,并且由于逻辑上很近的节点(父子)物理上可能很远,无法利用局部性
- **方便扫库。**B树必须用中序遍历的方法按序扫库,而B+树直接从叶子结点挨个扫一遍就完了,B+树支持range-query非常方便,而B树不支持,这是数据库选用B+树的最主要原因
8. B树和B+树的区别【树型结构】【多路搜索树】
- 为什么不用二叉树?
- 二叉树算法时间复杂度是lg(N),最坏的情况下查找的次数是树的高度,即io次数为树的高度,查询速度和比较次数都是较小的。
- B-树【O(logn)】查询的次数并不比二叉树的次数小,但是相比起磁盘io速度,内存中比较的耗时就不足为提了。所以只要树的高度足够低,io次数少,就可以提升查找性能。而每个节点中有多个元素,都只在内存中操作。
B-Tree
- B-树的定义如下:【每个节点都存储key和data】【性能总是等价于二分查找(与 M 值无关)】
- **B- 树的搜索:**从根结点开始,对结点内的关键字(有序)序列进行二分查找,如果命中则结束,否则进入查询关键字所属范围的儿子结点;重复,直到所对应的儿子指针为空,或已经是叶子结点;
- B- 树的特性:【B- 树的性能 == 二分查找(与 M 值无关),没有 B 树平衡的问题】
B+Tree【所有的叶子结点中包含了全部关键字的信息】
9.为什么说B+比B树更适合实际应用中操作系统的文件索引和数据库索引?
- 范围查询简单[range query]:b+树不需要中序遍历,遍历链表即可
- B+树只要遍历叶子节点就可以实现整棵树的遍历,而且在数据库中基于范围的查询是非常频繁的,而B树只能中序遍历所有节点,效率太低。
- io次数少:b+树中间节点只存索引,不存在实际的数据,所以可以存储更多的数据。索引树更加的矮胖,io次数更少
- 性能/查询效率稳定:b+树数据只存在于叶子节点,查询性能稳定
- 由于非终结点并不是最终指向文件内容的结点,而只是叶子结点中关键字的索引。所以任何关键字的查找必须走一条从根结点到叶子结点的路。所有关键字查询的路径长度相同,导致每一个数据的查询效率相当。
三、Query Evaluation/优化
1. 查询语句不同元素(where、jion、limit、group by、having等等)执行先后顺序?
查询中用到的关键词主要包含六个,并且他们的顺序依次为
- select–from–where–group by–having–order by
2. 使用explain优化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如何解析查询的额外信息。将在表4.3中讨论,但这里可以看到的坏的例子是Using temporary和Using filesort,意思MySQL根本不能使用索引,结果是检索会很慢。
3. MySQL慢查询怎么解决?
- slow_query_log 慢查询开启状态
- slow_query_log_file 慢查询日志存放的位置(这个目录需要MySQL的运行帐号的可写权限,一般设置为MySQL的数据存放目录)
- long_query_time 查询超过多少秒才记录
4. 数据库的优化
服务层面
系统层面
- 优化数据表结构,将字段较多的表【如果有些字段的使用频率很低】分解成多个表
- 增加中间表【经常需要联合查询的表建立中间表】
- 优化字段类型、字段索引、分表、分库、读写分离
- 使用缓存和NoSQL数据库方式存储,如MongoDB/Memcached/Redis来缓解高并发下数据库查询的压力
数据库层面
应用层面
- 使用缓存和NoSQL数据库方式存储,如MongoDB/Memcached/Redis来缓解高并发下数据库查询的压力
- 提升数据库服务器硬件配置,或者搭建数据库集群
不常使用的数据迁移备份,避免每次都在海量数据中去检索
减少数据库操作次数,尽量使用数据库访问驱动的批处理方法
提升数据库服务器硬件配置or搭建数据库集群
四、数据库设计
1. 数据库范式【NORMAL FORMS】,根据某个场景设计数据表?
- **第一范式【1NF】:**列/属性不可分,数据库表的每一列都是不可分割的原子数据项
- 确保每列保持原子性
- eg:【联系人】(姓名,性别,电话),一个联系人有家庭电话和公司电话,那么这种表结构设计就没有达到 1NF;
- 第二范式【2NF】:满足1NF,表中的非主键字段都依赖与主键字段,有主键,保证完全依赖
- 确保表中的每列都和主键相关
- eg:订单明细表(OrderID,ProductID,UnitPrice,Discount,Quantity, ProductName),Discount(折扣),Quantity(数量)完全依赖(取决)于主键(OderID,ProductID),而 UnitPrice,ProductName 只依赖于 ProductID,不符合2NF;
- **第三范式【3NF】:**满足2NF,表中的非主键字段必须直接依赖于主键字段,无传递依赖(非主键列 A 依赖于非主键列 B,非主键列 B 依赖于主键的情况);属性不依赖于其它非主属性
- 确保每列都和主键列直接相关,而不是间接相关
- eg:
2. 设计数据库应注意哪些问题
- 首先应尽量满足三范式的要求,在一定程度上打破三范式的要求以提高数据库的性能。例如,我们创建某些表的时候,不仅会插入外键,还会插入相关的属性,这违反了第三范式,但这样做的好处,就是我们在业务查询的时候会减少很多关联查询,从而提高查询效率
五、事务管理 Transaction Management
1) Overview:事务 | 并发控制
1. 事务【Transaction】四大特性【ACID】
Transaction定义:
- 并发控制的基本单位;是一个操作序列,这些操作要么都执行,要么都不执行,它是一个不可分割的工作单位
- 事务是对数据库中一系列操作进行统一的回滚或者提交的操作
- 满足ACID特性
- 主要用来保证数据的完整性和一致性。
**作用:**the foundation for concurrent execution and system failure recovery in DBMS
原子性(Atomicity)
- 事务被视为不可分割的最小单元,事务的所有操作要么全部提交成功,要么全部失败回滚
- 回滚可以用日志(log)来实现,日志记录着事务所执行的修改操作,在回滚时反向执行这些修改操作即可
隔离性(Isolation)
- 一个事务所做的修改在最终提交以前,对其它事务是不可见的。
一致性(Consistency)
- 数据库在事务执行前后都保持一致性状态
- 在一致性状态下,所有事务对一个数据的读取结果都是相同的
持久性(Durability)
- 一旦事务提交,则其所做的修改将会永远保存到数据库中。即使系统发生崩溃,事务执行的结果也不能丢失
- 可以通过数据库备份和恢复来实现,在系统发生崩溃时,使用备份数据库恢复数据
2. 并发控制参数:事务隔离级别【Isolation level】,每个级别会引发什么问题
- Every transaction has 3 characteristics: access mode, diagnostics size, and isolation level.
- 通过不同的事务隔离级别,并发事务读取数据的结果是不一样的,数据库可以避免并发事务问题(更新/读问题)
2.1 SERIALIZABLE(串行化)
一个事务在执行过程中完全看不到其他事务对数据库所做的更新。当两个事务同时操作数据库中相同数据时,如果第一个事务已经在访问该数据,第二个事务只能停下来等待,必须等到第一个事务结束后才能恢复运行。因此这两个事务实际上是串行化方式运行。
2.3 READ COMMITTED(读已提交数据)
一个事务在执行过程中可以看到其他事务已经提交的新插入的记录,而且还能看到其他事务已经提交的对已有记录的更新。
2.2 REPEATABLE READ(可重复读)
一个事务在执行过程中可以看到其他事务已经提交的新插入的记录,但是不能看到其他事务对已有记录的更新。
2.4 READ UNCOMMITTED(读未提交数据)
一个事务在执行过程中可以看到其他事务没有提交的新插入的记录,而且还能看到其他事务没有提交的对已有记录的更新。
并发一致性问题:
丢失更新:T1 和 T2 两个事务都对一个数据进行修改,T1 先修改,T2 随后修改,T2 的修改覆盖了 T1 的修改
幻读:T1 读取某个范围的数据,T2 在这个范围内插入新的数据,T1 再次读取这个范围的数据,此时读取结果和和第一次读取结果不同
脏读数据:T1 修改一个数据,T2 随后读取这个数据。如果 T1 撤销了这次修改,那么 T2 读取的数据是脏数据
不可重复读:T2 读取一个数据,T1 对该数据做了修改。如果 T2 再次读取这个数据,此时读取的结果和第一次读取的结果不同
以上四种隔离级别按从高到底排序;SERIALIZABLE最安全,但也是最慢的!四种隔离级别的安全性与性能成反比!
[数据库事务隔离级别]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6JiiKIjw-1582363857718)(notion://www.notion.so/image/https://s3-us-west-2.amazonaws.com/secure.notion-static.com/06bba5a2-0312-4f9e-a74a-8e2a0bb70399/Untitled.png?table=block&id=86836e97-31f2-468f-a2cf-acb66154facc&width=2880&cache=v2)]
3.mysql 高并发环境解决方案?
- MySQL 高并发环境解决方案: 分库 分表 分布式 增加二级缓存
- 需求分析:互联网单位 每天大量数据读取,写入,并发性高
- 现有解决方式:水平分库分表,由单点分布到多点数据库中,从而降低单点数据库压力
- 集群方案:解决DB宕机带来的单点DB不能访问问题
- 读写分离策略:极大限度提高了应用中Read数据的速度和并发量。无法解决高写入压力
2) 锁【并发控制】
数据库管理系统(DBMS)中的并发控制的任务是确保在多个事务同时存取数据库中同一数据时不破坏事务的隔离性和统一性以及数据库的统一性。
**锁:**在所有DBMS中,锁是实现事务的关键,锁可以保证事务的完整性和并发性。与现实生活中锁一样,它可以使某些数据的拥有者,在某段时间内不能使用某些数据或数据结构。当然锁还分级别
1. mysql都有什么锁,死锁判定原理和具体场景,死锁怎么解决?
MyISAM只支持表级锁,用户在操作MyISAM表时,select、update、delete和insert语句都会给表自动加锁,如果加锁以后的表满足insert并发的情况下,可以在表的尾部插入新的数据。InnoDB支持事务和行级锁。行锁大幅度提高了多用户并发操作的新能,但是InnoDB的行锁,只是在WHERE的主键是有效的,非主键的WHERE都会锁全表的。
- MySQL有三种锁的级别:页级、表级、行级
- 表级锁:开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低
- 行级锁:开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高
- 页面锁:开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间
2. 并发度一般什么情况下会造成死锁?什么是死锁?
- 死锁【deadlock】: 是指两个或两个以上的进程在执行过程中。Such a cycle of transactions waiting for locks to be released 因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等竺的进程称为死锁进程。表级锁不会产生死锁.所以解决死锁主要还是针对于最常用的InnoDB。
- 死锁的解决办法?
- 死锁的关键在于:两个(或以上)的Session加锁的顺序不一致。那么对应的解决死锁问题的关键就是:让不同的session加锁有次序。
- 查出的线程杀死 【kill】
- SELECT trx_MySQL_thread_id FROM information_schema.INNODB_TRX
- 设置锁的超时时间
- Innodb 行锁的等待时间innodb_lock_wait_timeout,单位秒。可在会话级别设置,RDS 实例该参数的默认值为 50s,生产环境不推荐使用过大的参数值
- 该参数支持在会话级别修改,方便应用在会话级别单独设置某些特殊操作的行锁等待超时时间,如下:set innodb_lock_wait_timeout=1000;
- 指定获取锁的顺序
2.有哪些锁(乐观锁悲观锁),select 时怎么加排它锁?
【保证数据并发安全,防止更新丢失】
- 悲观锁(Pessimistic Lock):
- 【一锁二查三更新】【假定会发生并发冲突,屏蔽一切可能违反数据完整性的操作】
- 特点:先获取锁,再进行业务操作。
- 即“悲观”的认为获取锁是非常有可能失败的,因此要先确保获取锁成功再进行业务操作
- 通常来讲在数据库上的悲观锁需要数据库本身提供支持,即通过常用的select … for update操作来实现悲观锁。当数据库执行select for update时会获取被select中的数据行的行锁,因此其他并发执行的select for update如果试图选中同一行则会发生排斥(需要等待行锁被释放),因此达到锁的效果。select for update获取的行锁会在当前事务结束时自动释放,因此必须在事务中使用。
- 【补充】不同的数据库对select for update的实现和支持都是有所区别的:
- 悲观锁按照使用性质划分:
- 共享锁(Share locks简记为S锁):也称读锁,事务A对对象T加s锁,其他事务也只能对T加S,多个事务可以同时读,但不能有写操作,直到A释放S锁。
- 排它锁(Exclusivelocks简记为X锁):也称写锁,事务A对对象T加X锁以后,其他事务不能对T加任何锁,只有事务A可以读写对象T直到A释放X锁。
- 更新锁(简记为U锁):用来预定要对此对象施加X锁,它允许其他事务读,但不允许再施加U锁或X锁;当被读取的对象将要被更新时,则升级为X锁,主要是用来防止死锁的
- 悲观锁按照作用范围划分**:行锁 & 表锁**
- 优缺点:
- 乐观锁(Optimistic Lock):
- 【乐观并发控制】【假设不会发生并发冲突,只在提交操作时检查是否违反数据完整性】
- 它假设多用户并发的事务在处理时不会彼此互相影响,各事务能够在不产生锁的情况下处理各自影响的那部分数据。在提交数据更新之前,每个事务会先检查在该事务读取数据后,有没有其他事务又修改了该数据。如果其他事务有更新的话,那么当前正在提交的事务会进行回滚。
- 特点:先进行业务操作,不到万不得已不去拿锁。即“乐观”的认为拿锁多半是会成功的,因此在进行完业务操作需要实际更新数据的最后一步再去拿一下锁就好。乐观锁在数据库上的实现完全是逻辑的,不需要数据库提供特殊的支持。
- 实现方式:需要锁的数据上增加一个版本号,或者时间戳
- 注意:乐观锁在不发生取锁失败的情况下开销比悲观锁小,但是一旦发生失败回滚开销则比较大,因此适合用在取锁失败概率比较小的场景,可以提升系统并发性能乐观锁还适用于一些比较特殊的场景,例如在业务操作过程中无法和数据库保持连接等悲观锁无法适用的地方。
- 优缺点:
- 总结:【读多写少更适合用乐观锁,读少写多更适合用悲观锁】
- 响应速度: 如果需要非常高的响应速度,建议采用乐观锁方案,成功就执行,不成功就失败,不需要等待其他并发去释放锁。
- 冲突频率: 如果冲突频率非常高,建议采用悲观锁,保证成功率,如果冲突频率大,乐观锁会需要多次重试才能成功,代价比较大。
- 重试代价: 如果重试代价大,建议采用悲观锁。
3) 崩溃恢复 Crash Recovery
1. 数据库崩溃时事务的恢复机制(REDO日志和UNDO日志)?
- Undo Log:
- Undo Log是为了实现事务的原子性,在MySQL数据库InnoDB存储引擎中,还用了Undo Log来实现多版本并发控制(简称:MVCC)。
- 为了满足事务的原子性,在操作任何数据之前,首先将数据备份到一个地方(这个存储数据备份的地方称为UndoLog)。然后进行数据的修改。如果出现了错误或者用户执行了ROLLBACK语句,系统可以利用Undo Log中的备份将数据恢复到事务开始之前的状态。
- 之所以能同时保证原子性和持久化,是因为以下特点:更新数据前记录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的内容,将所有数据恢复到最新的状态。
六、存储引擎
1.MySQL常见的三种存储引擎(InnoDB、MyISAM、MEMORY)的区别?
-
横向比较:
在MySQL 5.5之前,MyISAM是mysql的默认数据库引擎,虽然MyISAM性能极佳,但却有一个显著的缺点: 不支持事务处理。不过,MySQL也导入了另一种数据库引擎InnoDB,以强化参考完整性与并发违规处理机制,后来就逐渐取代MyISAM。InnoDB的最大特色就是支持ACID兼容的事务功能,类似于PostgreSQL。
- **存储结构:**每个MyISAM在磁盘上存储成三个文件:第一个文件的名字以表的名字开始,扩展名指出文件类型。.frm文件存储表定义,数据文件的扩展名为.MYD (MYData),索引文件的扩展名是.MYI (MYIndex)。InnoDB所有的表都保存在同一个数据文件中(也可能是多个文件,或者是独立的表空间文件),InnoDB表的大小只受限于操作系统文件的大小,一般为2GB。
- 存储空间:MyISAM可被压缩,占据的存储空间较小,支持静态表、动态表、压缩表三种不同的存储格式。InnoDB需要更多的内存和存储,它会在主内存中建立其专用的缓冲池用于高速缓冲数据和索引。
- **可移植性、备份及恢复:**MyISAM的数据是以文件的形式存储,所以在跨平台的数据转移中会很方便,同时在备份和恢复时也可单独针对某个表进行操作。InnoDB免费的方案可以是拷贝数据文件、备份 binlog,或者用 mysqldump,在数据量达到几十G的时候就相对痛苦了。
- **事务支持:**MyISAM强调的是性能,每次查询具有原子性,其执行数度比InnoDB类型更快,但是不提供事务支持。InnoDB提供事务、外键等高级数据库功能,具有事务提交、回滚和崩溃修复能力。
- **AUTO_INCREMENT:**在MyISAM中,可以和其他字段一起建立联合索引。引擎的自动增长列必须是索引,如果是组合索引,自动增长可以不是第一列,它可以根据前面几列进行排序后递增。InnoDB中必须包含只有该字段的索引,并且引擎的自动增长列必须是索引,如果是组合索引也必须是组合索引的第一列。
- **表锁差异:**MyISAM只支持表级锁,用户在操作MyISAM表时,select、update、delete和insert语句都会给表自动加锁,如果加锁以后的表满足insert并发的情况下,可以在表的尾部插入新的数据。InnoDB支持事务和行级锁。行锁大幅度提高了多用户并发操作的新能,但是InnoDB的行锁,只是在WHERE的主键是有效的,非主键的WHERE都会锁全表的。
- 全文索引:MyISAM支持 FULLTEXT类型的全文索引;InnoDB不支持FULLTEXT类型的全文索引,但是innodb可以使用sphinx插件支持全文索引,并且效果更好。
- 表主键:MyISAM允许没有任何索引和主键的表存在,索引都是保存行的地址。对于InnoDB,如果没有设定主键或者非空唯一索引,就会自动生成一个6字节的主键(用户不可见),数据是主索引的一部分,附加索引保存的是主索引的值。
- 表的具体行数:MyISAM保存表的总行数,select count() from table;会直接取出出该值;而InnoDB没有保存表的总行数,如果使用select count() from table;就会遍历整个表,消耗相当大,但是在加了wehre条件后,myisam和innodb处理的方式都一样。
- **CURD操作:**在MyISAM中,如果执行大量的SELECT,MyISAM是更好的选择。对于InnoDB,如果你的数据执行大量的INSERT或UPDATE,出于性能方面的考虑,应该使用InnoDB表。DELETE从性能上InnoDB更优,但DELETE FROM table时,InnoDB不会重新建立表,而是一行一行的删除,在innodb上如果要清空保存有大量数据的表,最好使用truncate table这个命令。
- 外键:MyISAM不支持外键,而InnoDB支持外键。
通过上述的分析,基本上可以考虑使用InnoDB来替代MyISAM引擎了,原因是InnoDB自身很多良好的特点,比如事务支持、存储过程、视图、行级锁、外键等等。尤其在并发很多的情况下,相信InnoDB的表现肯定要比MyISAM强很多。另外,必须需要注意的是,任何一种表都不是万能的,合适的才是最好的,才能最大的发挥MySQL的性能优势。如果是不复杂的、非关键的Web应用,还是可以继续考虑MyISAM的,这个具体情况具体考虑
-
InnoDB【支持高级功能】
- InnoDB用于事务处理应用程序、行级锁,具有众多特性,包括ACID事务支持。如果应用中需要执行大量的INSERT或UPDATE操作,则应该使用InnoDB,这样可以提高多用户并发操作的性能。
- 适合频繁修改以及涉及到安全性较高的应用
- InnoDB支持事务。事务是一种高级的处理方式,如在一些列增删改中只要哪个出错还可以回滚还原,而MyISAM就不可以了
- 不支持FULLTEXT类型的索引
- InnoDB**支持行锁(**某些情况下还是锁整表,如 update table set a=1 where user like ‘%lee%’
- 支持外键foreign key
- 不保存表的行数,如select count() from table时,InnoDB需要扫描一遍整个表来计算有多少行
- 对于自增长的字段,InnoDB中必须包含只有该字段的索引
- DELETE FROM table时,InnoDB不会重新建立表,而是一行一行的删除,效率非常慢
- 聚簇索引主要用在Innodb存储引擎中
- 从MySQL5.5.5以后,InnoDB是默认引擎
- MyISAM【性能更优】
- MyISAM管理非事务表,用于只读程序。它提供高速存储和检索,以及全文搜索能力。如果应用中需要执行大量的SELECT查询,那么MyISAM是更好的选择。
- 适合查询以及插入为主的应用
- 不支持事务
- 只支持表锁
- 支持FULLTEXT类型的索引
- 不支持外键
- **保存表的行数,**MyISAM只要简单的读出保存好的行数即可。注意的是,当count()语句包含where条件时MyISAM也需要扫描整个表
- 对于自增长的字段,MyISAM表中可以和其他字段一起建立联合索引
- DELETE FROM table时,MyISAM则会重建表
- 非聚族索引主要用在MyISAM存储引擎
- 2. MySQL存储引擎MyISAM与InnoDB如何选择
- 现在一般都是选用innodb了,主要是MyISAM的全表锁,读写串行问题,并发效率锁表,效率低,MyISAM对于读写密集型应用一般是不会去选用的。
- 如果你的应用程序一定要使用事务,毫无疑问你要选择INNODB引擎。但要注意,INNODB的行级锁是有条件的。在where条件没有使用主键时,照样会锁全表。比如DELETE FROM mytable这样的删除语句。
- 如果你的应用程序对查询性能要求较高,就要使用MyISAM了。MyISAM索引和数据是分开的,而且其索引是压缩的,可以更好地利用内存。所以它的查询性能明显优于INNODB。压缩后的索引也能节约一些磁盘空间。MyISAM拥有全文索引的功能,这可以极大地优化LIKE查询的效率。
- 有人说MyISAM只能用于小型应用,其实这只是一种偏见。如果数据量比较大,这是需要通过升级架构来解决,比如分表分库,而不是单纯地依赖存储引擎。
- 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:支持事务和行级锁。行锁大幅度提高了多用户并发操作的新能。但是行锁,只是在WHERE的主键是有效的,非主键的WHERE都会锁全表的。
七、比较 / NoSQL/主从复制
1. 了解NoSQL【Not Only SQL】
- 非关系型的数据存储
- 易于数据的分散
- 没有声明性查询语言
- 没有预定义的模式
- 最终一致性,而非ACID属性
- 非结构化和不可预知的数据
- 高性能,高可用性和可伸缩性
- 键 - 值对存储,列存储,文档存储,图形数据库
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3BhcMYmX-1582363599920)(https://s3-us-west-2.amazonaws.com/secure.notion-static.com/097e399b-5c23-43aa-b364-faca09e2d49c/Untitled.png)]
-
CAP定理:任何分布式系统只可同时满足二点,没法三者兼顾
- Consistency(一致性), 数据一致更新,所有数据变动都是同步的
- Availability(可用性), 好的响应性能
- Partition tolerance(分区容错性) 可靠性
P: 系统中任意信息的丢失或失败不会影响系统的继续运作。
-
根据 CAP 原理将 NoSQL 数据库分成了满足 CA 原则、满足 CP 原则和满足 AP 原则三大类:
CA - 单点集群,满足一致性,可用性的系统,通常在可扩展性上不太强大。
CP - 满足一致性,分区容忍性的系统,通常性能不是特别高。
AP - 满足可用性,分区容忍性的系统,通常可能对一致性要求低一些。
2. 非关系型数据库和关系型数据库区别,优势比较?
对于这两类数据库,对方的优势就是自己的弱势,反之亦然。
- 关系型数据库的优缺点
- 优点:
- 事务支持:使得对于安全性能很高的数据访问要求得以实现;保持数据的一致性
- 由于以标准化为前提,数据更新的开销很小(相同的字段基本上只有一处)
- 复杂查询、可以进行JOIN等复杂的操作
- 存在很多实际成果和专业技术信息(成熟的技术)
- 缺点:
- 大量数据的写入处理
- 为有数据更新的表做索引或变更表结构
- 字段不固定时使用
- 对于简单查询需要快速返回结果的业务处理
- 适合处理一般量级的数据(银行转账和钱)
- 非关系数据库的优缺点
- 优点:
- 性能:NOSQL是基于键值对的,可以想象成表中的主键和值的对应关系,不需要经过SQL层的解析,所以性能非常高。
- 可扩展性:同样也是因为基于键值对,数据之间没有耦合性,所以非常容易水平扩展。
- 海量数据的增删改查是可以的【如MongoDB】
- 对于事务的支持也可以用一些系统级的原子操作来实现例如乐观锁之类的方法来曲线救国,比如Redis set nx【原子性就是对数据的更改要么全部执行,要么全部不执行】
- 海量数据的维护和处理非常轻松
- 缺点:
- 数据和数据没有关系,他们之间就是单独存在的
- 非关系数据库没有关系,没有强大的事务关系,没有保证数据的完整性和安全性
- 适合处理海量数据,保证效率,不一定安全(统计数据,例如微博数据)
3. 数据库的主从复制:【数据库备份的日常机制】
以主机器为准,从机器进行拷贝复制,防止主机器挂掉时,让机器能够恢复工作
- 主从复制的几种方式:
- 同步复制:意思是master的变化,必须等待slave-1,slave-2,…,slave-n完成后才能返回。 这样,显然不可取,也不是MySQL复制的默认设置。比如,在WEB前端页面上,用户增加了条记录,需要等待很长时间。
- 异步复制【MySQL的默认设置】:如同AJAX请求一样。master只需要完成自己的数据库操作即可。至于slaves是否收到二进制日志,是否完成操作,不用关心,
- 半同步复制:master只保证slaves中的一个操作成功,就返回,其他slave不管。 这个功能,是由google为MySQL引入的
- binlog与redo/undo log区别:
- 层次不同。redo/undo 是 innoDB 引擎层维护的,而 binlog 是 mysql server 层维护的,跟采用何种引擎没有关系,记录的是所有引擎的更新操作的日志记录。
- 记录内容不同。redo/undo 记录的是 每个页/每个数据 的修改情况,属于物理日志+逻辑日志结合的方式(redo log 是物理日志,undo log 是逻辑日志)。binlog 是逻辑日志,记录的都是事务操作内容,binlog 有三种模式:Statement(基于 SQL 语句的复制)、Row(基于行的复制) 以及 Mixed(混合模式)。不管采用的是什么模式,当然格式是二进制的
- statement:基于SQL语句的模式,某些语句中含有一些函数,例如
UUID
NOW
等在复制过程可能导致数据不一致甚至出错。
- row:基于行的模式,记录的是行的变化,很安全。但是 binlog 的磁盘占用会比其他两种模式大很多,在一些大表中清除大量数据时在 binlog 中会生成很多条语句,可能导致从库延迟变大。
- mixed:混合模式,根据语句来选用是 statement 还是 row 模式。
- 记录时机不同。redo/undo 在 事务执行过程中 会不断的写入(循环写),日志空间大小固定,而 binlog 是在 事务最终提交前 写入的(追加写),是指一份写到一定大小的时候会更换下一个文件,不会覆盖。binlog 什么时候刷新到磁盘跟参数
sync_binlog
相关
- binlog可以作为恢复数据使用,主从复制搭建,redo log作为异常宕机或者介质故障后的数据恢复使用。
4.数据库主从复制分析的 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挂了,某些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响应,这样的话,就无法利用查询缓存了。
- 应该找一个共享式的缓存,比如memcache来解决。将slave-2,slave-3,...这些查询的结果都缓存至mamcache中。
> **问题7:**随着应用的日益增长,读操作很多,我们可以扩展slave,但是如果master满足不了写操作了,怎么办呢?
- scale on ?更好的服务器? 没有最好的,只有更好的,太贵了
- scale out ? 主从复制架构已经满足不了。
- 可以分库【垂直拆分】,分表【水平拆分】。
参考资料
- 《Database management systems》------ Raghu Ramakrishnan, Johannes Gehrke
- https://www.cnblogs.com/wenxiaofei/p/9853682.html
- https://blog.csdn.net/snowbaby1234/article/details/81238760
- https://blog.csdn.net/justloveyou_/article/details/78308460
- https://www.jianshu.com/p/57c510f4ec28