6.MySQL高频面试题

目录


Java Web面试题目录清单(高频面试题型)(点击进入…)


MySQL高频面试题


MySQL高频面试题

1.为什么要使用数据库

数据保存在内存
(1)优点
存取速度快

(2)缺点
数据不能永久保存

数据保存在文件
(1)优点
数据永久保存

(2)缺点
①速度比内存操作慢,频繁的IO操作
②查询数据不方便

数据保存在数据库
(1)数据永久保存
(2)使用SQL语句,查询方便效率高
(3)管理数据方便


2.什么是SQL?

结构化查询语言(Structured Query Language)简称SQL,是一种数据库查询语言。

作用:用于存取数据、查询、更新和管理关系数据库系统


3.什么是MySQL?

MySQL是一个关系型数据库管理系统,由瑞典MySQL AB公司开发,属于Oracle旗下产品。MySQL是最流行的关系型数据库管理系统之一。

在WEB应用方面,MySQL是最好的RDBMS(Relational Database Management System,关系数据库管理系统)应用软件之一。在Java企业级开发中非常常用,因为MySQL是开源免费的,并且方便扩展。


4.数据库三大范式是什么?

范式描述
第一范式每个列都不可以再拆分
第二范式在第一范式的基础上,非主键列完全依赖于主键,而不能是依赖于主键的一部分
第三范式在第二范式的基础上,非主键列只依赖于主键,不依赖于其他非主键

在设计数据库结构的时候,要尽量遵守三范式,如果不遵守,必须有足够的理由。比如性能。事实上经常会为了性能而妥协数据库的设计


5.MySQL有关权限的表都有哪几个?

MySQL服务器通过权限表来控制用户对数据库的访问,权限表存放在MySQL数据库里,由mysql_install_db脚本初始化。这些权限表分别user、db、table_priv、columns_priv和host

权限表描述
user记录允许连接到服务器的用户帐号信息,里面的权限是全局级的
db记录各个帐号在各个数据库上的操作权限
table_priv记录数据表级的操作权限
columns_priv记录数据列级的操作权限
host配合db权限表对给定主机上数据库级操作权限作更细致的控制。这个权限表不受GRANT和REVOKE语句的影响

6.MySQL的binlog有有几种录入格式?分别有什么区别?

有三种格式:statement、row和mixed

录入格式描述
statement模式每一条会修改数据的sql都会记录在binlog中。不需要记录每一行的变化,减少了binlog日志量,节约了IO,提高性能。由于sql的执行是有上下文的,因此在保存的时候需要保存相关的信息,同时还有一些使用了函数之类的语句无法被记录复制
row级别不记录sql语句上下文相关信息,仅保存哪条记录被修改。记录单元为每一行的改动,基本是可以全部记下来但是由于很多操作,会导致大量行的改动(比如alter table),因此这种模式的文件保存的信息太多,日志量太大
mixed一种折中的方案,普通操作使用statement记录,当无法使用statement的时候使用row。

此外,新版的MySQL中对row级别也做了一些优化,当表结构发生变化的时候,会记录语句而不是逐行记录


7.MySQL数据类型

整数类型

整数类型描述
tinyInt很小的整数(1字节,8位二进制)
smallint小的整数(2字节,16位二进制)
mediumint中等大小的整数(3字节,24位二进制)
int(integer)普通大小的整数(4字节,32位二进制)
bigint大的整数(8字节,32位二进制)

任何整数类型都可以加上UNSIGNED属性,表示数据是无符号的,即非负整数

长度:整数类型可以被指定长度

例如:INT(11)表示长度为11的INT类型。长度在大多数场景是没有意义的,它不会限制值的合法范围,只会影响显示字符的个数,而且需要和UNSIGNED ZEROFILL属性配合使用才有意义。
例子,假定类型设定为INT(5),属性为UNSIGNED ZEROFILL,如果用户插入的数据为12的话,那么数据库实际存储数据为00012


浮点数(小数)类型

浮点数描述
float单精度浮点数
double双精度浮点数
decimal(m,d)压缩严格的定点数
FLOAT和DOUBLE是有取值范围的,并支持使用标准的浮点进行近似计算。
计算时FLOAT和DOUBLE相比DECIMAL效率更高一些,DECIMAL你可以理解成是用字符串进行处理
DECIMAL可以用于存储比BIGINT还大的整型,能存储精确的小数

日期类型

日期描述
year年份 ‘1999’
time时间 ‘12:25:36’
date日期 ‘2008-12-2’
datetime日期时间 ‘2008-12-2 22:06:44’
timestamp自动存储记录修改时间

日期和时间类型,尽量使用timestamp,空间效率高于datetime,用整数保存时间戳通常不方便处理。如果需要存储微妙,可以使用bigint存储

若定义一个字段为timestamp,这个字段里的时间数据会随其他字段修改的时候自动刷新,所以这个数据类型的字段可以存放这条记录最后被修改的时间

字符串(文本、二进制)类型
字符串类型,包括char、varchar、text、blob

varchar
(1)用于存储可变长字符串,它比定长类型更节省空间
(2)使用额外1或2个字节存储字符串长度。列长度小于255字节时,使用1字节表示,否则使用2字节表示
(3)存储的内容超出设置的长度时,内容会被截断

char
(1)定长的,根据定义的字符串长度分配足够的空间
(2)CHAR会根据需要使用空格进行填充方便比较
(3)适合存储很短的字符串,或者所有值都接近同一个长度
(4)存储的内容超出设置的长度时,内容同样会被截断

字符串类型描述
char(m)m为0~255之间的整数
varchar(m)m为0~65535之间的整数
binary(m)允许长度0~m个字节的定长字节字符串
varbinary(m)允许长度0~m个字节的变长字节字符串
tinyblob允许长度0~255字节
blob允许长度0~65535字节
mediumblob允许长度0~167772150字节
longblob允许长度0~4294967295字节
text允许长度0~65535字节
tinytext允许长度0~255字节
mediumtext允许长度0~167772150字节
longtext允许长度0~4294967295字节

使用策略:
对于经常变更的数据来说,CHAR比VARCHAR更好,因为CHAR不容易产生碎片。
对于非常短的列,CHAR比VARCHAR在存储空间上更有效率。
使用时要注意只分配需要的空间,更长的列排序时会消耗更多内存。
尽量避免使用TEXT/BLOB类型,查询时会使用临时表,导致严重的性能开销

枚举类型(ENUM),把不重复的数据存储为一个预定义的集合。有时可以使用ENUM代替常用的字符串类型。ENUM存储非常紧凑,会把列表值压缩到一个或两个字节。ENUM在内部存储时,其实存的是整数。尽量避免使用数字作为ENUM枚举的常量,因为容易混乱。排序是按照内部存储的整数

数据库类型JAVA类型JDBC类型 索引(int)
VARCHARString12
CHARString1
BLOBbyte[]-4
TEXTString-1
INTEGER UNSIGNEDLong4
TINYINT UNSIGNEDInteger-6
SMALLINT UNSIGNEDInteger5
MEDIUMINT UNSIGNEInteger4
BITBoolean-7
BIGINT UNSIGNEDBigInteger-5
FLOATFloat7
DOUBLEDouble8
DECIMALBigDecimal3
BOOLEANInteger
DATEDate91
TIMETime92
DATETIMETimestamp93
TIMESTAMPTimestamp93
YEARDate91

8.MySQL存储引擎有哪些?

