2020PHP面试-SQL篇
一、乐观锁和悲观锁
1.悲观锁是指假设并发更新会发生冲突,不管冲突是否会发生,都会使用锁机制。
优点: 完全保证数据安全。
缺点:锁机制会有额外开销,并发度降低。 可能会产生死锁。
2. 乐观锁是指假设数据不会发生冲突,只在数据提交更新的时候,才会对数据是否冲突进行检测(通过版本号),如果发现冲突,则认为是过期数据。
优点: 没有锁机制的额外开销,并发高,不会出现死锁。
缺点:回滚重试性能孙损耗明显。
mysql底层update会自动施加写锁,不会在底层还支持并发更新,所以如果两个请求同时打进来要更新版本号,只有一个会成功,另一个则会由于等待写锁释放而失败,然后需要重新查询最新版本号去更新
二、Innodb的四种隔离级别,mysql的默认隔离级别是
首先要知道脏读、不可重复读、幻读的概念。
脏读:一个事务读取到另一个事务未提交的数据。
不可重复读:同一事务,多次读取同一数据,结果返回不同。也就是读取到了其他事务已提交的数据。 相反,可重复读也就是同一事物多次读取同一数据,结果返回都是一样的。
幻读:主要指的是,一个事务读取到了另一个事务新insert的数据。
四种隔离级别如下:
未提交读(Read uncommitted) 脏读、不可重复读、幻读。
已提交读(Read committed) 不可重复读、幻读。
可重复读(Repeatable read) 幻读。 --- mysql 默认的隔离级别。 但是mysql在此基础上,通过事务版本号的形式解决了可能会出现幻读的问题。mvcc 多版本并发控制
可串行化(SERIALIZABLE) 三种问题都不存在。
mvcc
三、事务的四种特性
事务是并发控制的基本单位,要么全执行,要么全不执行。
原子性、一致性、隔离性、持久性。
四、查找慢查询的sql方法以及优化方案
1. sql慢查询的查找方法:
a. 查看慢查询日志 这里有慢查询日志记录的开启方法 (I. set global slow_query_log=1; 只开启当前数据库的慢查询日志记录,重启Mysql失效。 II.set gloal long_query_time = 1 全局设置,但是对当前连接不生效。 如果需要对当前连接生效, 需要使用 set session_long_query_time = 1.0 III. 如果要永久生效,需要修改my.cnf配置 slow_query_log =1
slow_query_log_file=/var/lib/mysql/atguigu-slow.log 指定开启慢查询以及文件记录位置。)
b. set profiling = 1的情况下 使用show profile; (只能对当前会话执行的sql进行分析) 再通过show profile + id的形式看每条慢的语句慢的原因。 新版本的mysql 用 performance schema
c. show status 可以看一些 操作记录的次数等 以及执行过的一些curd语句,可以理解为作为计数器。
d. show processlist 看Mysql连接线程的问题。
e. 单条sql的话,直接用explain 或者 desc + sql语句,看索引的使用情况,扫描行数等。
2.sql优化方案:
a.查询时,用对索引,减少大量无用的行数扫描。 以及所查即所需,尽量不要使用select * ,指定好使用的列,避免大量冗余数据扫描。以及大量重复查询,在应用层做一下缓存。
b.分解部分复杂的查询变成相关少量的多条, 可以提高缓存效率,单挑查询减少锁的竞争等。
c.特定类型相关优化,尽量不用子查询,用关联或者拆分代替,count(*),加*号会不扫描列,只扫描行。
ps: count(1) 和 count(*) 和 count(name) 的区别
count(1) 和 count(*) 无任何区别,因为()里的不是字段名 也非null。 如果count(null) 则直接等于0 不扫表了。
count(name) name是字段名,这样的话如果name字段为null的就不会计算在总数中。
五、sql具体索引相关优化
1.insert多次插入的时候选择批量插入。
2.%开头的Like无法使用索引。
3.数据类型隐式转换无法使用索引。int 转 string 这种
4.如果mysql使用索引时比全表扫描慢则不使用索引,扫描行数超过30%一般就会不用索引了。(也是避免了频繁的普通索引和聚集索引的切换)
5.大的文本或超长字段不要建索引。
6.垂直分表,水平分表相关,这时候一般可以考虑人为生成主键id,单要维持顺序。
7.避免null字段 原因如下:
(1)所有使用NULL值的情况,都可以通过一个有意义的值的表示,这样有利于代码的可读性和可维护性,并能从约束上增强业务数据的规范性。
(2)NULL值到非NULL的更新无法做到原地更新,更容易发生索引分裂,从而影响性能。(null -> not null性能提升很小,除非确定它带来了问题,否则不要当成优先的优化措施)
(3)NULL值在timestamp类型下容易出问题,特别是没有启用参数explicit_defaults_for_timestamp
(4)NOT IN、!= 等负向条件查询在有 NULL 值的情况下返回永远为空结果,查询容易出错
六、常用的索引类型
主键索引、唯一索引、普通索引、联合索引。
主键索引属于聚簇索引(也叫聚集索引),其他索引属于非聚簇索引。
聚簇索引在存储结构中存储了索引的id以及行记录(使用的是b+树的叶子节点。) 而其他索引存的是索引内容以及主键聚集索引的值,查的时候通过索引再结合主键索引指向的位置获取数据。
为什么主键一般自增,因为自增的话就不用去改变节点的结构,只需要在最后追加就行,不然就要不断调整数据的物理地址分页等,加大io损耗。
联合索引有个最左前缀原则 key idx_a_b_c(a,b,c);
查询 (abc) (ab) (a) (ac)都会直接用到索引时,explain出来的type为ref。 但是需要注意的是,查询ac的时候 Extra还会出现 using Where。 说明不仅使用了索引,还使用了where进行过滤。这个时候如果type为all之类的,则会有优化空间。 ref代表mysql会根据特定的算法快速查找到某个符合条件的索引。
查询 (b) (c) 时, explain 出来的type 为 index。 这种类型表示mysql也用到了索引。但是效率不高,是从第一个索引一直查找到最后一个索引,直到找到符合判断条件的索引才用。
七、分库分表分区
千万行级别的表才要拆。一般行数量级在500W以下是mysql性能最优的时候。
分库:主从复制,负载均衡。降低单数据库压力。
分表:垂直分表 水平分表
垂直分表:
将一个表结构的字段拆成多张表, 容易变更的一些字段(热数据)存在一张表,主更新,并且采用redis等加以缓存配置。不容易变更的一些字段(冷数据)存在另一张表,主查询,可以多配置一些从库。
水平分表:
表的字段结构不变,按id或者日期等属性,将一张表的数据拆分成多张表。
分库分表会带来的系统问题:
数据迁移,分页排序,表关联查询(设计之初最好就避免,通过提高冗余度降低查询复杂度),分布式事务一致性,分布式全局唯一Id (预生成id , uuid ,使用系统时间, snowflake算法等)
分区: 将sql的数据散落在不同的物理文件,可以按照HASH分区(分区键必须是int或者可以通过函数转换为int类型的字段,散落数据很平均)、RANGE分区(比较常用,大多按日期等节点金子那个分区, 默认less than 原则,每个分区不包括指定的那个原则,多个分区的范围要连续,不可重叠)、LIST分区(采用values in 每行数据必须找到自己的分区,否则插入报错)。
ps : mysql的分区受mysql版本限制,用之前需要先用show plugins; 查看partition属性是否启用。
八、char和varchar Int和tinyint
char 定长 最大长度255 空符从右边填充空格 检索时删除尾部空格 | varchar 变长 最大长度65535 不填充空格 检索时不删除空格
int 和 tinyint 存储的数据大小有区别 , tinyint 0 - 255 | int 0 - 2^32 int(m) tinyint(m) 括号里的m指的是显示的数字的长度,不足长度的会以0填充。
九、SQL的约束类型
NOT NULL | UNIQUE | PRIMARY KEY | FOREIGN KEY | CHECK
十、主从复制
Mysql主从复制基于binlog,主服务器使用binlog记录数据变更情况,从服务器通过读取和选择性执行该日志文件来保持和主服务器的数据一致。
主库会生成一个 log dump 线程,给从库传binlog。
从库会生成两个线程, 一个是I/O线程,用来获取主库生成的binlog文件,并写入relay log (中继日志)文件中。 一个是SQL线程,读取并解析relay log文件成具体的操作,用来保证和主库一致。
ps: 有一点呢需要注意的是,主库上的sql操作在并发的场景下,都是并行的,但是从库从relayl log里解析出来后,会串行执行。再加上从库本身还要去获取主库的binlog,时间上在一定是存在主从复制延迟的。
解决方案:
1.主库的binlog没有及时同步给从库:
采用半同步复制(semi-sync):指的就是主库写入 binlog 日志之后,就会将强制此时立即将数据同步到从库,从库将日志写入自己本地的 relay log 之后,接着会返回一个 ack 给主库,主库接收到至少一个从库的 ack 之后才会认为写操作完成了。
2.主从同步延时:
采用并行复制:指的是从库开启多个线程,并行读取relay log中不同库的日志,然后并行重放不同库的日志。属于库级别的并行。
最好还是避免写后立即查询的场景,如果实在避免不了,可以采用1.分主库,降低qps压力。2.并行复制。 3:查询时直连主库。
十一、 auto increment 自增,表中记录达到最大值,会怎样
插入报错。
十二、一条select语句的执行过程
引用大佬的图
十三、索引覆盖与回表
背景:
1. 需要了解索引的定义, 索引是帮助mysql高效获取数据并且排好序的数据结构。
2.Innodb 本身数据就已经聚集在主键索引这个大b+树上了。
3.其他辅助索引叶子节点存的是索引内容以及主键的值。
这时候再来介绍回表:
mysql获取数据的时候,单独从一颗索引树上获取不到全部列的值,需要通过获取叶子节点的主键id再去聚集索引的树上获取列值 就可称为回表。
这时候再说下索引覆盖:
mysql获取数据的时候,从一颗索引树上直接获取了全部列值数据,效率很快,无需回表。 Extra出来的属性为using index。
从回表->索引覆盖的常用做法就是单字段索引->联合索引。 将所查的列字段值作为索引内容存储。
参考:https://www.jianshu.com/p/8991cbca3854
十四、B+树小tips
如图所示,不同页之间维护着双向链表,然后一个叶子节点之间其实可以存储多个数据,叶子节点之间的数据是单向的,通过这种“外双内单”的形式,支持mysql快速进行范围查找。
2020PHP面试-SQL篇的更多相关文章
- 2020PHP面试-PHP篇
一.列举一些PHP的设计模式 单例模式:保证在整个应用程序的生命周期中,任何一个时刻,单例类的实例都只存在一个,同时这个类还必须提供一个访问该类的全局访问点. 工厂模式:定义一个创建对象的接口,但是让 ...
- 2020PHP面试-Redis篇
一.Redis 数据类型 1. string 字符型. 2.hash hash 结构化的对象. key不可重复 3.list 队列 lpush rpop lpop rpush 4. set 集 ...
- 2020PHP面试-网络篇
一.网络协议分层 OSI七层: 物理层.数据链路层.网络层.传输层.会话层.表示层.应用层. TCP/IP四(五)层 : 物理层(主要是光电信号的传输). 数据链路层(MAC地址.以太网协议).网络层 ...
- 50个常用的笔试、面试sql语句
50个常用的笔试.面试sql语句 2009-12-17 15:05 Student(S#,Sname,Sage,Ssex) 学生表Course(C#,Cname,T#) 课程表SC(S#,C#,s ...
- Oracle SQL篇(一)null值之初体验
从我第一次正式的写sql语句到现在,已经超过10年的时间了.我写报表,做统计分析和财务对账,我一点点的接触oracle数据库,并尝试深入了解.这条路,一走就是10年,从充满热情,到开始厌 ...
- 转:sql篇 select from where group by having order by
原文地址: sql篇 select from where group by having order by select from where group by having order by 的基 ...
- 【面试 SQL】【第十六篇】SQL相关面试
=================================================================================== 1.一张表,姓名,科目,成绩,一 ...
- Log4net入门(SQL篇)
我们在Log4net入门(回滚日志篇)中详细讲述了如何将日志信息输出到日志文件中,在这一篇中,我们将讲述如何将日志文件写入SQL Server数据库,以方便我们分析统计日志信息. 首先,我们在SQL ...
- sql篇,动态合并数据
背景: 为何说是一雪前耻呢,想当年,我还小,我出去面试远洋,远远地看着浩哥在那里坐着,然后下班去吃饭,我和东辉却在那里静静地等待着第二轮的技术面试(结果是没有面上,一个是学历问题),终于一个小个子姐姐 ...
随机推荐
- KAZE特征和各向异性扩散滤波
kaze feature: http://www.doc88.com/p-6911376909693.html 各向异性扩散滤波 Scale-space and edge detection usi ...
- C++面试常见问题——15函数的值传递、指针传递、引用传递
函数的值传递.指针传递.引用传递 值传递 形参是实参的拷贝,该表形参的值并不会影响外部的实参.值传递是单向的(实参-->形参),参数的值只能传入,不能传出.当函数内部需要修改参数并且不影响调用者 ...
- @Autowired 和 @ Resource 的区别
转 都是用来装配Bean的注解.都可以写在字段上,或写在setter方法上. @Autowired注解是按照类型(byType)装配依赖对象,默认情况下它要求依赖对象必须存在,如果允许null值,可以 ...
- JS写一个漂亮的音乐播放器
先放上效果图: 正如图中所展示的播放器那样,我们用HTML+CSS+JS将这个效果实现出来. HTML页面布局 <div class="music"> <div ...
- CPU各个具体的指标含义
CPU各个具体的指标含义解释如下: ①CPU(监测到的master主机上的CPU使用情况) 从图中看出,一共有五个关于CPU的指标.分别如下: 1. User User表示:CPU一共花了多少比例的时 ...
- 小程序 scroll-view 中文字不换行问题
问题描述:在scroll-view 中scroll-x="true"时控制文字超出显示省略号,要求如图: 但实际中会出现如文字不换行或样式错乱的问题. 横向滚动的实现如下: 超过两 ...
- mysql 免安装版后续操作
在安装好mysql后,软件默认的root用户的密码为空. 1.进入mysql 2.创建数据库 3.创建表格 4.插入数据 5.显示数据库.表信息
- CGridCtrl只点击规定行中的按钮才弹出对话框
在头文件中添加: afx_msg void OnClick(NMHDR* pNMHDR, LRESULT* pResult); 添加映射:ON_NOTIFY(NM_CLICK, IDC_CUSTOM1 ...
- PHP页面跳转以及伪登录实例
PHP页面跳转一.header()函数header()函数是PHP中进行页面跳转的一种十分简单的方法.header()函数的主要功能是将HTTP协议标头(header)输出到浏览器. header() ...
- cf749 D. Leaving Auction
#include<bits/stdc++.h> #define lowbit(x) x&(-x) #define LL long long #define N 200005 #de ...