数据库常见面试题一
- 一、基本概念
- 1.主键、外键、超键、候选键
- 2.为什么用自增列作为主键
- 3.触发器的作用?
- 4.什么是存储过程?用什么来调用?
- 5.存储过程的优缺点?
- 6.存储过程与函数的区别
- 7.什么叫视图?游标是什么?
- 8.视图的优缺点
- 9.drop、truncate、 delete区别
- 10.什么是临时表,临时表什么时候删除?
- 11.非关系型数据库和关系型数据库区别,优势比较?
- 12.数据库范式,根据某个场景设计数据表?
- 13.什么是 内连接、外连接、交叉连接、笛卡尔积等?
- 14.varchar和char的使用场景?
- 15.SQL语言分类
- 16.like %和-的区别
- 17.count(*)、count(1) 、count(column),的区别
- 18.最左前缀原则
- 19.SQL 注入
- 20.Redis
- 20.1、 有没有使用过redis? Redis是什么
- 20.2、Redis和memche的比较?
- 20.3、 简单说一下redis的使用场景?
- 20.4、 redis对象保存方式?
- 20.5、 Redis数据淘汰机制
- 20.6、 Java访问Redis
- 20.7、 Redis集群
- 二、索引
- 1.什么是索引?
- 2.索引的作用?
- 3.索引的优缺点?
- 3.1、索引具体的优缺点
- 3.2、哪些列适合建立索引?
- 3.3、对于有些列不应该创建索引:
- 4.什么样的字段适合建索引
- 5.MySQL B+Tree索引和Hash索引的区别?
- 5.1、Hash索引和B+树索引的特点:
- 5.2、为什么不都用Hash索引而使用B+树索引?
- 6.B树和B+树的区别
- 7.为什么说B+比B树更适合实际应用中操作系统的文件索引和数据库索引?
- 8.聚集索引和非聚集索引区别?
- 9.索引的最左匹配原则?
- 10.普通索引、唯一索引、主索引
- 三、事务
- 1.什么是事务?
- 2.事务四大特性(ACID)原子性、一致性、隔离性、持久性?
- 3.事务的并发?事务隔离级别,每个级别会引发什么问题,MySQL默认是哪个级别?
- 4.事务传播行为
- 5.嵌套事务
- 5.1、什么是嵌套事务?
- 5.2、如果子事务回滚,会发生什么?
- 5.3、如果父事务回滚,会发生什么?
- 5.4、事务的提交,是什么情况?
(根据自己的面试经验总结的知识点,内容比较浅显,有问题的地方欢迎指正呀)
一、基本概念
1.主键、外键、超键、候选键
- 超键:在关系中能唯一标识元组的属性集称为关系模式的超键。一个属性可以为作为一个超键,多个属性组合在一起也可以作为一个超键。超键包含候选键和主键。
- 候选键:是最小超键,即没有冗余元素的超键。
- 主键:数据库表中对储存数据对象予以唯一和完整标识的数据列或属性的组合。一个数据列只能有一个主键,且主键的取值不能缺失,即不能为空值(Null)。
- 外键:在一个表中存在的另一个表的主键称此表的外键。
1.1、主键、外键的作用?
- 主键:是表中的唯一标示键。作用:保证实体的完整性;加快数据库的操作速度;增加新的表记录时,数据库会自动检索新记录的主键值,不允许该值与其他表中记录的主键重复;数据库会按主键值的顺序显示记录,如果没有设定主键,则按输入的顺序显示记录。
- 外键:是主键的从属,表示了两个表之间的联系。作用:使用外键可以避免冗余。
2.为什么用自增列作为主键
如果我们定义了主键(PRIMARY KEY),那么InnoDB会选择主键作为聚集索引
如果没有显式定义主键,则InnoDB会选择第一个不包含有NULL值的唯一索引作为主键索引、
如果也没有这样的唯一索引,则InnoDB会选择内置6字节长的ROWID作为隐含的聚集索引(ROWID随着行记录的写入而主键递增,这个ROWID不像ORACLE的ROWID那样可引用,是隐含的)。
数据记录本身被存于主索引(一颗B+Tree)的叶子节点上。这就要求同一个叶子节点内(大小为一个内存页或磁盘页)的各条数据记录按主键顺序存放,因此每当有一条新的记录插入时,MySQL会根据其主键将其插入适当的节点和位置,如果页面达到装载因子(InnoDB默认为15/16),则开辟一个新的页(节点)
如果表使用自增主键,那么每次插入新的记录,记录就会顺序添加到当前索引节点的后续位置,当一页写满,就会自动开辟一个新的页
如果使用非自增主键(如果身份证号或学号等),由于每次插入主键的值近似于随机,因此每次新纪录都要被插到现有索引页得中间某个位置,此时MySQL不得不为了将新记录插到合适位置而移动数据,甚至目标页面可能已经被回写到磁盘上而从缓存中清掉,此时又要从磁盘上读回来,这增加了很多开销,同时频繁的移动、分页操作造成了大量的碎片,得到了不够紧凑的索引结构,后续不得不通过OPTIMIZE TABLE来重建表并优化填充页面。
3.触发器的作用?
触发器是一种特殊的存储过程,主要是通过事件来触发而被执行的。它可以强化约束,来维护数据的完整性和一致性,可以跟踪数据库内的操作从而不允许未经许可的更新和变化。可以联级运算。如,某表上的触发器上包含对另一个表的数据操作,而该操作又会导致该表触发器被触发。
4.什么是存储过程?用什么来调用?
存储过程是一个预编译的SQL语句,优点是允许模块化的设计,就是说只需创建一次,以后在该程序中就可以调用多次。如果某次操作需要执行多次SQL,使用存储过程比单纯SQL语句执行要快。
调用:
1)可以用一个命令对象来调用存储过程。
2)可以供外部程序调用,比如:java程序。
5.存储过程的优缺点?
优点:
1)存储过程是预编译过的,执行效率高。
2)存储过程的代码直接存放于数据库中,通过存储过程名直接调用,减少网络通讯。
3)安全性高,执行存储过程需要有一定权限的用户。
4)存储过程可以重复使用,可减少数据库开发人员的工作量。
缺点:移植性差
6.存储过程与函数的区别
存储过程是用户定义的一系列sql语句的集合,涉及特定表或其它对象的任务,用户可以调用存储过程。
而函数通常是数据库已定义的方法,它接收参数并返回某种类型的值并且不涉及特定用户表。
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是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.什么是临时表,临时表什么时候删除?
临时表可以手动删除:
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.数据库范式,根据某个场景设计数据表?
- 第一范式:(确保每列保持原子性)所有字段值都是不可分解的原子值。
第一范式是最基本的范式。如果数据库表中的所有字段值都是不可分解的原子值,就说明该数据库表满足了第一范式。
第一范式的合理遵循需要根据系统的实际需求来定。比如某些数据库系统中需要用到“地址”这个属性,本来直接将“地址”属性设计成一个数据库表的字段就行。但是如果系统经常会访问“地址”属性中的“城市”部分,那么就非要将“地址”这个属性重新拆分为省份、城市、详细地址等多个部分进行存储,这样在对地址中某一部分操作的时候将非常方便。这样设计才算满足了数据库的第一范式,如下表所示。
上表所示的用户信息遵循了第一范式的要求,这样在对用户使用城市进行分类的时候就非常方便,也提高了数据库的性能。
- 第二范式:(确保表中的每列都和主键相关)在一个数据库表中,一个表中只能保存一种数据,不可以把多种数据保存在同一张数据库表中。
第二范式在第一范式的基础之上更进一层。第二范式需要确保数据库表中的每一列都和主键相关,而不能只与主键的某一部分相关(主要针对联合主键而言)。也就是说在一个数据库表中,一个表中只能保存一种数据,不可以把多种数据保存在同一张数据库表中。
比如要设计一个订单信息表,因为订单中可能会有多种商品,所以要将订单编号和商品编号作为数据库表的联合主键。
- 第三范式:(确保每列都和主键列直接相关,而不是间接相关) 数据表中的每一列数据都和主键直接相关,而不能间接相关。
第三范式需要确保数据表中的每一列数据都和主键直接相关,而不能间接相关。
比如在设计一个订单数据表的时候,可以将客户编号作为一个外键和订单表建立相应的关系。而不可以在订单表中添加关于客户其它信息(比如姓名、所属公司等)的字段。
- BCNF:符合3NF,并且,主属性不依赖于主属性。
若关系模式属于第二范式,且每个属性都不传递依赖于键码,则R属于BC范式。
通常BC范式的条件有多种等价的表述:每个非平凡依赖的左边必须包含键码;每个决定因素必须包含键码。
BC范式既检查非主属性,又检查主属性。当只检查非主属性时,就成了第三范式。满足BC范式的关系都必然满足第三范式。
还可以这么说:若一个关系达到了第三范式,并且它只有一个候选码,或者它的每个候选码都是单属性,则该关系自然达到BC范式。
一般,一个数据库设计符合3NF或BCNF就可以了。
- 第四范式:要求把同一表内的多对多关系删除。
- 第五范式:从最终结构重新建立原始结构。
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的使用场景?
- 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个字节。
4.两者的存储数据都非unicode的字符数据。
15.SQL语言分类
SQL语言共分为四大类:
数据查询语言DQL
数据操纵语言DML
数据定义语言DDL
数据控制语言DCL。
- 数据查询语言DQL
数据查询语言DQL基本结构是由SELECT子句,FROM子句,WHERE子句组成的查询块:
SELECT FROM WHERE
2 .数据操纵语言DML
数据操纵语言DML主要有三种形式:
- 插入:INSERT
- 更新:UPDATE
- 删除:DELETE
- 数据定义语言DDL
数据定义语言DDL用来创建数据库中的各种对象-----表、视图、索引、同义词、聚簇等如:
CREATE TABLE/VIEW/INDEX/SYN/CLUSTER
表 视图 索引 同义词 簇
DDL操作是隐性提交的!不能rollback
- 数据控制语言DCL
数据控制语言DCL用来授予或回收访问数据库的某种特权,并控制数据库操纵事务发生的时间及效果,对数据库实行监视等。如:
- GRANT:授权。
- ROLLBACK [WORK] TO [SAVEPOINT]:回退到某一点。回滚—ROLLBACK;回滚命令使数据库状态回到上次最后提交的状态。其格式为:
SQL>ROLLBACK;
- COMMIT [WORK]:提交。
在数据库的插入、删除和修改操作时,只有当事务在提交到数据库时才算完成。在事务提交前,只有操作数据库的这个人才能有权看到所做的事情,别人只有在最后提交完成后才可以看到。提交数据有三种类型:显式提交、隐式提交及自动提交。下面分别说明这三种类型。
(1) 显式提交
用COMMIT命令直接完成的提交为显式提交。其格式为:SQL>COMMIT;
(2) 隐式提交
用SQL命令间接完成的提交为隐式提交。这些命令是:ALTER,AUDIT,COMMENT,CONNECT,CREATE,DISCONNECT,DROP,EXIT,GRANT,NOAUDIT,QUIT,REVOKE,RENAME。
(3) 自动提交
若把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’的出现
(4)如果表没有主键的话,count(1)比count()快,因为count(1)与count(主键) 一样 ,只扫描主键,但是count()与count(非主键)一样,扫描整个表
(5)如果有主键,count(主键,联合主键)比count()快
(6)如果只有一个字段,count()最快
count和sum的区别
count()是算行数的,sum是求和的
18.最左前缀原则
多列索引:ALTER TABLE people ADD INDEX lname_fname_age (lame,fname,age);
为了提高搜索效率,我们需要考虑运用多列索引,由于索引文件以B-Tree格式保存,所以我们不用扫描任何记录,即可得到最终结果。
注:在mysql中执行查询时,只能使用一个索引,如果我们在lname,fname,age上分别建索引,执行查询时,只能使用一个索引,mysql会选择一个最严格(获得结果集记录数最少)的索引。
最左前缀原则:顾名思义,就是最左优先,上例中我们创建了lname_fname_age多列索引,相当于创建了(lname)单列索引,(lname,fname)组合索引以及(lname,fname,age)组合索引。
19.SQL 注入
SQL注入就是通过把SQL命令插入到Web表单提交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令。总体思路(1). 寻找到SQL注入的位置 (2). 判断服务器类型和后台数据库类型 (3). 针对不通的服务器和数据库特点进行SQL注入攻击
19.1、常见的Sql注入的手段:
(1) 构造可以正常运行的目标地址:http://172.18.3.13:81/login.asp?name=admin &pass=admin’ and ‘1=1,用恒等式作为判断条件
(2) 猜解数据库表名:http://172.18.3.13:81/login.asp?pass=admin&pass=admin’ and (select count(*)from data)>0 and ‘a’=‘a’,成功则证明数据库表明确实为data
(3) 猜解数据库字段名:http://172.18.3.13:81/login.asp?pass=admin&pass=admin’ and (select count(uname)from data)>0 and ‘a’=‘a’,若用户名为usname,则成功。同理是密码字段名
(4) 猜测密码长度,一直尝试
19.2、常见的Sql注入的防范手段:
(1) 普通用户与系统管理员用户的权限要有严格的区分 (2)、 强迫使用参数化语句(3)、 加强对用户输入的验证。(4)、 多多使用SQL Server数据库自带的安全参数。(5) 必要的情况下使用专业的漏洞扫描工具来寻找可能被攻击的点(6)、设置陷阱账号:设置两个帐号,一个是普通管理员帐号,一个是防注入的帐号。将防注入的账号设置的很象管理员,如 admin,以制造假象吸引软件的检测,而密码是大于千字以上的中文字符,迫使软件分析账号的时候进入全负荷状态甚至资源耗尽而死机
20.Redis
20.1、 有没有使用过redis? Redis是什么
Redis是一个key-value的nosql数据库.先存到内存中,会根据一定的策略持久化到磁盘,即使断电也不会丢失数据。支持的数据类型比较多。
主要用来做缓存数据库的数据和web集群时当做中央缓存存放seesion
20.2、Redis和memche的比较?
1、 Redis和Memcache都是将数据存放在内存中,都是内存数据库。不过memcache还可用于缓存其他东西,例如图片、视频等等。
2、Redis不仅仅支持简单的k/v类型的数据,同时还提供list,set,hash等数据结构的存储。
3、虚拟内存–Redis当物理内存用完时,可以将一些很久没用到的value 交换到磁盘
20.3、 简单说一下redis的使用场景?
- 缓存:把经常需要查询的、很少修改数据,放到读速度很快的空间(内存),以便下次访问减少时间。减轻压力,减少访问时间.
- 计数器:redis中的计数器是原子性的内存操作。 可以解决库存溢出问题.进销存系统库存溢出。
- session缓存服务器:web集群时作为session缓存服务器
- 缓存队列等
20.4、 redis对象保存方式?
Json字符串:
需要把对象转换为json字符串,当做字符串处理。直接使用set get来设置或者或。
优点:设置和获取比较简单
缺点:没有提供专门的方法,需要把把对象转换为json。(jsonlib)
字节:
需要做序列号,就是把对象序列化为字节保存。
如果是担心JSON转对象会消耗资源的情况,这个问题需要考量几个地方,
第一点:就是使用的JSON转换lib是否就会存在性能问题。
第二点:就是数据的数据量级别,如果是存储百万级的大数据对象,建议采用存储序列化对象方式。如果是少量的数据级对象,或者是数据对象字段不多,还是建议采用JSON转换成String方式。
毕竟redis对存储字符类型这部分优化的非常好。具体采用的方式与方法,还要看你所使用的场景。
20.5、 Redis数据淘汰机制
在 redis 中,允许用户设置最大使用内存大小 server.maxmemory,在内存限定的情况下是很有用的。譬如,在一台 8G 机子上部署了 4 个 redis 服务点,每一个服务点分配 1.5G 的内存大小,减少内存紧张的情况,由此获取更为稳健的服务。
内存大小有限,需要保存有效的数据?
redis 内存数据集大小上升到一定大小的时候,就会施行数据淘汰策略。
redis 提供 6种数据淘汰策略:
- volatile-lru:从已设置过期时间的数据集(server.db[i].expires)中挑选最近最少使用的数据淘汰
- volatile-ttl:从已设置过期时间的数据集(server.db[i].expires)中挑选将要过期的数据淘汰
- volatile-random:从已设置过期时间的数据集(server.db[i].expires)中任意选择数据淘汰
- allkeys-lru:从数据集(server.db[i].dict)中挑选最近最少使用的数据淘汰
- allkeys-random:从数据集(server.db[i].dict)中任意选择数据淘汰
- no-enviction(驱逐):禁止驱逐数据
20.6、 Java访问Redis
1、使用jedis java客户端来访问redis服务器,有点类似通过jdbc访问mysql一样。
2、当然如果是spring进行集成时,可以使用spring data来访问redis,spring data只是对jedis的二次封装。jdbcTemplate jdbc关系一样
20.7、 Redis集群
当一台数据无法满足要求,可以使用reids集群来处理,类似于mysql的读写分离。
二、索引
1.什么是索引?
何为索引:
数据库索引,是数据库管理系统中一个排序的数据结构,索引的实现通常使用B树及其变种B+树。
在数据之外,数据库系统还维护着满足特定查找算法的数据结构,这些数据结构以某种方式引用(指向)数据,这样就可以在这些数据结构上实现高级查找算法。这种数据结构,就是索引。
2.索引的作用?
索引作用:协助快速查询、更新数据库表中数据。
3.索引的优缺点?
3.1、索引具体的优缺点
1.通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性。
2.可以大大加快数据的检索速度,这也是创建索引的最主要的原因。
3.可以加速表和表之间的连接,特别是在实现数据的参考完整性方面特别有意义。
4.在使用分组和排序子句进行数据检索时,同样可以显著减少查询中分组和排序的时间。
5.通过使用索引,可以在查询的过程中,使用优化隐藏器,提高系统的性能。
增加索引也有许多不利的方面(缺点):
1.创建索引和维护索引要耗费时间,这种时间随着数据量的增加而增加。
2.索引需要占物理空间,除了数据表占数据空间之外,每一个索引还要占一定的物理空间,如果要建立聚簇索引,那么需要的空间就会更大。
3.当对表中的数据进行增加、删除和修改的时候,索引也要动态的维护,这样就降低了数据的维护速度。
3.2、哪些列适合建立索引?
索引是建立在数据库表中的某些列的上面。在创建索引的时候,应该考虑在哪些列上可以创建索引,在哪些列上不能创建索引。
一般来说,应该在这些列上创建索引:
(1)在经常需要搜索的列上,可以加快搜索的速度;
(2)在作为主键的列上,强制该列的唯一性和组织表中数据的排列结构;
(3)在经常用在连接的列上,这些列主要是一些外键,可以加快连接的速度;
(4)在经常需要根据范围进行搜索的列上创建索引,因为索引已经排序,其指定的范围是连续的;
(5)在经常需要排序的列上创建索引,因为索引已经排序,这样查询可以利用索引的排序,加快排序查询时间;
(6)在经常使用在WHERE子句中的列上面创建索引,加快条件的判断速度。
3.3、对于有些列不应该创建索引:
(1)对于那些在查询中很少使用或者参考的列不应该创建索引。
这是因为,既然这些列很少使用到,因此有索引或者无索引,并不能提高查询速度。相反,由于增加了索引,反而降低了系统的维护速度和增大了空间需求。
(2)对于那些只有很少数据值的列也不应该增加索引。
这是因为,由于这些列的取值很少,例如人事表的性别列,在查询的结果中,结果集的数据行占了表中数据行的很大比例,即需要在表中搜索的数据行的比例很大。增加索引,并不能明显加快检索速度。
(3)对于那些定义为text, image和bit数据类型的列不应该增加索引。
这是因为,这些列的数据量要么相当大,要么取值很少。
(4)当修改性能远远大于检索性能时,不应该创建索引。
这是因为,修改性能和检索性能是互相矛盾的。当增加索引时,会提高检索性能,但是会降低修改性能。当减少索引时,会提高修改性能,降低检索性能。因此,当修改性能远远大于检索性能时,不应该创建索引。
4.什么样的字段适合建索引
唯一、不为空、经常被查询的字段
5.MySQL B+Tree索引和Hash索引的区别?
5.1、Hash索引和B+树索引的特点:
Hash索引结构的特殊性,其检索效率非常高,索引的检索可以一次定位;
B+树索引需要从根节点到枝节点,最后才能访问到页节点这样多次的IO访问;
5.2、为什么不都用Hash索引而使用B+树索引?
- Hash索引仅仅能满足"=",“IN"和”"查询,不能使用范围查询,因为经过相应的Hash算法处理之后的Hash值的大小关系,并不能保证和Hash运算前完全一样;
- Hash索引无法被用来避免数据的排序操作,因为Hash值的大小关系并不一定和Hash运算前的键值完全一样;
- Hash索引不能利用部分索引键查询,对于组合索引,Hash索引在计算Hash值的时候是组合索引键合并后再一起计算Hash值,而不是单独计算Hash值,所以通过组合索引的前面一个或几个索引键进行查询的时候,Hash索引也无法被利用;
- Hash索引在任何时候都不能避免表扫描,由于不同索引键存在相同Hash值,所以即使取满足某个Hash键值的数据的记录条数,也无法从Hash索引中直接完成查询,还是要回表查询数据;
- Hash索引遇到大量Hash值相等的情况后性能并不一定就会比B+树索引高。
补充:
- MySQL中,只有HEAP/MEMORY引擎才显示支持Hash索引。
- 常用的InnoDB引擎中默认使用的是B+树索引,它会实时监控表上索引的使用情况,如果认为建立哈希索引可以提高查询效率,则自动在内存中的“自适应哈希索引缓冲区”建立哈希索引(在InnoDB中默认开启自适应哈希索引),通过观察搜索模式,MySQL会利用index key的前缀建立哈希索引,如果一个表几乎大部分都在缓冲池中,那么建立一个哈希索引能够加快等值查询。
B+树索引和哈希索引的明显区别是:
- 如果是等值查询,那么哈希索引明显有绝对优势,因为只需要经过一次算法即可找到相应的键值;当然了,这个前提是,键值都是唯一的。如果键值不是唯一的,就需要先找到该键所在位置,然后再根据链表往后扫描,直到找到相应的数据;
- 如果是范围查询检索,这时候哈希索引就毫无用武之地了,因为原先是有序的键值,经过哈希算法后,有可能变成不连续的了,就没办法再利用索引完成范围查询检索;
同理,哈希索引没办法利用索引完成排序,以及like ‘xxx%’ 这样的部分模糊查询(这种部分模糊查询,其实本质上也是范围查询);
- 哈希索引也不支持多列联合索引的最左匹配规则;
- B+树索引的关键字检索效率比较平均,不像B树那样波动幅度大,在有大量重复键值情况下,哈希索引的效率也是极低的,因为存在所谓的哈希碰撞问题。
- 在大多数场景下,都会有范围查询、排序、分组等查询特征,用B+树索引就可以了。
6.B树和B+树的区别
B树,每个节点都存储key和data,所有节点组成这棵树,并且叶子节点指针为nul,叶子结点不包含任何关键字信息。
B+树,所有的叶子结点中包含了全部关键字的信息,及指向含有这些关键字记录的指针,且叶子结点本身依关键字的大小自小而大的顺序链接,所有的非终端结点可以看成是索引部分,结点中仅含有其子树根结点中最大(或最小)关键字。 (而B 树的非终节点也包含需要查找的有效信息)
7.为什么说B+比B树更适合实际应用中操作系统的文件索引和数据库索引?
- B+的磁盘读写代价更低
B+的内部结点并没有指向关键字具体信息的指针。因此其内部结点相对B树更小。如果把所有同一内部结点的关键字存放在同一盘块中,那么盘块所能容纳的关键字数量也越多。一次性读入内存中的需要查找的关键字也就越多。相对来说IO读写次数也就降低了。
- B+tree的查询效率更加稳定
由于非终结点并不是最终指向文件内容的结点,而只是叶子结点中关键字的索引。所以任何关键字的查找必须走一条从根结点到叶子结点的路。所有关键字查询的路径长度相同,导致每一个数据的查询效率相当。
8.聚集索引和非聚集索引区别?
- 聚合索引(clustered index):
聚集索引表记录的排列顺序和索引的排列顺序一致,所以查询效率快,只要找到第一个索引值记录,其余就连续性的记录在物理也一样连续存放。聚集索引对应的缺点就是修改慢,因为为了保证表中记录的物理和索引顺序一致,在记录插入的时候,会对数据页重新排序。
聚集索引类似于新华字典中用拼音去查找汉字,拼音检索表于书记顺序都是按照a~z排列的,就像相同的逻辑顺序于物理顺序一样,当你需要查找a,ai两个读音的字,或是想一次寻找多个傻(sha)的同音字时,也许向后翻几页,或紧接着下一行就得到结果了。
- 非聚合索引(nonclustered index):
非聚集索引指定了表中记录的逻辑顺序,但是记录的物理和索引不一定一致,两种索引都采用B+树结构,非聚集索引的叶子层并不和实际数据页相重叠,而采用叶子层包含一个指向表中的记录在数据页中的指针方式。非聚集索引层次多,不会造成数据重排。
非聚集索引类似在新华字典上通过偏旁部首来查询汉字,检索表也许是按照横、竖、撇来排列的,但是由于正文中是a~z的拼音顺序,所以就类似于逻辑地址于物理地址的不对应。同时适用的情况就在于分组,大数目的不同值,频繁更新的列中,这些情况即不适合聚集索引。
根本区别:
聚集索引和非聚集索引的根本区别是表记录的排列顺序和与索引的排列顺序是否一致。
9.索引的最左匹配原则?
最左优先,以最左边的为起点任何连续的联合索引都能匹配上。同时遇到范围查询(>、<、between、like)就会停止匹配。
例如:b = 2 如果建立(a,b)顺序的索引,是匹配不到(a,b)索引的;但是如果查询条件是a = 1 and b = 2或者a=1(又或者是b = 2 and b = 1)就可以,因为优化器会自动调整a,b的顺序。再比如a = 1 and b = 2 and c > 3 and d = 4 如果建立(a,b,c,d)顺序的索引,d是用不到索引的,因为c字段是一个范围查询,它之后的字段会停止匹配。
10.普通索引、唯一索引、主索引
- 普通索引:普通索引(由关键字KEY或INDEX定义的索引)的唯一任务是加快对数据的访问速度。因此,应该只为那些最经常出现在查询条件(WHERE column = …)或排序条件(ORDER BY column)中的数据列创建索引。只要有可能,就应该选择一个数据最整齐、最紧凑的数据列(如一个整数类型的数据列)来创建索引。
- 唯一索引:普通索引允许被索引的数据列包含重复的值。比如说,因为人有可能同名,所以同一个姓名在同一个"员工个人资料"数据表里可能出现两次或更多次。 如果能确定某个数据列将只包含彼此各不相同的值,在为这个数据列创建索引的时候就应该用关键字UNIQUE把它定义为一个唯一索引。这么做的好处:一是简化了MySQL对这个索引的管理工作,这个索引也因此而变得更有效率;二是MySQL会在有新记录插入数据表时,自动检查新记录的这个字段的值是否已经在某个记录的这个字段里出现过了;如果是,MySQL将拒绝插入那条新记录。也就是说,唯一索引可以保证数据记录的唯一性。事实上,在许多场合,人们创建唯一索引的目的往往不是为了提高访问速度,而只是为了避免数据出现重复。
- 主索引 :在前面已经反复多次强调过:必须为主键字段创建一个索引,这个索引就是所谓的"主索引"。主索引与唯一索引的唯一区别是:前者在定义时使用的关键字是PRIMARY而不是UNIQUE。
- 外键索引 :如果为某个外键字段定义了一个外键约束条件,MySQL就会定义一个内部索引来帮助自己以最有效率的方式去管理和使用外键约束条件。
- 复合索引 :索引可以覆盖多个数据列,如像INDEX(columnA, columnB)索引。这种索引的特点是MySQL可以有选择地使用一个这样的索引。如果查询操作只需要用到columnA数据列上的一个索引,就可以使用复合索引INDEX(columnA, columnB)。不过,这种用法仅适用于在复合索引中排列在前的数据列组合。比如说,INDEX(A, B, C)可以当做A或(A, B)的索引来使用,但不能当做B、C或(B, C)的索引来使用。
- 全文索引 :文本字段上的普通索引只能加快对出现在字段内容最前面的字符串(也就是字段内容开头的字符)进行检索操作。如果字段里存放的是由几个、甚至是多个单词构成的较大段文字,普通索引就没什么作用了。这种检索往往以LIKE %word%的形式出现,这对MySQL来说很复杂,如果需要处理的数据量很大,响应时间就会很长。这类场合正是全文索引(full-text index)可以大显身手的地方。在生成这种类型的索引时,MySQL将把在文本中出现的所有单词创建为一份清单,查询操作将根据这份清单去检索有关的数据记录。全文索引即可以随数据表一同创建,也可以等日后有必要时再使用下面这条命令添加: ALTER TABLE tablename ADD FULLTEXT(column1, column2) ,有了全文索引,就可以用SELECT查询命令去检索那些包含着一个或多个给定单词的数据记录了。下面是这类查询命令的基本语法:
SELECT * FROM tablename WHERE MATCH(column1, column2) AGAINST(‘word1’, ‘word2’, ‘word3’) 上面这条命令将把column1和column2字段里有word1、word2和word3的数据记录全部查询出来。
注解:InnoDB数据表不支持全文索引。
三、事务
1.什么是事务?
事务是对数据库中一系列操作进行统一的回滚或者提交的操作,主要用来保证数据的完整性和一致性。
2.事务四大特性(ACID)原子性、一致性、隔离性、持久性?
- 原子性(Atomicity):
原子性是指事务包含的所有操作要么全部成功,要么全部失败回滚,因此事务的操作如果成功就必须要完全应用到数据库,如果操作失败则不能对数据库有任何影响。
- 一致性(Consistency):
事务开始前和结束后,数据库的完整性约束没有被破坏。比如A向B转账,不可能A扣了钱,B却没收到。
- 隔离性(Isolation):
隔离性是当多个用户并发访问数据库时,比如操作同一张表时,数据库为每一个用户开启的事务,不能被其他事务的操作所干扰,多个并发事务之间要相互隔离。同一时间,只允许一个事务请求同一数据,不同的事务之间彼此没有任何干扰。比如A正在从一张银行卡中取钱,在A取钱的过程结束前,B不能向这张卡转账。
- 持久性(Durability):
持久性是指一个事务一旦被提交了,那么对数据库中的数据的改变就是永久性的,即便是在数据库系统遇到故障的情况下也不会丢失提交事务的操作。
3.事务的并发?事务隔离级别,每个级别会引发什么问题,MySQL默认是哪个级别?
从理论上来说, 事务应该彼此完全隔离, 以避免并发事务所导致的问题,然而, 那样会对性能产生极大的影响, 因为事务必须按顺序运行, 在实际开发中, 为了提升性能, 事务会以较低的隔离级别运行, 事务的隔离级别可以通过隔离事务属性指定。
3.1、事务的并发问题
- 脏读:事务A读取了事务B更新的数据,然后B回滚操作,那么A读取到的数据是脏数据
- 不可重复读:事务 A 多次读取同一数据,事务 B 在事务A多次读取的过程中,对数据作了更新并提交,导致事务A多次读取同一数据时,结果因此本事务先后两次读到的数据结果会不一致。
- 幻读:幻读解决了不重复读,保证了同一个事务里,查询的结果都是事务开始时的状态(一致性)。例如:事务T1对一个表中所有的行的某个数据项做了从“1”修改为“2”的操作 这时事务T2又对这个表中插入了一行数据项,而这个数据项的数值还是为“1”并且提交给数据库。 而操作事务T1的用户如果再查看刚刚修改的数据,会发现还有跟没有修改一样,其实这行是从事务T2中添加的,就好像产生幻觉一样,这就是发生了幻读。
小结:不可重复读的和幻读很容易混淆,不可重复读侧重于修改,幻读侧重于新增或删除。解决不可重复读的问题只需锁住满足条件的行,解决幻读需要锁表。
3.2、事务的隔离级别
- **读未提交:**另一个事务修改了数据,但尚未提交,而本事务中的SELECT会读到这些未被提交的数据脏读
- 读已提交:事务 A 多次读取同一数据,事务 B 在事务A多次读取的过程中,对数据作了更新并提交,导致事务A多次读取同一数据时,结果因此本事务先后两次读到的数据结果会不一致。
- 可重复读:在同一个事务里,SELECT的结果是事务开始时时间点的状态,因此,同样的SELECT操作读到的结果会是一致的。但是,会有幻读现象
- 串行化:最高的隔离级别,在这个隔离级别下,不会产生任何异常。并发的事务,就像事务是在一个个按照顺序执行一样
特别注意:
MySQL默认的事务隔离级别为repeatable-read
MySQL 支持 4 中事务隔离级别.
事务的隔离级别要得到底层数据库引擎的支持, 而不是应用程序或者框架的支持.
Oracle 支持的 2 种事务隔离级别:READ_COMMITED , SERIALIZABLE
SQL规范所规定的标准,不同的数据库具体的实现可能会有些差异
MySQL中默认事务隔离级别是“可重复读”时并不会锁住读取到的行
事务隔离级别为未提交读时,写数据只会锁住相应的行。
事务隔离级别为可重复读时,写数据会锁住整张表。
事务隔离级别为串行化时,读写数据都会锁住整张表。
隔离级别越高,越能保证数据的完整性和一致性,但是对并发性能的影响也越大,鱼和熊掌不可兼得啊。对于多数应用程序,可以优先考虑把数据库系统的隔离级别设为ReadCommitted,它能够避免脏读取,而且具有较好的并发性能。尽管它会导致不可重复读、幻读这些并发问题,在可能出现这类问题的个别场合,可以由应用程序采用悲观锁或乐观锁来控制。
4.事务传播行为
- PROPAGATION_REQUIRED:如果当前没有事务,就创建一个新事务,如果当前存在事务,就加入该事务,该设置是最常用的设置。
- PROPAGATION_SUPPORTS:支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就以非事务执行。
- PROPAGATION_MANDATORY:支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就抛出异常。
- PROPAGATION_REQUIRES_NEW:创建新事务,无论当前存不存在事务,都创建新事务。
- PROPAGATION_NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
- PROPAGATION_NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。
- PROPAGATION_NESTED:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作。
5.嵌套事务
5.1、什么是嵌套事务?
嵌套是子事务套在父事务中执行,子事务是父事务的一部分,在进入子事务之前,父事务建立一个回滚点,叫save point,然后执行子事务,这个子事务的执行也算是父事务的一部分,然后子事务执行结束,父事务继续执行。重点就在于那个save point。看几个问题就明了了:
5.2、如果子事务回滚,会发生什么?
父事务会回滚到进入子事务前建立的save point,然后尝试其他的事务或者其他的业务逻辑,父事务之前的操作不会受到影响,更不会自动回滚。
5.3、如果父事务回滚,会发生什么?
父事务回滚,子事务也会跟着回滚!为什么呢,因为父事务结束之前,子事务是不会提交的,我们说子事务是父事务的一部分,正是这个道理。那么:
5.4、事务的提交,是什么情况?
是父事务先提交,然后子事务提交,还是子事务先提交,父事务再提交?答案是第二种情况,还是那句话,子事务是父事务的一部分,由父事务统一提交。