存储引擎Storage engine:MySQL中的数据、索引以及其他对象是如何存储的,是一套文件系统的实现

存储引擎描述
Innodb引擎Innodb引擎提供了对数据库ACID事务的支持。并且还提供了行级锁和外键的约束。它的设计的目标就是处理大数据容量的数据库系统
MyIASM引擎(原本Mysql的默认引擎)不提供事务的支持,也不支持行级锁和外键
MEMORY引擎所有的数据都在内存中,数据的处理速度快,但是安全性不高

9.MyISAM与InnoDB区别

MyISAMInnodb
存储结构每张表被存放在三个文件:frm-表格定义、MYD(MYData)-数据文件、MYI(MYIndex)-索引文件所有的表都保存在同一个数据文件中(也可能是多个文件,或者是独立的表空间文件),InnoDB表的大小只受限于操作系统文件的大小,一般为2GB
存储空间可被压缩,存储空间较小需要更多的内存和存储,它会在主内存中建立其专用的缓冲池用于高速缓冲数据和索引
可移植性、备份及恢复由于MyISAM的数据是以文件的形式存储,所以在跨平台的数据转移中会很方便。在备份和恢复时可单独针对某个表进行操作免费的方案可以是拷贝数据文件、备份 binlog,或者用 mysqldump,在数据量达到几十G的时候就相对痛苦了
文件格式数据和索引是分别存储的,数据.MYD,索引.MYI数据和索引是集中存储的,.ibd
记录存储顺序按记录插入顺序保存按主键大小有序插入
外键不支持支持
事务不支持支持
锁支持(锁是避免资源争用的一个机制,MySQL锁对用户几乎是透明的)表级锁定 行级锁定、表级锁定,锁定力度小并发能力高
SELECTMyISAM更优
INSERT、UPDATE、DELETEInnoDB更优
select count(*)myisam更快,因为myisam内部维护了一个计数器,可以直接调取
索引实现方式B+树索引,myisam 是堆表B+树索引,Innodb 是索引组织表
哈希索引不支持支持
全文索引支持不支持

10.MyISAM索引与InnoDB索引区别?

InnoDB索引MyISAM索引
聚簇索引非聚簇索引
主键索引的叶子节点存储着行数据,因此主键索引非常高效 叶子节点存储的是行数据地址,需要再寻址一次才能得到数据InnoDB非主键索引的叶子节点存储的是主键和其他带索引的列数据,因此查询时做到覆盖索引会非常高效

11.InnoDB引擎的4大特性

(1)插入缓冲(insert buffer)
(2)二次写(double write)
(3)自适应哈希索引(ahi)
(4)预读(read ahead)


12.存储引擎选择

如果没有特别的需求,使用默认的Innodb即可。

存储引擎描述
MyISAM以读写为主的应用程序,比如博客系统、新闻门户网站
Innodb更新(删除)操作频率也高,或者要保证数据的完整性;并发量高,支持事务和外键。比如OA自动化办公系统

13.什么是索引?

索引是一种特殊的文件(InnoDB数据表上的索引是表空间的一个组成部分),它们包含着对数据表里所有记录的引用指针

索引是一种数据结构。数据库索引,是数据库管理系统中一个排序的数据结构,以协助快速查询、更新数据库表中数据。索引的实现通常使用B-Tree及其变种B+Tree

更通俗的说,索引就相当于目录。为了方便查找书中的内容,通过对内容建立索引形成目录。索引是一个文件,它是要占据物理空间的


14.索引有哪些优缺点?

优点
(1)可以大大加快数据的检索速度,这也是创建索引的最主要的原因
(2)通过使用索引,可以在查询的过程中,使用优化隐藏器,提高系统的性能

缺点
(1)时间方面:创建索引和维护索引要耗费时间,具体地,当对表中的数据进行增加、删除和修改的时候,索引也要动态的维护,会降低增/改/删的执行效率
(2)空间方面:索引需要占物理空间

order by
当使用order by将查询结果按照某个字段排序时,如果该字段没有建立索引,那么执行计划会将查询出的所有数据使用外部排序(将数据从硬盘分批读取到内存使用内部排序,最后合并排序结果),这个操作是很影响性能的,因为需要将查询涉及到的所有数据从磁盘中读到内存(如果单条数据过大或者数据量过多都会降低效率),更无论读到内存之后的排序了。

但是如果我们对该字段建立索引alter table 表名 add index(字段名),那么由于索引本身是有序的,因此直接按照索引的顺序和映射关系逐条取出数据即可。而且如果分页的,那么只用取出索引表某个范围内的索引对应的数据,而不用像上述那取出所有数据进行排序再返回某个范围内的数据。(从磁盘取数据是最影响性能的)

join
对join语句匹配关系(on)涉及的字段建立索引能够提高效率

索引覆盖
如果要查询的字段都建立过索引,那么引擎会直接在索引表中查询而不会访问原始数据(否则只要有一个字段没有建立索引就会做全表扫描),这叫索引覆盖。因此我们需要尽可能的在select后只写必要的查询字段,以增加索引覆盖的几率。

这里值得注意的是不要想着为每个字段建立索引,因为优先使用索引的优势就在于其体积小


15.索引有哪几种类型?

(1)主键索引
数据列不允许重复,不允许为NULL,一个表只能有一个主键

(2)唯一索引
数据列不允许重复,允许为NULL值,一个表允许多个列创建唯一索引
可以通过 ALTER TABLE table_name ADD UNIQUE (column); 创建唯一索引
可以通过 ALTER TABLE table_name ADD UNIQUE (column1,column2); 创建唯一组合索引

(3)普通索引
基本的索引类型,没有唯一性的限制,允许为NULL值
可以通过ALTER TABLE table_name ADD INDEX index_name (column);创建普通索引
可以通过ALTER TABLE table_name ADD INDEX index_name(column1, column2, column3);创建组合索引

(4)全文索引
目前搜索引擎使用的一种关键技术
可以通过ALTER TABLE table_name ADD FULLTEXT (column);创建全文索引


16.索引基本原理

用来快速地寻找那些具有特定值的记录。如果没有索引,一般来说执行查询时遍历整张表

索引的原理很简单,就是把无序的数据变成有序的查询
(1)创建索引的列的内容进行排序
(2)对排序结果生成倒排表
(3)在倒排表内容上拼上数据地址链
(4)在查询的时候,先拿到倒排表内容,再取出数据地址链,从而拿到具体数据


17.索引算法有哪些?

索引算法有 BTree算法和Hash算法

BTree算法
BTree是最常用的mysql数据库索引算法,也是mysql默认的算法。因为它不仅可以被用在=,>,>=,<,<=和between这些比较操作符上,而且还可以用于like操作符,只要它的查询条件是一个不以通配符开头的常量, 例如:

-- 只要它的查询条件是一个不以通配符开头的常量
select * from user where name like 'jack%'; 

-- 如果一通配符开头,或者没有使用常量,则不会使用索引,例如: 
select * from user where name like '%jack'; 

Hash算法
Hash Hash索引只能用于对等比较,例如=,<=>(相当于=)操作符。由于是一次定位数据,不像BTree索引需要从根节点到枝节点,最后才能访问到页节点这样多次IO访问,所以检索效率远高于BTree索引


18.索引设计原则?

