mysql数据库面试总结
数据库优化
建表优化
1)数据库范式
l 第一范式(1NF):强调的是列的原子性,即列不能够再分成其他几列。
如电话列可进行拆分---家庭电话、公司电话
l 第二范式(2NF):首先是 1NF,另外包含两部分内容,一是表必须有主键;二是没有包含在主键中的列必须完全依赖于主键,而不能只依赖于主键的一部分。
l 第三范式(3NF):首先是 2NF,另外非主键列必须直接依赖于主键,不能存在传递依赖。
比如Student表(学号,姓名,年龄,性别,所在院校,院校地址,院校电话)
这样一个表结构,就存在上述关系。 学号--> 所在院校 --> (院校地址,院校电话)
这样的表结构,我们应该拆开来,如下。
(学号,姓名,年龄,性别,所在院校)--(所在院校,院校地址,院校电话)
满足这些规范的数据库是简洁的、结构明晰的;同时,不会发生插入(insert)、删除(delete)和更新(update)操作异常。
2)数据类型选择
l 数字类型
Float和double选择(尽量选择float)
区分开TINYINT / INT / BIGINT,能确定不会使用负数的字段,建议添加 unsigned定义
能够用数字类型的字段尽量选择数字类型而不用字符串类型的
l 字符类型
char,varchar,TEXT的选择:非万不得已不要使用 TEXT 数据类型,定长字段,建议使用 CHAR 类型(填空格),不定长字段尽量使用 VARCHAR(自动适应长度,超过阶段),且仅仅设定适当的最大长度
l 时间类型
按选择优先级排序DATE(精确到天)、TIMESTAMP、DATETIME(精确到时间)
l ENUM
对于状态字段,可以尝试使用 ENUM 来存放
l 避免使用NULL字段,很难查询优化且占用额外索引空间
3)字符编码
同样的内容使用不同字符集表示所占用的空间大小会有较大的差异,所以通过使用合适的字符集,可以帮助我们尽可能减少数据量,进而减少IO操作次数。
1.纯拉丁字符能表示的内容,选择 latin1 字符编码
2.中文可选用utf-8
3.MySQL的数据类型可以精确到字段,所以当我们需要大型数据库中存放多字节数据的时候,可以通过对不同表不同字段使用不同的数据类型来较大程度减小数据存储量,进而降低 IO 操作次数并提高缓存命中率
Sql优化
1) 只返回需要的数据
a) 不要写SELECT *的语句
b) 合理写WHERE子句,不要写没有WHERE的SQL语句。
2) 尽量少做重复的工作
可以合并一些sql语句
3) 适当建立索引(不是越多越好)但以下几点会进行全表扫描
a) 左模糊查询’%...’
b) 使用了不等操作符!=
c) Or使用不当,or两边都必须有索引才行
d) In 、not in
e) Where子句对字段进行表达式操作
f) 对于创建的复合索引(从最左边开始组合),查询条件用到的列必须从左边开始不能间隔。否则无效,复合索引的结构与电话簿类似
g) 全文索引:当于对文件建立了一个以词库为目录的索引(文件大全文索引比模糊匹配效果好)
能在char、varchar、text类型的列上面创建全文索引
MySQL 5.6 Innodb引擎也能进行全文索引
搜索语法:MATCH (列名1, 列名2,…) AGAINST (搜索字符串 [搜索修饰符])
如果列类型是字符串,但在查询时把一个数值型常量赋值给了一个字符型的列名name,那么虽然在name列上有索引,但是也没有用到。
4) 使用join代替子查询
5) 使用union代替手动创建临时表
索引优化
一、 创建索引,以下情况不适合建立索引
l 表记录太少
l 经常插入、删除、修改的表
l 数据重复且分布平均的表字段
二、 复合索引
如果一个表中的数据在查询时有多个字段总是同时出现则这些字段就可以作为复合索引
索引
索引是对数据库表中一列或多列的值进行排序的一种结构。
优点:
l 大大加快数据的检索速度
l 创建唯一性索引,保证数据库表中每一行数据的唯一性
l 可以加速表和表之间的连接
缺点:
l 索引需要占物理空间。
l 当对表中的数据进行增加、删除和修改的时候,索引也要动态的维护,
降低了数据的维护速度。
索引分类:
l 普通索引
create index zjj_temp_index_1 on zjj_temp_1(first_name);
drop index zjj_temp_index_1;
l 唯一索引,索引列的值必须唯一,但允许有空值
create unique index zjj_temp_1 on zjj_temp_1(id);
l 主键索引,它是一种特殊的唯一索引,不允许有空值。
l 组合索引
事务
数据库事务(Database Transaction) ,是指作为单个逻辑工作单元执行的一系列操作,要么完全地执行,要么完全地不执行。
四大特征:
(1)原子性
事务必须是原子工作单元;对于其数据修改,要么全都执行,要么全都不执行。
(2)一致性
事务的一致性指的是在一个事务执行之前和执行之后数据库都必须处于一致性状态。事务执行的结果必须是使数据库从一个一致性状态变到另一个一致性状态。
(3) 隔离性(关于事务的隔离性数据库提供了多种隔离级别)
一个事务的执行不能干扰其它事务。即一个事务内部的操作及使用的数据对其它并发事务是隔离的,并发执行的各个事务之间不能互相干扰。
(4)持久性
事务完成之后,它对于数据库中的数据改变是永久性的。该修改即使出现系统故障也将一
直保持。
在介绍数据库提供的各种隔离级别之前,我们先看看如果不考虑事务的隔离性,会发生的几种问题:
l 脏读
脏读是指在一个事务处理过程里读取了另一个未提交的事务中的数据。
l 不可重复读
l 幻读
幻读和不可重复读都是读取了另一条已经提交的事务,不可重复读重点在于update和delete,而幻读的重点在于insert。
在可重复读中,该sql第一次读取到数据后,就将这些数据加锁,其它事务无法修改这些数据,就可以实现可重复 读了。但这种方法却无法锁住insert的数据,所以当事务A先前读取了数据,或者修改了全部数据,事务B还是可以insert数据提交,这时事务A就会 发现莫名其妙多了一条之前没有的数据,这就是幻读,不能通过行锁来避免。需要Serializable隔离级别 ,读用读锁,写用写锁,读锁和写锁互斥,这么做可以有效的避免幻读、不可重复读、脏读等问题,但会极大的降低数据库的并发能力。
现在来看看MySQL数据库为我们提供的四种隔离级别:
① Serializable (串行化):可避免脏读、不可重复读、幻读的发生。
② Repeatable read (可重复读):可避免脏读、不可重复读的发生。
③ Read committed (读已提交):可避免脏读的发生。
④ Read uncommitted (读未提交):最低级别,任何情况都无法保证。
在MySQL数据库中默认的隔离级别为Repeatable read (可重复读)。
锁模式包括:
l 共享锁:(读取)操作创建的锁。其他用户可以并发读取数据,但任何事物都不能获取数据上的排它锁,直到已释放所有共享锁。
l 排他锁(X锁):对数据A加上排他锁后,则其他事务不能再对A加任任何类型的封锁。获准排他锁的事务既能读数据,又能修改数据。
l 更新锁:
更新 (U) 锁可以防止通常形式的死锁。如果两个事务获得了资源上的共享模式锁,然后试图同时更新数据,则两个事务需都要转换共享锁为排它 (X) 锁,并且每个事务都等待另一个事务释放共享模式锁,因此发生死锁。
若要避免这种潜 在的死锁问题,请使用更新 (U) 锁。一次只有一个事务可以获得资源的更新 (U) 锁。如果事务修改资源,则更新 (U) 锁转换为排它 (X) 锁。否则,锁转换为共享锁。
锁的粒度主要有以下几种类型:
l 行锁: 粒度最小,并发性最高
l 页锁:一次锁定一页。25个行锁可升级为一个页锁。
l 表锁:粒度大,并发性低
l 数据库锁:控制整个数据库操作
乐观锁:相对悲观锁而言,乐观锁假设认为数据一般情况下不会造成冲突,所以在数据进行提交更新的时候,才会正式对数据的冲突与否进行检测,如果发现冲突了,则让返回用户错误的信息,让用户决定如何去做。一般的实现乐观锁的方式就是记录数据版本。
悲观锁:顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会block直到它拿到锁。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。
索引
MyISAM、InnoDB区别
l MyISAM类型不支持事务处理等高级处理,而InnoDB类型支持。
l MyISAM表不支持外键,InnoDB支持
l MyISAM锁的粒度是表级,而InnoDB支持行级锁定。
l MyISAM支持全文类型索引,而InnoDB不支持全文索引。(mysql 5.6后innodb支持全文索引)
MyISAM相对简单,所以在效率上要优于InnoDB,小型应用可以考虑使用MyISAM。当你的数据库有大量的写入、更新操作而查询比较少或者数据完整性要求比较高的时
候就选择innodb表。当你的数据库主要以查询为主,相比较而言更新和写 入比较少,并且业务方面数据完整性要求不那么严格,就选择mysiam表。
MyISAM和InnoDB索引实现:
MyISAM索引实现
MyISAM索引文件和数据文件是分离的,索引文件仅保存数据记录的地址。
l 主索引
MyISAM引擎使用B+Tree作为索引结构,叶节点的data域存放的是数据记录的地址。
l 辅助索引
在MyISAM中,主索引和辅助索引(Secondary key)在结构上没有任何区别,只是主索引要求key是唯一的,而辅助索引的key可以重复。
MyISAM中索引检索的算法为首先按照B+Tree搜索算法搜索索引,如果指定的Key存在,则取出其data域的值,然后以data域的值为地址,读取相应数据记录。
MyISAM的索引方式也叫做“非聚集”的,之所以这么称呼是为了与InnoDB的聚集索引区分。
InnoDB索引实现
然InnoDB也使用B+Tree作为索引结构,但具体实现方式却与MyISAM截然不同.
l 主索引
InnoDB表数据文件本身就是主索引。
InnoDB主索引(同时也是数据文件)的示意图,可以看到叶节点包含了完整的数据记录。这种索引叫做聚集索引。因为InnoDB的数据文件本身要按主键聚集,所以InnoDB要求表必须有主键(MyISAM可以没有),如果没有显式指定,则MySQL系统会自动选择一个可以唯一标识数据记录的列作为主键,如果不存在这种列,则MySQL自动为InnoDB表生成一个隐含字段作为主键,这个字段长度为6个字节,类型为长整形。
l 辅助索引
InnoDB的所有辅助索引都引用主键作为data域。
聚集索引这种实现方式使得按主键的搜索十分高效,但是辅助索引搜索需要检索两遍索引:首先检索辅助索引获得主键,然后用主键到主索引中检索获得记录。
不同存储引擎的索引实现方式对于正确使用和优化索引都非常有帮助,例如知道了InnoDB的索引实现后,就很容易明白
1、为什么不建议使用过长的字段作为主键,因为所有辅助索引都引用主索引,过长的主索引会令辅助索引变得过大。再例如,
2、用非单调的字段作为主键在InnoDB中不是个好主意,因为InnoDB数据文件本身是一颗B+Tree,非单调的主键会造成在插入新记录时数据文件为了维持B+Tree的特性而频繁的分裂调整,十分低效,而使用自增字段作为主键则是一个很好的选择。
InnoDB索引和MyISAM索引的区别:
l 一是主索引的区别,InnoDB的数据文件本身就是索引文件。而MyISAM的索引和数据是分开的。
l 二是辅助索引的区别:InnoDB的辅助索引data域存储相应记录主键的值而不是地址。而MyISAM的辅助索引和主索引没有多大区别。
红黑树 B树 B+树 B-树
二叉查找树(BST):
二叉排序树或者是一棵空树,或者是具有下列性质的二叉树:
l 若左子树不空,则左子树上所有结点的值均小于它的根结点的值。
l 若右子树不空,则右子树上所有结点的值均大于它的根结点的值。
l 左、右子树也分别为二叉排序树。
l 没有键值相等的节点(因此,插入的时候一定是叶子节点)。
删除算法
l 要删除节点是叶子节点。
l 要删除的节点只有一个孩子(左孩子或右孩子),这种情况比较简单,只需要将该孩子连接到当前节点的父节点即可。
l 要删除的节点有两个孩子,这个时候的算法就比较复杂(相比较于只有一个孩子的情况)。首先我们需要找到待删除节点的左子树上的最大值节点,或者右子树上的最小值节点,然后将该节点的参数值与待删除的节点参数值进行交换,最后删除该节点,这样需要删除的参数就从该二叉树中删除了。
红黑树:
红黑树(Red Black Tree) 是一种自平衡二叉查找树 :
l 每个节点或者是黑色,或者是红色。
l 根节点是黑色。
l 每个叶子节点是黑色。
l 如果一个节点是红色的,则它的子节点必须是黑色的。
l 从一个节点到该节点的子孙节点的所有路径上包含相同数目的黑节点。
红黑树的各种操作的时间复杂度是O(log2N)。
红黑树 vs AVL
红黑树的查询性能略微逊色于AVL树,因为他比avl树会稍微不平衡最多一层,也就是说红黑树的查询性能只比相同内容的avl树最多多一次比较,但是,红黑树在插入和删除上完爆avl树,avl树每次插入删除会进行大量的平衡度计算,而红黑树为了维持红黑性质所做的红黑变换和旋转的开销,相较于avl树为了维持平衡的开销要小得多
插入操作
红父
如果新节点的父结点为红色,这时就需要进行一系列操作以保证整棵树红黑性质。如下图所示,由于父结点为红色,此时可以判定,祖父结点必定为黑色。这时需要根据叔父结点的颜色来决定做什么样的操作。青色结点表示颜色未知。由于有可能需要根结点到新点的路径上进行多次旋转操作,而每次进行不平衡判断的起始点(我们可将其视为新点)都不一样。所以我们在此使用一个蓝色箭头指向这个起始点,并称之为判定点。
l 红叔
当叔父结点为红色时,如下图所示,无需进行旋转操作,只要将父和叔结点变为黑色,将祖父结点变为红色即可。但由于祖父结点的父结点有可能为红色,从而违反红黑树性质。此时必须将祖父结点作为新的判定点继续向上(迭代)进行平衡操作。
需要注意的是,无论“父节点”在“叔节点”的左边还是右边,无论“新节点”是“父节点”的左孩子还是右孩子,它们的操作都是完全一样的(其实这种情况包括4种,只需调整颜色,不需要旋转树形)。
l 黑叔
当叔父结点为黑色时,需要进行旋转,以下图示了所有的旋转可能:
Case 1:
Case 2:
Case 3:
Case 4:
B树与B-树:
B-tree树即B树,B即Balanced,平衡的意思。因为B树的原英文名称为B-tree,而国内很多人喜欢把B-tree译作B-树,其实,这是个非常不好的直译,很容易让人产生误解。如人们可能会以为B-树是一种树,而B树又是另一种树。而事实上是,B-tree就是指的B树。
m阶B树是一棵平衡的m路搜索树。它是空树,或者是满足下列性质的树:
l 根结点的儿子数为[2, M];
l 除根结点以外的非叶子结点的儿子数为[M/2, M]; (M/2向上取整)
l 每个结点存放至少M/2-1(取上整)和至多M-1个关键字;
l 非叶子结点的关键字个数=指向儿子的指针个数-1;
l 非叶子结点的关键字:K[1], K[2], …, K[X-1];且K[i] < K[i+1];
l 非叶子结点的指针:P[1], P[2], …, P[X];其中P[1]指向关键字小于K[1]的
子树,P[X]指向关键字大于K[X-1]的子树,其它P[i]指向关键字属于(K[i-1], K[i])的子树;
l 所有叶子结点位于同一层;
B+树:
B+树是B-树的变体,也是一种多路搜索树:
其定义基本与B-树同,除了:
l 非叶子结点的子树指针与关键字个数相同;
l 非叶子结点的子树指针P[i],指向关键字值属于[K[i], K[i+1])的子树
(B-树是开区间);
l 为所有叶子结点增加一个指针链;
l 所有关键字都在叶子结点出现;
基本SQL操作
l SELECT * FROM table ORDER BY field DESC; (ASC|DESC)
SELECT DISTINCT field from table where 范围
l INSERT INTO table_name (column1,column2,column3,...)
VALUES (value1,value2,value3,...);
l UPDATE table_name SET column1=value1,column2=value2,...
WHERE some_column=some_value;
l DELETE FROM table_name WHERE some_column=some_value;
LIKE 操作符
SELECT column_name(s) FROM table_name WHERE column_name LIKE pattern;
IN 操作符
SELECT column_name(s) FROM table_name WHERE column_name
IN (value1,value2,...);
BETWEEN 操作符
SELECT column_name(s) FROM table_name WHERE column_name BETWEEN
JOIN
左连接,右连接,内连接
left join(左联接): 返回包括左表中的所有记录和右表中联结字段相等的记录。
right join(右联接): 返回包括右表中的所有记录和左表中联结字段相等的记录。
inner join(等值连接): 只返回两个表中联结字段相等的行。(默认)
UNION 操作符
UNION 操作符用于合并两个或多个 SELECT 语句的结果集。
SELECT country, name FROM Websites WHERE country='CN'
UNION
SELECT country, app_name FROM apps WHERE country='CN'
ORDER BY country;
创建视图
CREATE VIEW view_name AS SELECT column_name(s) FROM table_name WHERE condition
SQL函数
Avg() Count() Max() Min() Sum()
Group By():
GROUP BY 语句用于结合聚合函数,根据一个或多个列对结果集进行分组。
SELECT column_name, aggregate_function(column_name)
FROM table_name WHERE column_name operator value
GROUP BY column_name;
HAVING 子句可以让我们筛选分组后的各组数据。
SELECT column_name, aggregate_function(column_name)
FROM table_name WHERE column_name operator value
GROUP BY column_name
HAVING aggregate_function(column_name) operator value;
如何查询数据库表结构,主键
desc tabl_name;
建表
CREATE TABLE 表名称
(
列名称1 数据类型,
....
)