参考资料:
[1]. MySQL 是怎样运行的:从根儿上理解 MySQL
[2]. Mysql并发时经典常见的死锁原因及解决方法
[3]. 数据库连接池-常用参数配置及含义
binlog机制描述,binlog日志格式有哪些
MySQL主从架构(读写分离),主从数据复制过程,数据复制过程丢失如何处理
在数据库层面怎么保证对某个库存数据的加减安全?
数据库分布式锁
- 悲观锁
for update 直接加锁 - 乐观锁
增加version字段,每次更新加一次version,更新的时候where带上上一次的version
嵌套子查询如何优化
建立子查询,转化为内连接
Innodb如何解决幻读
MVCC:每条记录记录修改的版本,里面含有事务的id,事务一开始的时候保存ReadView,包含当时活跃的事务id,提交的事务id等,然后查询的时候找到那些已经提交的事务id提交的记录。
如果线上出现慢sql,如何定位和解决,有实际动手优化过慢sql吗。
慢查询日志,explain
索引有哪些种类
聚簇索引,二级索引,联合索引。
建立索引的原则
根据用途进行建立,建立尽量少的索引
聚簇索引和非聚簇索引实现区别
非聚簇索引只包含索引列和主id,查询的时候需要回表
mysql写入数据的时候,是先把数据写到缓冲区,然后再flush到磁盘的,如何在flush过程中发生了宕机,数据如何恢复。
读取log日志,然后将log日志写入到buffer,再刷新到磁盘
mysql的底层数据结构、B+树和B树区别
B+树是应数据库所需而出现的一种B树的变形树
对比:
- B+树关键字和子树的对应关系为:n:n;B树关键字和子树的对应关系为:n-1:n
- B+树的关键字是对应的子树的最大元素,该元素在节点中也有包含;B树的关键字是大于对应的子树的所有元素的,该元素在节点中没有包含。
- B+树种关键字起到索引的作用而已,B树包含的是对应的记录。
连接池的参数都什么意思
maxActive :最大连接数
initialSize:初始化连接数目
maxWait:等待时间
数据库的三范式
数据库单一尽量要精简和联系比较简单,越拆越明那种。
第一范式:列不可分,eg:【联系人】(姓名,性别,电话),一个联系人有家庭电话和公司电话,那么这种表结构设计就没有达到 1NF;
第二范式:有主键,保证完全依赖。eg:订单明细表【OrderDetail】(OrderID,ProductID,UnitPrice,Discount,Quantity,ProductName),Discount(折扣),Quantity(数量)完全依赖(取决)于主键(OderID,ProductID),而 UnitPrice,ProductName 只依赖于 ProductID,不符合2NF;
第三范式:无传递依赖(非主键列 A 依赖于非主键列 B,非主键列 B 依赖于主键的情况),eg:订单表【Order】(OrderID,OrderDate,CustomerID,CustomerName,CustomerAddr,CustomerCity)主键是(OrderID),CustomerName,CustomerAddr,CustomerCity 直接依赖的是 CustomerID(非主键列),而不是直接依赖于主键,它是通过传递才依赖于主键,所以不符合 3NF。
解决幻读
分2种,快照读和当前读
(1)快照读(mvcc) 普通的 select 就是快照读。将历史数据存一份快照,所以其他事务增加与删除数据,对于当前事务来说是不可见的。事务每次取数据的时候都会取创建版本<当前事务的数据,以及删除版本号码>当前版本的数据。
(2)当前读 执行数据库的增删改操作的时, 就是当前读
采用next-key锁的方式解决问题
next-key 锁包含两部分: 记录锁(行锁)+ 间隙锁 就是在索引和索引之间上面加锁
- char和varchar的区别
- 占用空间
char占用的空间开始的时候是固定的,char(n)最少占用n个字节,当然如果存储字符够多,编码起来也多的话,会增加字节,并不是不变的,varchar占用的空间是不固定的,实际存储的字符串长度+1或者+2,用来表示字符串的长度。char(n)和varchar(n)中的n指的是字符。UTF-8:一个汉字=3个字节。GBK:一个汉字=2个字节 - 最大长度
char:255字节
varchar:65535字节 - 截断空格
char会截断空格,char类型如果小于实际定义的字符个数,会用空格进行填充。(参考[1]第5节InnoDB记录结构) - 存储方式
char的存储方式是:英文字符占1个字节,汉字占用2个字节;varchar的存储方式是:英文和汉字都占用2个字节,两者的存储数据都非unicode的字符数据。
-
索引字符串的前缀
创建索引的时候,我们可能会在列上限定长度,如果列过于长,在建索引的时候会出现两个问题:
1、索引的占用空间太大
2、建立索引的时候花费时间过多,对短的字符串排序比较快。
缺点可能会是同一个前缀可能有多个对应的字段值,需要进一步进行排查,还看会使得
-
创建索引和不创建索引的情况
-
建议在真实工作中最好不要使用*作为查询列表,最好把真实用到的列作为查询列表
比如index就比all快,前者是扫描索引,后者是扫描全表。 -
死锁(参考2)
因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去.
此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等竺的进程称为死锁进程。
解决办法:让不同的事务加锁有次序。
例子1:
依次选择多条记录,如果不按照顺序来的话,很容易就产生死锁,最好还是用in来解决,在in里面的列表值mysql是会自动从小到大排序,加锁也是一条条从小到大加的锁。下面的语句中是用5,8,10的顺序进行锁定的,如果8已经被锁定,那么会先锁定5,然后在8这里等待。
Select * from xxx where id in (10,8,5) for update
例子2:
在插入之前会先检查是否存在,会加gap锁,然后插入,select...for update和insert两个语句,两个session分别执行完第一句,加了两个gap锁进去,然后接下来的insert都无法执行了。
insert into t3(xx,xx) on duplicate key update `xx`='XX';
因为insert语句对于主键来说,插入的行不管有没有存在,都会只有行锁。
例子3:
session1锁住了一个id=9这条记录,session2锁住了id<20的范围,除了id=9,被锁住了,然后session1要去插入id=7,已经被锁住,死锁了。
mysql> select * from t3 where id=9 for update;
+----+--------+------+---------------------+
| id | course | name | ctime |
+----+--------+------+---------------------+
| 9 | JX | f | 2016-03-01 11:36:30 |
+----+--------+------+---------------------+
1 row in set (0.00 sec)
Session2:
mysql> select * from t3 where id<20 for update;
锁等待中
Session1:
mysql> insert into t3 values(7,'ae','a',now());
ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction
- mysql表级锁为什么不会产生死锁?
MyISAM 操作数据都是使用表级锁,MyISAM总是一次性获得所需的全部锁,要么全部满足,要么全部等待。所以不会产生死锁,但是由于每操作一条记录就要锁定整个表,导致性能较低,并发不高。
- 怎么解决 like ‘%字符串%’ 时索引失效?
只有右边的%是不会失效的。可以用多个字段的索引覆盖所有查询字段,那样type=index而不是all了
网友评论