(1)适合索引的列是出现在where子句中的列,或者连接子句中指定的列
(2)基数较小的类,索引效果较差,没有必要在此列建立索引
(3)使用短索引,如果对长字符串列进行索引,应该指定一个前缀长度,这样能够节省大量索引空间
(4)不要过度索引。索引需要额外的磁盘空间,并降低写操作的性能。在修改表内容的时候,索引会进行更新甚至重构,索引列越多,这个时间就会越长。所以只保持需要的索引有利于查询即可


19.创建索引的原则(重中之重)

索引虽好,但也不是无限制的使用,最好符合一下几个原则

(1)最左前缀匹配原则,组合索引非常重要的原则
mysql会一直向右匹配直到遇到范围查询(>、<、between、like)就停止匹配,比如a = 1 and b = 2 and c > 3 and d = 4 如果建立(a,b,c,d)顺序的索引,d是用不到索引的,如果建立(a,b,d,c)的索引则都可以用到,a,b,d的顺序可以任意调整

(2)较频繁作为查询条件的字段才去创建索引
(3)更新频繁字段不适合创建索引
(4)若是不能有效区分数据的列不适合做索引列(如性别,男女未知,最多也就三种,区分度实在太低)
(5)尽量的扩展索引,不要新建索引。比如表中已经有a的索引,现在要加(a,b)的索引,那么只需要修改原来的索引即可
(6)定义有外键的数据列一定要建立索引
(7)对于那些查询中很少涉及的列,重复值比较多的列不要建立索引
(8)对于定义为text、image和bit的数据类型的列不要建立索引


20.创建索引(三种方式)

第一种方式:在执行CREATE TABLE时创建索引

CREATE TABLE user_index2 (
	id INT auto_increment PRIMARY KEY,
	first_name VARCHAR (16),
	last_name VARCHAR (16),
	id_card VARCHAR (18),
	information text,
	KEY name (first_name, last_name),
	FULLTEXT KEY (information),
	UNIQUE KEY (id_card)
);

第二种方式:使用ALTER TABLE命令去增加索引

ALTER TABLE table_name ADD INDEX index_name (column_list);
ALTER TABLE用来创建普通索引、UNIQUE索引或PRIMARY KEY索引。

其中table_name是要增加索引的表名,column_list指出对哪些列进行索引,多列时各列之间用逗号分隔。

索引名index_name可自己命名,缺省时,MySQL将根据第一个索引列赋一个名称。另外,ALTER TABLE允许在单个语句中更改多个表,因此可以在同时创建多个索引

第三种方式:使用CREATE INDEX命令创建

CREATE INDEX index_name ON table_name (column_list);
CREATE INDEX可对表增加普通索引或UNIQUE索引。(但是,不能创建PRIMARY KEY索引)

删除索引
根据索引名删除普通索引、唯一索引、全文索引:alter table 表名 drop KEY 索引名

alter table user_index drop KEY name;
alter table user_index drop KEY id_card;
alter table user_index drop KEY information;

删除主键索引:alter table 表名 drop primary key(因为主键只有一个)。这里值得注意的是,如果主键自增长,那么不能直接执行此操作(自增长依赖于主键索引)


21.创建索引时需要注意什么?

(1)非空字段
应该指定列为NOT NULL,除非想存储NULL。在mysql中,含有空值的列很难进行查询优化,因为它们使得索引、索引的统计信息以及比较运算更加复杂。你应该用0、一个特殊的值或者一个空串代替空值

(2)取值离散大的字段
(变量各个取值之间的差异程度)的列放到联合索引的前面,可以通过count()函数查看字段的差异值,返回值越大说明字段的唯一值越多字段的离散程度高;

(3)索引字段越小越好
数据库的数据存储以页为单位一页存储的数据越多一次IO操作获取的数据越大效率越高


22.使用索引查询一定能提高查询的性能吗?为什么

通常,通过索引查询数据比全表扫描要快。但是也必须注意到它的代价

索引需要空间来存储,也需要定期维护, 每当有记录在表中增减或索引列被修改时,索引本身也会被修改。 这意味着每条记录的INSERT,DELETE,UPDATE将为此多付出4,5 次的磁盘I/O。 因为索引需要额外的存储空间和处理,那些不必要的索引反而会使查询反应时间变慢。使用索引查询不一定能提高查询性能,索引范围查询(INDEX RANGE SCAN)适用于两种情况:
(1)基于一个范围的检索,一般查询返回结果集小于表中记录数的30%
(2)基于非唯一性索引的检索


23.百万级别或以上的数据如何删除

关于索引:由于索引需要额外的维护成本,因为索引文件是单独存在的文件,所以当我们对数据的增加,修改,删除,都会产生额外的对索引文件的操作,这些操作需要消耗额外的IO,会降低增/改/删的执行效率。所以,在我们删除数据库百万级别数据的时候,查询MySQL官方手册得知删除数据的速度和创建的索引数量是成正比的。

(1)想要删除百万数据的时候可以先删除索引(此时大概耗时三分多钟)
(2)然后删除其中无用数据(此过程需要不到两分钟)
(3)删除完成后重新创建索引(此时数据较少了)创建索引也非常快,约十分钟左右。
(4)与之前的直接删除绝对是要快速很多,更别说万一删除中断,一切删除会回滚。那更是坑了


24.前缀索引

语法:index(field(10))

使用字段值的前10个字符建立索引,默认是使用字段的全部内容建立索引
前提:前缀的标识度高。比如密码就适合建立前缀索引,因为密码几乎各不相同

实操的难度:在于前缀截取的长度。
我们可以利用select count(*)/count(distinct left(password,prefixLen));,通过从调整prefixLen的值(从1自增)查看不同前缀长度的一个平均匹配度,接近1时就可以了(表示一个密码的前prefixLen个字符几乎能确定唯一一条记录)


25.什么是最左前缀原则?

最左优先,在创建多列索引时,要根据业务需求,where子句中使用最频繁的一列放在最左边。

最左前缀匹配原则,非常重要的原则,mysql会一直向右匹配直到遇到范围查询(>、<、between、like)就停止匹配,比如a = 1 and b = 2 and c > 3 and d = 4 如果建立(a,b,c,d)顺序的索引,d是用不到索引的,如果建立(a,b,d,c)的索引则都可以用到,a,b,d的顺序可以任意调整。
=和in可以乱序,比如a = 1 and b = 2 and c = 3 建立(a,b,c)索引可以任意顺序,mysql的查询优化器会帮你优化成索引可以识别的形式


26.什么是聚簇索引?何时使用聚簇索引与非聚簇索引

聚簇索引描述
聚簇索引将数据存储与索引放到了一块,找到索引也就找到了数据
非聚簇索引将数据存储于索引分开结构,索引结构的叶子节点指向了数据的对应行,myisam通过key_buffer把索引先缓存到内存中,当需要访问数据时(通过索引访问数据),在内存中直接搜索索引,然后通过索引找到磁盘相应数据,这也就是为什么索引不在key buffer命中时,速度慢的原因

澄清一个概念:innodb中,在聚簇索引之上创建的索引称之为辅助索引,辅助索引访问数据总是需要二次查找,非聚簇索引都是辅助索引,像复合索引、前缀索引、唯一索引,辅助索引叶子节点存储的不再是行的物理位置,而是主键值


27.非聚簇索引一定会回表查询吗?

不一定。这涉及到查询语句所要求的字段是否全部命中了索引,如果全部命中了索引,那么就不必再进行回表查询。

举个简单的例子,假设在员工表的年龄上建立了索引,那么当进行select age from employee where age < 20的查询时,在索引的叶子节点上,已经包含了age信息,不会再次进行回表查询


28.何时使用聚簇索引与非聚簇索引

动作聚簇索引非聚簇索引
列经常被分组排序
返回某范围内的数据不应
一个或极少不同值不应不应
小数目的不同值不应
大数目的不同值不应
频繁更新列不应
外键列
主键列
频繁修改索引列不应

29.联合索引是什么?为什么需要注意联合索引中的顺序?

MySQL可以使用多个字段同时建立一个索引,叫做联合索引。在联合索引中,如果想要命中索引,需要按照建立索引时的字段顺序挨个使用,否则无法命中索引。

具体原因为:
MySQL使用索引时需要索引有序,假设现在建立了"name,age,school"的联合索引,那么索引的排序为:先按照name排序,如果name相同,则按照age排序,如果age的值也相等,则按照school进行排序。

当进行查询时,此时索引仅仅按照name严格有序,因此必须首先使用name字段进行等值查询,之后对于匹配到的列而言,其按照age字段严格有序,此时可以使用age字段用做索引查找,以此类推。因此在建立联合索引的时候应该注意索引列的顺序,一般情况下,将查询需求频繁或者字段选择性高的列放在前面。此外可以根据特例的查询或者表结构进行单独的调整


30.什么是数据库事务?

事务是一个不可分割的数据库操作序列,也是数据库并发控制的基本单位,其执行的结果必须使数据库从一种一致性状态变到另一种一致性状态。事务是逻辑上的一组操作,要么都执行,要么都不执行(要么都成功要么都失败)


31.事务四大特性

(1)原子性
事务是最小的执行单位,不允许分割。事务的原子性确保动作要么全部完成,要么完全不起作用

(2)一致性
执行事务前后,数据保持一致,多个事务对同一个数据读取的结果是相同的

(3)隔离性
并发访问数据库时,一个用户的事务不被其他事务所干扰,各并发事务之间数据库是独立的

(4)持久性
一个事务被提交之后。它对数据库中数据的改变是持久的,即使数据库发生故障也不应该对其有任何影响


32.什么是脏读?幻读?不可重复读?

(1)脏读(Drity Read)
某个事务已更新一份数据,另一个事务在此时读取了同一份数据,由于某些原因,前一个RollBack了操作,则后一个事务所读取的数据就会是不正确的

(2)不可重复读(Non-repeatable read)
在一个事务的两次查询之中数据不一致,这可能是两次查询过程中间插入了一个事务更新的原有的数据

(3)幻读(Phantom Read)
在一个事务的两次查询中数据笔数不一致。例如有一个事务查询了几列(Row)数据,而另一个事务却在此时插入了新的几列数据,先前的事务在接下来的查询中,就会发现有几列数据是它先前所没有的


33.什么是事务的隔离级别?MySQL默认隔离级别是什么?

为了达到事务的四大特性,数据库定义了4种不同的事务隔离级别,由低到高依次为Read uncommitted、Read committed、Repeatable read、Serializable,这四个级别可以逐个解决脏读、不可重复读、幻读这几类问题

隔离级别脏读不可重复读幻读
READ-UNCOMMITTED
READ-COMMITTED×
REPEATABLE-READ××
SERIALIZABLE×××

SQL标准定义了四个隔离级别(高 --> 低)
(1)READ-UNCOMMITTED(读取未提交)
最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读

(2)READ-COMMITTED(读取已提交)
允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生

(3)REPEATABLE-READ(可重复读)
对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生

(4)SERIALIZABLE(可串行化)
最高的隔离级别,完全服从ACID的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读

注意:Mysql默认采用的REPEATABLE_READ隔离级别,Oracle 默认采用READ_COMMITTED隔离级别

事务隔离机制的实现基于锁机制和并发调度。其中并发调度使用的是MVVC(多版本并发控制),通过保存修改的旧版本信息来支持并发一致性读和回滚等特性。因为隔离级别越低,事务请求的锁越少,所以大部分数据库系统的隔离级别都是READ-COMMITTED(读取提交内容),但是要知道的是InnoDB 存储引擎默认使用 REPEATABLE-READ(可重读)并不会有任何性能损失

InnoDB存储引擎在分布式事务的情况下一般会用到SERIALIZABLE(可串行化)隔离级别


34.对MySQL的锁了解吗

当数据库有并发事务的时候,可能会产生数据的不一致,这时候需要一些机制来保证访问的次序,锁机制就是这样的一个机制。

就像酒店的房间,如果大家随意进出,就会出现多人抢夺同一个房间的情况,而在房间上装上锁,申请到钥匙的人才可以入住并且将房间锁起来,其他人只有等他使用完毕才可以再次使用


35.隔离级别与锁的关系

在Read Uncommitted级别下,读取数据不需要加共享锁,这样就不会跟被修改的数据上的排他锁冲突
在Read Committed级别下,读操作需要加共享锁,但是在语句执行完以后释放共享锁;

在Repeatable Read级别下,读操作需要加共享锁,但是在事务提交之前并不释放共享锁,也就是必须等待事务执行完毕以后才释放共享锁

SERIALIZABLE限制性最强的隔离级别,因为该级别锁定整个范围的键,并一直持有锁,直到事务完成


36.按照锁的粒度分数据库锁有哪些?锁机制与InnoDB锁算法

在关系型数据库中,可以按照锁的粒度把数据库锁划分:
①行级锁(INNODB引擎)
②表级锁(MYISAM引擎)
③页级锁(BDB引擎)

MyISAM存储引擎:采用表级锁(table-level locking)
InnoDB存储引擎:行级锁(row-level locking)和表级锁,默认为行级锁

(1)行级锁
行级锁是Mysql中锁定粒度最细的一种锁,表示只针对当前操作的行进行加锁。行级锁能大大减少数据库操作的冲突。其加锁粒度最小,但加锁的开销也最大。行级锁分为共享锁 和 排他锁。
特点:开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高。

(2)表级锁
表级锁是MySQL中锁定粒度最大的一种锁,表示对当前操作的整张表加锁,它实现简单,资源消耗较少,被大部分MySQL引擎支持。最常使用的MYISAM与INNODB都支持表级锁定。表级锁定分为表共享读锁(共享锁)与表独占写锁(排他锁)
特点:开销小,加锁快;不会出现死锁;锁定粒度大,发出锁冲突的概率最高,并发度最低。

(3)页级锁
页级锁是MySQL中锁定粒度介于行级锁和表级锁中间的一种锁。表级锁速度快,但冲突多,行级冲突少,但速度慢。所以取了折衷的页级,一次锁定相邻的一组记录。
特点:开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度一般


37.从锁的类别上分MySQL都有哪些锁呢?像上面那样子进行锁定岂不是有点阻碍并发效率

从锁的类别划分:共享锁、排他锁

(1)共享锁
又叫做读锁。 当用户要进行数据的读取时,对数据加上共享锁。共享锁可以同时加上多个

(2)排他锁
又叫做写锁。当用户要进行数据的写入时,对数据加上排他锁。排他锁只可以加一个,他和其他的排他锁,共享锁都相斥

用上面的例子来说就是用户的行为有两种,一种是来看房,多个用户一起看房是可以接受的。 一种是真正的入住一晚,在这期间,无论是想入住的还是想看房的都不可以。
锁的粒度取决于具体的存储引擎,InnoDB实现了行级锁,页级锁,表级锁。
他们的加锁开销从大到小,并发能力也是从大到小


38.InnoDB引擎的行锁是怎么实现的?

InnoDB是基于索引来完成行锁。

select * from tab_with_index where id = 1 for update;

for update:可以根据条件来完成行锁锁定,并且id是有索引键的列,如果id不是索引键那么InnoDB将完成表锁,并发将无从谈起


39.InnoDB存储引擎的锁的算法(三种)

算法描述
Record lock单个行记录上的锁
Gap lock间隙锁,锁定一个范围,不包括记录本身
Next-keylock record+gap 锁定一个范围,包含记录本身

(1)innodb对于行的查询使用next-key lock
(2)Next-locking keying为了解决Phantom Problem幻读问题
(3)当查询的索引含有唯一属性时,将next-key lock降级为record key
(4)Gap锁设计的目的是为了阻止多个事务将记录插入到同一范围内,而这会导致幻读问题的产生
(5)有两种方式显式关闭gap锁:(除了外键约束和唯一性检查外,其余情况仅使用record lock) A. 将事务隔离级别设置为RC B. 将参数innodb_locks_unsafe_for_binlog设置为1


40.什么是死锁?怎么解决?

死锁是指两个或多个事务在同一资源上相互占用,并请求锁定对方的资源,从而导致恶性循环的现象

(1)如果不同程序会并发存取多个表,尽量约定以相同的顺序访问表,可以大大降低死锁机会
(2)在同一个事务中,尽可能做到一次锁定所需要的所有资源,减少死锁产生概率
(3)对于非常容易产生死锁的业务部分,可以尝试使用升级锁定颗粒度,通过表级锁定来减少死锁产生的概率

如果业务处理不好可以用分布式事务锁或者使用乐观锁


41.数据库的乐观锁和悲观锁是什么?怎么实现?

数据库管理系统(DBMS)中的并发控制的任务是确保在多个事务同时存取数据库中同一数据时不破坏事务的隔离性和统一性以及数据库的统一性。乐观并发控制(乐观锁)和悲观并发控制(悲观锁)是并发控制主要采用的技术手段。

(1)悲观锁
假定会发生并发冲突,屏蔽一切可能违反数据完整性的操作。在查询完数据的时候就把事务锁起来,直到提交事务。实现方式:使用数据库中的锁机制

(2)乐观锁
假设不会发生并发冲突,只在提交操作时检查是否违反数据完整性。在修改数据的时候把事务锁起来,通过version的方式来进行锁定。实现方式:乐一般会使用版本号机制或CAS算法实现。

两种锁的使用场景
两种锁各有优缺点,不可认为一种好于另一种,像乐观锁适用于写比较少的情况下(多读场景),即冲突真的很少发生的时候,这样可以省去了锁的开销,加大了系统的整个吞吐量。但如果是多写的情况,一般会经常产生冲突,这就会导致上层应用会不断的进行retry,这样反倒是降低了性能,所以一般多写的场景下用悲观锁就比较合适


42.为什么要使用视图?什么是视图?

为了提高复杂SQL语句的复用性和表操作的安全性,MySQL数据库管理系统提供了视图特性。所谓视图,本质上是一种虚拟表,在物理上是不存在的,其内容与真实的表相似,包含一系列带有名称的列和行数据。但是,视图并不在数据库中以储存的数据值形式存在。行和列数据来自定义视图的查询所引用基本表,并且在具体引用视图时动态生成。

视图使开发者只关心感兴趣的某些特定数据和所负责的特定任务,只能看到视图中所定义的数据,而不是视图所引用表中的数据,从而提高了数据库中数据的安全性


43.视图有哪些特点?

(1)视图的列可以来自不同的表,是表的抽象和在逻辑意义上建立的新关系
(2)视图是由基本表(实表)产生的表(虚表)
(3)视图的建立和删除不影响基本表,对视图内容的更新(添加,删除和修改)直接影响基本表
(4)当视图来自多个基本表时,不允许添加和删除数据

视图的操作包括创建视图,查看视图,删除视图和修改视图


44.视图的使用场景有哪些?

视图用途:简化SQL查询,提高开发效率。如果说还有另外一个用途那就是兼容老的表结构

(1)重用SQL语句
(2)简化复杂的SQL操作。在编写查询后,可以方便的重用而不必知道它的基本查询细节
(3)使用表的组成部分而不是整个表
(4)保护数据。可以给用户授予表的特定部分的访问权限而不是整个表的访问权限
(5)更改数据格式和表示。视图可返回与底层表的表示和格式不同的数据


45.视图优点

(1)查询简单化。视图能简化用户的操作
(2)数据安全性。视图使用户能以多种角度看待同一数据,能够对机密数据提供安全保护
(3)逻辑数据独立性。视图对重构数据库提供了一定程度的逻辑独立性


46.视图缺点

(1)性能
数据库必须把视图的查询转化成对基本表的查询,如果这个视图是由一个复杂的多表查询所定义,那么,即使是视图的一个简单查询,数据库也把它变成一个复杂的结合体,需要花费一定的时间。

(2)修改限制
当用户试图修改视图的某些行时,数据库必须把它转化为对基本表的某些行的修改。事实上,当从视图中插入或者删除时,情况也是这样。对于简单视图来说,这是很方便的,但是,对于比较复杂的视图,可能是不可修改的

这些视图有如下特征
1.有UNIQUE等集合操作符的视图
2.有GROUP BY子句的视图
3.有诸如AVG\SUM\MAX等聚合函数的视图
4.使用DISTINCT关键字的视图
5.连接表的视图


47.什么是游标?

游标是系统为用户开设的一个数据缓冲区,存放SQL语句的执行结果,每个游标区都有一个名字。用户可以通过游标逐一获取记录并赋给主变量,交由主语言进一步处理。


48.什么是存储过程?有哪些优缺点?

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

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

缺点
(1)调试麻烦,但是用 PL/SQL Developer 调试很方便!弥补这个缺点
(2)移植问题,数据库端代码当然是与数据库相关的。但是如果是做工程型项目,基本不存在移植问题
(3)重新编译问题,因为后端代码是运行前编译的,如果带有引用关系的对象发生改变时,受影响的存储过程、包将需要重新编译(不过也可以设置成运行时刻自动编译)
(4)如果在一个程序系统中大量的使用存储过程,到程序交付使用的时候随着用户需求的增加会导致数据结构的变化,接着就是系统的相关问题了,最后如果用户想维护该系统可以说是很难很难、而且代价是空前的,维护起来更麻烦


49.SQL语句主要分为哪几类

(1)数据定义语言DDL(Data Ddefinition Language)
CREATE,DROP,ALTER。主要为以上操作 即对逻辑结构等有操作的,其中包括表结构,视图和索引

(2)数据查询语言DQL(Data Query Language)
SELECT。即查询操作,以select关键字。各种简单查询,连接查询等 都属于DQL

(3)数据操纵语言DML(Data Manipulation Language)
INSERT,UPDATE,DELETE。主要为以上操作 即对数据进行操作的,对应上面所说的查询操作 DQL与DML共同构建了多数初级程序员常用的增删改查操作。而查询是较为特殊的一种 被划分到DQL中。

(4)数据控制功能DCL(Data Control Language)
GRANT,REVOKE,COMMIT,ROLLBACK。主要为以上操作 即对数据库安全性完整性等有操作的,可以简单的理解为权限控制等


50.超键、候选键、主键、外键分别是什么?

数据键描述
超键在关系中能唯一标识元组的属性集称为关系模式的超键。一个属性可以为作为一个超键,多个属性组合在一起也可以作为一个超键。超键包含候选键和主键
候选键最小超键,即没有冗余元素的超键
主键数据库表中对储存数据对象予以唯一和完整标识的数据列或属性的组合。一个数据列只能有一个主键,且主键的取值不能缺失,即不能为空值(Null)
外键在一个表中存在的另一个表的主键称此表的外键

51.SQL约束有哪几种?

SQL约束描述
NOT NULL用于控制字段的内容一定不能为空(NULL)
UNIQUE控件字段内容不能重复,一个表允许有多个Unique约束
PRIMARY KEY也是用于控件字段内容不能重复,但它在一个表只允许出现一个
FOREIGN KEY用于预防破坏表之间连接的动作,也能防止非法数据插入外键列,因为它必须是它指向的那个表中的值之一
CHECK用于控制字段的值范围

52.关联查询

内连接(INNER JOIN)
内连接分为三类
(1)等值连接:ON A.id=B.id
(2)不等值连接:ON A.id > B.id
(3)自连接:SELECT * FROM A T1 INNER JOIN A T2 ON T1.id=T2.pid

外连接(LEFT JOIN/RIGHT JOIN)
左外连接
LEFT OUTER JOIN,以左表为主,先查询出左表,按照ON后的关联条件匹配右表,没有匹配到的用NULL填充,可以简写成LEFT JOIN

右外连接
RIGHT OUTER JOIN,以右表为主,先查询出右表,按照ON后的关联条件匹配左表,没有匹配到的用NULL填充,可以简写成RIGHT JOIN

联合查询(UNION与UNION ALL)

SELECT * FROM A UNION SELECT * FROM B UNION ...

(1)就是把多个结果集集中在一起,UNION前的结果为基准,需要注意的是联合查询的列数要相等,相同的记录行会合并
(2)如果使用UNION ALL,不会合并重复的记录行
(3)效率UNION高于UNION ALL

全连接(FULL JOIN)
MySQL不支持全连接
可以使用LEFT JOIN 和UNION和RIGHT JOIN联合使用

SELECT * 
	FROM A 
LEFT JOIN B ON A.id=B.id 
UNION
SELECT *
	FROM A 
RIGHT JOIN B ON A.id=B.id

53.什么是子查询

条件:一条SQL语句的查询结果做为另一条查询语句的条件或查询结果
嵌套:多条SQL语句嵌套使用,内部的SQL查询语句称为子查询


54.子查询的三种情况

(1)子查询是单行单列的情况:结果集是一个值,父查询使用:=、 <、 > 等运算符

-- 查询工资最高的员工是谁? 
select * from employee where salary=(select max(salary) from employee); 

(2)子查询是多行单列的情况:结果集类似于一个数组,父查询使用:in 运算符

-- 查询工资最高的员工是谁? 
select * from employee where salary=(select max(salary) from employee);    

(3)子查询是多行多列的情况:结果集类似于一张虚拟表,不能用于where条件,用于select子句中做为子表
①查询出2011年以后入职的员工信息
②查询所有的部门信息,与上面的虚拟表中的信息比对,找出所有部门ID相等的员工。

select * from dept d, (select * from employee where join_date > '2011-1-1') e 
where e.dept_id = d.id;
-- 使用表连接:
select d.*, e.* from dept d inner join employee e on d.id = e.dept_id where e.join_date >  '2011-1-1'  

55.mysql中in和exists区别

mysql中的in语句是把外表和内表作hash连接,而exists语句是对外表作loop循环,每次loop循环再对内表进行查询。一直大家都认为exists比in语句的效率要高,这种说法其实是不准确的。这个是要区分环境的

如果查询的两个表大小相当,那么用in和exists差别不大。
如果两个表中一个较小,一个是大表,则子查询表大的用exists,子查询表小的用in。
not in/not exists:如果查询语句使用not in,那么内外表都进行全表扫描,没有用到索引;而not extsts的子查询依然能用到表上的索引。所以无论那个表大,用not exists都比not in要快


56.varchar与char区别

char特点
(1)char表示定长字符串,长度是固定的
(2)如果插入数据的长度小于char的固定长度时,则用空格填充
(3)因为长度固定,所以存取速度要比varchar快很多,甚至能快50%,但正因为其长度固定,所以会占据多余的空间,是空间换时间的做法
(4)对于char来说,最多能存放的字符个数为255,和编码无关

varchar特点
(1)varchar表示可变长字符串,长度是可变的
(2)插入的数据是多长,就按照多长来存储
(3)varchar在存取方面与char相反,它存取慢,因为长度不固定,但正因如此,不占据多余的空间,是时间换空间的做法
(4)对于varchar来说,最多能存放的字符个数为65532

总之,结合性能角度(char更快)和节省磁盘空间角度(varchar更小),具体情况还需具体来设计数据库才是妥当的做法


57.varchar(50)中50的涵义

最多存放50个字符,varchar(50)和(200)存储hello所占空间一样,但后者在排序时会消耗更多内存,因为order by col采用fixed_length计算col长度(memory引擎也一样)。在早期 MySQL 版本中, 50 代表字节数,现在代表字符数


58.int(20)中20的涵义

是指显示字符的长度。20表示最大显示宽度为20,但仍占4字节存储,存储范围不变
不影响内部存储,只是影响带 zerofill 定义的 int 时,前面补多少个 0,易于报表展示


59.mysql中int(10)和char(10)以及varchar(10)的区别

int(10)的10表示显示的数据的长度,不是存储数据的大小
chart(10)和varchar(10)的10表示存储数据的大小,即表示存储多少个字符

int(10):10位的数据长度 9999999999,占32个字节,int型4位
char(10): 10位固定字符串,不足补空格 最多10个字符
varchar(10): 10位可变字符串,最多10个字符
char(10):表示存储定长的10个字符,不足10个就用空格补齐,占用更多的存储空间
varchar(10):表示存储10个变长的字符,存储多少个就是多少个,空格也按一个字符存储,这一点是和char(10)的空格不同的,char(10)的空格表示占位不算一个字符


60.FLOAT和DOUBLE的区别?

FLOAT类型数据可以存储至多8位十进制数,并在内存中占4字节
DOUBLE类型数据可以存储至多18位十进制数,并在内存中占8字节


61.drop、delete与truncate区别

三者都表示删除,但是三者有一些差别:

DeleteTruncateDrop
类型属于DML属于DDL属于DDL
回滚可回滚不可回滚不可回滚
删除内容表结构还在,删除表的全部或者一部分数据行表结构还在,删除表中的所有数据从数据库中删除表,所有的数据行,索引和权限也会被删除
删除速度删除速度慢,需要逐行删除删除速度快删除速度最快

因此,在不再需要一张表的时候,用drop;在想删除部分数据行时候,用delete;在保留表而删除所有数据的时候用truncate


62.UNION与UNION ALL的区别?

(1)如果使用UNION ALL,不会合并重复的记录行
(2)效率 UNION 高于 UNION ALL


63.如何定位及优化SQL语句的性能问题?创建的索引有没有被使用到?或者说怎么才可以知道这条语句运行很慢的原因?

对于低性能的SQL语句的定位,最重要也是最有效的方法就是使用执行计划,MySQL提供了explain命令来查看语句的执行计划。 我们知道,不管是哪种数据库,或者是哪种数据库引擎,在对一条SQL语句进行执行的过程中都会做很多相关的优化,对于查询语句,最重要的优化方式就是使用索引。 而执行计划,就是显示数据库引擎对于SQL语句的执行的详细,其中包含了是否使用索引,使用什么索引,使用的索引的相关信息等


64.SQL的生命周期?

(1)应用服务器与数据库服务器建立一个连接
(2)数据库进程拿到请求sql
(3)解析并生成执行计划,执行
(4)读取数据到内存并进行逻辑处理
(5)通过步骤一的连接,发送结果到客户端
(6)关掉连接,释放资源


65.大表数据查询,怎么优化

当MySQL单表记录数过大时,数据库的CRUD性能会明显下降,一些常见的优化措施如下:
(1)限定数据的范围:务必禁止不带任何限制数据范围条件的查询语句

(2)优化shema、sql语句优化 + 索引

(3)缓存,memcached, redis

(4)读/写分离:经典的数据库拆分方案,主库负责写,从库负责读

(5)垂直拆分:根据数据库里面数据表的相关性进行拆分
优点:可以使得行数据变小,在查询时减少读取的Block数,减少I/O次数。此外,垂直分区可以简化表的结构,易于维护。
缺点:主键会出现冗余,需要管理冗余列,并会引起Join操作,可以通过在应用层进行Join来解决。此外,垂直分区会让事务变得更加复杂
适用场景:
①如果一个表中某些列常用,另外一些列不常用
②可以使数据行变小,一个数据页能存储更多数据,查询时减少I/O次数

(6)水平切分:针对数据量大的表,这一步最麻烦,最能考验技术水平,要选择一个合理的sharding key, 为了有好的查询效率,表结构也要改动,做一定的冗余,应用也要改,sql中尽量带sharding key,将数据定位到限定的表上去查,而不是扫描全部的表

①保持数据表结构不变,通过某种策略存储数据分片。这样每一片数据分散到不同的表或者库中,达到了分布式的目的。水平拆分可以支撑非常大的数据量。
②水平拆分是指数据表行的拆分,表的行数超过200万行时,就会变慢,这时可以把一张的表的数据拆成多张表来存放
水品拆分可以支持非常大的数据量。需要注意的一点是:分表仅仅是解决了单一表数据过大的问题,但由于表的数据还是在同一台机器上,其实对于提升MySQL并发能力没有什么意义,所以水平拆分最好分库

尽量不要对数据进行分片,因为拆分会带来逻辑、部署、运维的各种复杂度 ,一般的数据表在优化得当的情况下支撑千万以下的数据量是没有太大问题的。如果实在要分片,尽量选择客户端分片架构,这样可以减少一次和中间件的网络I/O互交

数据库分片的两种常见方案:
客户端代理:分片逻辑在应用端,封装在jar包中,通过修改或者封装JDBC层来实现。 当当网的Sharding-JDBC、阿里的TDDL是两种比较常用的实现
中间件代理:在应用和数据中间加了一个代理层。分片逻辑统一维护在中间件服务中。Mycat 、360的Atlas、网易的DDB等等都是这种架构的实现


66.超大分页怎么处理?

超大的分页一般从两个方向上来解决:

(1)数据库层面
类似于select * from table where age > 20 limit 1000000,10这种查询其实也是有可以优化的余地的。这条语句需要加载1000000数据然后基本上全部丢弃,只取10条当然比较慢。可以修改为select * from table where id in (select id from table where age > 20 limit 1000000,10)。这样虽然也load了一百万的数据,但是由于索引覆盖,要查询的所有字段都在索引中,所以速度会很快
同时如果ID连续的话,还可以select * from table where id > 1000000 limit 10。效率也是不错的,优化的可能性有许多种,但是核心思想都一样,就是减少load的数据

从需求的角度减少这种请求…主要是不做类似的需求(直接跳转到几百万页之后的具体某一页.只允许逐页查看或者按照给定的路线走,这样可预测,可缓存)以及防止ID泄漏且连续被人恶意攻击.

解决超大分页,其实主要是靠缓存,可预测性的提前查到内容,缓存至redis等k-V数据库中,直接返回即可


67.mysql分页

LIMIT子句可以被用于强制SELECT语句返回指定的记录数。LIMIT接受一个或两个数字参数。参数必须是一个整数常量。如果给定两个参数,第一个参数指定第一个返回记录行的偏移量,第二个参数指定返回记录行的最大数目。初始记录行的偏移量是0(而不是 1)

mysql> SELECT * FROM table LIMIT 5,10; // 检索记录行 6-15 

为了检索从某一个偏移量到记录集的结束所有的记录行,可以指定第二个参数为 -1:

mysql> SELECT * FROM table LIMIT 95,-1; // 检索记录行 96-last. 

如果只给定一个参数,它表示返回最大的记录行数目:

mysql> SELECT * FROM table LIMIT 5; //检索前 5 个记录行

68.为什么要尽量设定一个主键?

主键是数据库确保数据行在整张表唯一性的保障,即使业务上本张表没有主键,也建议添加一个自增长的ID列作为主键。设定了主键之后,在后续的删改查的时候可能更加快速以及确保操作数据范围安全


69.主键使用自增ID还是UUID?

推荐使用自增ID,不要使用UUID。

因为在InnoDB存储引擎中,主键索引是作为聚簇索引存在的,也就是说,主键索引的B+树叶子节点上存储了主键索引以及全部的数据(按照顺序),如果主键索引是自增ID,那么只需要不断向后排列即可,如果是UUID,由于到来的ID与原来的大小不确定,会造成非常多的数据插入,数据移动,然后导致产生很多的内存碎片,进而造成插入性能的下降。

总之,在数据量大一些的情况下,用自增主键性能会好一些。
关于主键是聚簇索引,如果没有主键,InnoDB会选择一个唯一键来作为聚簇索引,如果没有唯一键,会生成一个隐式的主键


70.字段为什么要求定义为not null?

null值会占用更多的字节,且会在程序中造成很多与预期不符的情况


71.如果要存储用户的密码散列,应该使用什么字段进行存储?

密码散列、用户身份证号等固定长度的字符串应该使用char而不是varchar来存储,这样可以节省空间且提高检索效率


72.优化查询过程中的数据访问

访问数据太多导致查询性能下降
确定应用程序是否在检索大量超过需要的数据,可能是太多行或列
确认MySQL服务器是否在分析大量不必要的数据行

避免犯如下SQL语句错误
(1)查询不需要的数据。解决办法:使用limit解决
(2)多表关联返回全部列。解决办法:指定列名
(3)总是返回全部列。解决办法:避免使用SELECT *
(4)重复查询相同的数据。解决办法:可以缓存数据,下次直接读取缓存
(5)是否在扫描额外的记录。解决办法:使用explain进行分析,如果发现查询需要扫描大量的数据,但只返回少数的行,
可以通过如下技巧去优化:使用索引覆盖扫描,把所有的列都放到索引中,这样存储引擎不需要回表获取对应行就可以返回结果。
(6)改变数据库和表的结构,修改数据表范式
(7)重写SQL语句,让优化器可以以更优的方式执行查询


73.优化长难的查询语句

一个复杂查询还是多个简单查询
MySQL内部每秒能扫描内存中上百万行数据,相比之下,响应数据给客户端就要慢得多
使用尽可能小的查询是好的,但是有时将一个大的查询分解为多个小的查询是很有必要的

(1)切分查询
(2)将一个大的查询分为多个小的相同的查询
(3)一次性删除1000万的数据要比一次删除1万,暂停一会的方案更加损耗服务器开销
(4)分解关联查询,让缓存的效率更高
(5)执行单个查询可以减少锁的竞争
(6)在应用层做关联更容易对数据库进行拆分
(7)查询效率会有大幅提升
(8)较少冗余记录的查询


74.优化特定类型的查询语句

(1)count()会忽略所有的列,直接统计所有列数,不要使用count(列名)
(2)MyISAM中,没有任何where条件的count(
)非常快
(3)当有where条件时,MyISAM的count统计不一定比其它引擎快。
(4)可以使用explain查询近似值,用近似值替代count(*)
(5)增加汇总表
(6)使用缓存


75.优化关联查询

确定ON或者USING子句中是否有索引。
确保GROUP BY和ORDER BY只有一个表中的列,这样MySQL才有可能使用索引


76.优化WHERE子句(SQL优化)

(1)禁止3表以上的join,用jion替换子查询
(2)避免"select *"和排序功能共同使用
(3)用union all替换union
(4)避免数据类型的转换,同数据类型比较
(5)避免排序(通过索引或减少排序记录数)
(6)对数据尽早过滤(复合索引过滤性更好的字段放的更靠前;尽量加少最后join结果集的数量)
(7)把大sql拆分为多小sql
(8)如果只是分组,用”group by a1 order by null“替换“group by a1”去除排序
(9)禁止索引null列
(10)字符列是否是前缀索引

(1)对查询进行优化,应尽量避免全表扫描
首先应考虑在where及order by涉及的列上建立索引
在使用索引字段作为条件时,如果该索引是复合索引,那么必须使用到该索引中的第一个字段作为条件时才能保证系统使用该索引,否则该索引将不会被使用,并且应尽可能的让字段顺序与索引顺序相一致

索引对列存在大量重复数据无效,索引并不是越多越好,并不是所有索引对查询都有效,SQL是根据表中数据来进行查询优化的,当索引列有大量数据重复时,SQL查询可能不会去利用索引,如一表中有字段sex、male、female几乎各一半,那么即使在sex上建了索引也对查询效率起不了作用

索引并不是越多越好,索引固然可以提高相应的 select 的效率,但同时也降低了 insert 及 update 的效率,因为 insert 或 update 时有可能会重建索引,所以怎样建索引需要慎重考虑,视具体情况而定。一个表的索引数最好不要超过6个,若太多则应考虑一些不常使用到的列上建的索引是否有必要

(2)应尽量避免在where子句中对字段进行null值判断、使用!=或<>操作符、使用or来连接条件、使用in和not in(exists代替in )、like避免使用%开头,考虑全文检索、避免对字段进行表达式操作、避免对字段进行函数操作,否则将导致引擎放弃使用索引而进行全表扫描

select id from t where num is null
-- 可以在num上设置默认值0,确保表中num列没有null值,然后这样查询:
select id from t where num=?

select id from t where num=10 or num=20
-- 可以这样查询:
select id from t where num=10 union all select id from t where num=20

select id from t where num in(1,2,3) 
-- 对于连续的数值,能用between就不要用in了
select id from t where num between 1 and 3

select id from t where num/2=100
-- 应改为:
select id from t where num=100*2

select id from t where substring(name,1,3)=’abc’
-- name以abc开头的id应改为:
select id from t where name like ‘abc%’

(3)如果在where子句中使用参数,也会导致全表扫描。因为SQL只有在运行时才会解析局部变量,但优化程序不能将访问计划的选择推迟到运行时;它必须在编译时进行选择。然而,如果在编译时建立访问计划,变量的值还是未知的,因而无法作为索引选择的输入项。如下面语句将进行全表扫描

select id from t where num=@num
-- 可以改为强制查询使用索引:
select id from t with(index(索引名)) where num=@num

(4)不要在where子句中的“=”左边进行函数、算术运算或其他表达式运算,否则系统将可能无法正确使用索引

(5)尽可能的使用varchar/nvarchar代替char/nchar,因为首先变长字段存储空间小,可以节省存储空间,其次对于查询来说,在一个相对较小的字段内搜索效率显然要高些

(6)任何地方都不要使用*,用具体的字段列表代替“*”,不要返回用不到的任何字段

(7)尽量避免使用游标,因为游标的效率较差,如果游标操作的数据超过1万行,那么就应该考虑改写

(8)避免频繁创建和删除临时表,以减少系统表资源的消耗
临时表并不是不可使用,适当地使用它们可以使某些例程更有效,例如,当需要重复引用大型表或常用表中的某个数据集时。但是,对于一次性事件,最好使用导出表。
在新建临时表时,如果一次性插入数据量很大,那么可以使用 select into 代替 create table,避免造成大量 log ,以提高速度;如果数据量不大,为了缓和系统表的资源,应先create table,然后insert。
如果使用到了临时表,在存储过程的最后务必将所有的临时表显式删除,先 truncate table ,然后 drop table,这样可以避免系统表的较长时间锁定

LIMIT偏移量大的时候,查询效率较低;可以记录上次查询的最大ID,下次查询时直接根据该ID来查询


77.数据库为什么要优化

(1)系统的吞吐量瓶颈往往出现在数据库的访问速度上
(2)随着应用程序的运行,数据库的中的数据会越来越多,处理时间会相应变慢
(3)数据是存放在磁盘上的,读写速度无法和内存相比

优化原则:减少系统瓶颈,减少资源占用,增加系统的反应速度


78.数据库结构优化

一个好的数据库设计方案对于数据库的性能往往会起到事半功倍的效果
需要考虑数据冗余、查询和更新的速度、字段的数据类型是否合理等多方面的内容。

(1)将字段很多的表分解成多个表
对于字段较多的表,如果有些字段的使用频率很低,可以将这些字段分离出来形成新表。
因为当一个表的数据量很大时,会由于使用频率低的字段的存在而变慢。

(2)增加中间表
对于需要经常联合查询的表,可以建立中间表以提高查询效率
通过建立中间表,将需要通过联合查询的数据插入到中间表中,然后将原来的联合查询改为对中间表的查询。

(3)增加冗余字段
设计数据表时应尽量遵循范式理论的规约,尽可能的减少冗余字段,让数据库设计看起来精致、优雅。但是,合理的加入冗余字段可以提高查询速度
表的规范化程度越高,表和表之间的关系越多,需要连接查询的情况也就越多,性能也就越差

注意:冗余字段的值在一个表中修改了,就要想办法在其他表中更新,否则就会导致数据不一致的问题


79.MySQL主从复制

将主数据库中的DDL和DML操作通过二进制日志(BINLOG)传输到从数据库上,然后将这些日志重新执行(重做);从而使得从数据库的数据与主数据库保持一致


80.主从复制的作用

主数据库出现问题,可以切换到从数据库。
可以进行数据库层面的读写分离。
可以在从数据库上进行日常备份


81.MySQL主从复制解决的问题

数据分布:随意开始或停止复制,并在不同地理位置分布数据备份
负载均衡:降低单个服务器的压力
高可用和故障切换:帮助应用程序避免单点失败
升级测试:可以用更高版本的MySQL作为从库


82.MySQL主从复制工作原理

(1)在主库上把数据更改记录到二进制日志
(2)从库将主库的日志复制到自己的中继日志
(3)从库读取中继日志的事件,将其重放到从库数据中

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

未禾

您的支持是我最宝贵的财富!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值