1. PHP 面试题
1. PHP 常用的超全局变量
$GLOBALS
:包含了全部变量的全局数组,变量的名字就是数组的键;$_SERVER
:包含了诸如头信息(header) 、路径(path) 以及脚本位置(scrpit locations) 等等信息的数组。这个数组中的项目由 Web 服务器创建;$_REQUEST
:默认情况下包含了$_GET
、$_POST
和$_COOKIE
的数组;$_GET
:获取 get 请求的参数值,在 HTML 的 form 标签上指定属性method="GET"
;$_POST
:获取 post 请求的参数值,在 HTML 的 form 标签上指定属性method="POST"
;$_FILE
:通过 HTTP POST 方式上传到当前脚本的项目的数组,在 HTML 的 form 标签上指定属性enctype="multipart/form-data"
;$_SESSION
:当前脚本可用的 SESSION 变量的数组;$_COOKIE
:通过 HTTP Cookies 方式传递给当前脚本的变量的数组,通过setcookie()
函数可以发送修改 Cookie 信息;
2. PHP中双引号和单引号的区别
- 双引号解释变量,单引号不解释变量;
- 双引号解释转义字符,单引号不解释转义字符;
- 能使用单引号时尽量使用单引号,单引号效率比双引号高,因为双引号在执行的时候要先遍历一边,判断里面有没有变量,然后再进行操作,而单引号不需要判断。
3. isset() 和 empty() 区别
isset()
用于判断变量是否存在,可以传入多个变量,若其中一个不存在则返回 false;empty()
用于判断变量是否为空为假,只可传入一个变量,如果为空或为假则返回 true;
4. PHP 冒泡排序实例
冒泡排序法的基本思想是:依次比较相邻的两个数,然后根据大小做出排序,直至最后两位数。由于过程中是小数往前放,大树往后放,相当于气泡上升,所以称作冒泡排序。
实际过程中可以根据自己需求反过来用,大树往前,小数往后。
// 冒泡排序
// 每次只对相邻的两位进行对比排序
$arr = [18,11,1,15,2,35,55,12,17,65,23,48,56,22,5];
for($i=0; $i < count($arr), $i++){
for($j=0; $j < count($arr)-i-1; $j++){
// 冒泡排序 相邻的两位进行对比,小的往前换一位,打的换到后面,下轮继续和下一位对比
if($arr[$j] > $arr[$j+1]){
$tmp = $arr[$j];
$arr[$j] = $arr[$j+1];
$arr[$j+1] = $tmp;
}
}
}
// 选择排序
// 每次用一位对该位+1后面的所有数进行对比,直接把小的一位排到前面
$arr = [18,11,1,15,2,35,55,12,17,65,23,48,56,22,5];
for($i = 0; $i < count($arr); $i++){
for($j = $i+1; $j<count($arr); $j++){
if($arr[$i] > $arr[$j]){
$tmp = $arr[$i];
$arr[$i] = $arr[$j];
$arr[$j] = $tmp;
}
}
}
5. PHP中传值和引用的区别,优缺点
传值:将变量对应内存中的值传递给其他变量或函数,如传递给函数,则函数内对值的改变不会影响到函数外的原变量。
传引用:将变量对应内存的内存地址传递给其他变量或函数,如传递函数,则函数内对值的改变会影响到函数外的原变量。
优缺点:传值时,PHP是复制值传递,对于特别大型的字符串和对象来说,性能开销会比较大,而传引用则不需要复制值,只是把对应值的内存地址交过去,相对来说性能开销会小很多。
6. Session 和 Cookie 的区别
- Session
- Session 存储在服务器端,安全性比 Cookie 高;
- 因为 Session 存储在服务器端,每次读取 Session 都会对服务器造成一定的资源消耗;
- Session 默认保存为文件,可以通过 php.ini 中的
session.save_path
来配置; - Session 依赖 Cookie 进行传递,如果 Cookie 被禁用,可以通过其他方式在需要共享 Session 的页面传递 SessionID 来进行 Session 共享。
- 浏览器关闭后,服务器会有 Session 回收机制,自动删除过期 Session 。
- Cookie
- Cookie 存储在客户端,有被篡改的风险,安全性比 Session 低;
- 因为 Cookie 存储在客户端,需要占用服务器资源空间;
- Cookie 可以持久存储
- Cookie 可以被用户主动禁用
7. PHP 中 include 和 require 的区别
- require
- require 是无条件包含,也就是如果一个流程里加入 require ,无论条件是否成立都会先执行 require ,实际上,是用文件的内容替换 require 语句;
- require 引入文件时,如果碰到错误,会报致命错误,并停止运行下面的代码
- require 没有返回值
- include
- include 是在用到的时候才会加载;
- include 引入文件时,如果碰到错误,会报警告错误,并继续运行下面的代码
- include 有返回值
8. PHP 中常用的数组函数
- array_merge() :数组合并函数,把一个或多个数组合并为一个数组
- sort() :以升序对数组排序
- rsort() :以降序对数组排序
- asort() :根据值,以升序对关联数组进行排序
- ksort() :根据键,以升序对关联数组进行排序
- arsort() :根据值,以降序对关联数组进行排序
- krsort() :根据键,以降序对关联数组进行排序
- count() :返回数组元素个数
- array_unique() :去除数组重复的元素,保留第一个出现的,包括键和值
- in_array() :检查数组中是否存在某个值
- list() :将数组中的元素赋值给多个变量
- shuffle() :打乱数组中的元素
- array_keys() :获取数组的键,第二个参数可以获取指定元素的键
- array_diff() :比较两个或多个数组,并返回差集数组,比较以第一个参数的数组为主,结果为去除掉 array1 中对比其他数组重复的元素后,得到的结果集素组
- array_map() :为数组的每个元素应用回调函数
- array_pop() :弹出数组中的最后一个元素,并返回被弹出的元素内容
- array_push() :将一个或多个单元压入数组的末尾,并返回处理后的数组元素总数
- array_shift() :移除数组中的第一个元素,并返回被删除元素的值。
- array_rand() :从数组中随机去除一个或多个随机键
- array_search() :从数组中搜索给定的值,如果成功则返回第一个匹配的键名
- array_key_exists() :检查数组里是否有指定的键名。
- array_chunk() :将一个数组分割成多个
- array_filter() :使用回调函数过滤数组的元素,如果没有提供回调函数,将删除数组中的所有空元素。
- array_flip() :交换数组中的键和值,如果同一个值出现多次,则保留最后出现的
9. Get 个 Post 的区别
- Get
- Get 是显示的,数据可以从 URL 上看到,传输的数据量小,安全性较低
- Post
- Post 是隐式传递的,将数据打包到了请求中,可以传输大量的数据,安全性较高
2. MySQL 面试题
1. MySQL 中 char 和 varchar 的区别
varchar
类型是可变长度;char
是固定长度;
查找时,char
的效率要高于 varchar
。因为 varchar
是非固定长度,必须先查找长度,然后在进行数据提取。
2. 什么是索引
索引时一种数据结构,能够帮助我们快速的检索数据库中的数据
3. 索引的优点和缺点
- 优点:
- 可以极大的提高数据的查询性能
- 可以提高数据分组与排序的性能
- 缺点:
- 索引本身需要占用一定的存储空间,如果大量的使用索引,则索引文件会占用大量的磁盘空间;
- 索引的创建于维护需要耗费一定的时间,随着数据量的不断增长,耗费的时间会越来越长;
- 在执行 增 、删 、改 的操作时,MySQL 内部会对索引进行维护,也会消耗一定的维护时间;
4. 索引的创建原则
- 尽量使用小的数据类型的字段来创建索引;
- 尽量使用简单的数据类型的字段来创建索引;
- 尽量不要在 NULL 值字段上创建索引
5. 索引的使用场景
适合创建索引的场景
- 数据表中的数据达到一定量级时,应为数据表适当添加索引
- 与其它表进行关联的字段,并且经常进行关联查询,应当为连接字段添加索引
- 作为 where 子句的条件判断字段,并且经常用来进行相等的比较操作的字段,应当添加索引
- 作为 order by 语句的字段,并且经常用来执行排序操作的字段,应当添加索引
- 作为搜索一定范围内的字段,并且经常用来执行查询操作,应当添加索引
不适合创建索引的场景
- 在查询数据时很少使用的列和字段不适合添加索引
- 字段数据却别性较小的字段,如性别字段,不适合添加索引
- 大数据类型的字段,如 TEXT 、 BLOB 、BIT 等数据类型的字段,不适合添加索引
- 当某个表的数据需要非常频繁的修改,不适合创建索引
- 查询时,不作为 where 子句 、order by 子句 group by 子句 的字段,不适合添加索引
6. MySQL 的索引有哪些类型
- 主键索引
- 唯一索引
- 普通索引
- 组合索引
- 全文索引
- 空间索引
7. MySQL 有哪些索引方法
B+ Tree 索引
: 在B Tree
索引的基础上进行优化的结果,MySQL 中大部分存储引擎支持,MySQL 默认索引;Hash 索引
:比较适合存储 Key-Value 型数据。查询 Key-Value 型数据时,会根据 Key 快速获取数据。但是 Hash 索引有一个弊端,即不适合根据某个数据范围来查询数据,并且无法利用索引完成排序。而且不支持多列联合索引的最左匹配原则;R-Tree
:空间索引,对于地理空间类型的数据来说,通常会使用 R-Tree 索引;Full-Text
:全文索引。MySQL 5.6 之前只支持 MyISAM 存储引擎,5.6开始,InnoDB 存储引擎开始支持全文索引;
8. B+Tree 和 Hash 索引的区别
- Hash 索引不适合进行范围查询,更适合等值查询
- Hash 索引无法利用索引来完成排序
- Hash 索引不支持多列联合索引的最左匹配原则
- 在有大量重复键值的情况下,Hash 索引效率低,会存在 Hash 碰撞问题
9. MySQL 的优化有哪些方法
- 数据表优化方面:
- 在创建数据表时,给表定义一个自增非空的主键,因为如果不创建的话,InnDB 会选择一个非空且唯一的列来代替,如果没有这样的列,InnDB就会隐式定义一个主键;
- 选择合适的数据类型,例如可以使用 int 类型就不要用字符串类型,这样可以减少内存空间和磁盘空间的占用,也可以使查询和排序等操作效率更高。
- 尽量将字段设置为 NOT NULL ,如果字段允许为 NULL ,会使的索引更复杂,甚至导致索引失效
- 对于字段较多且部分字段查询频繁的表,可以将其中使用较少的字段进行分表处理,以此来提高表的查询效率
- 对于经常需要联合查询的多个表,建立中间表,将需要经常联合查询的数据放入中间表中,将原来的联合查询改为对中间表的查询,以此来提高查询效率
- 增加合理的冗余字段,以减少不必要的联合查询,以此来调高查询效率
- 查询优化方面:
- 开启 慢查询日志 ,通过日志定位查询时间过长的慢查询,然后通过 explain 来进一步分析
- 使用 explain 语句来查看语句的执行计划,看查询语句是否正确的使用了索引,是否进行了全表扫描等情况,并以此来对查询语句和索引进行优化调整;
- 尽量使用 JOIN 连表查询来代替嵌套查询(子查询),并且确保联合字段上有索引。子查询会创建一个临时表,在查询完成后还需要将临时表进行销毁;
- 查询时,如果要查找的字段上有索引,最好直接写明查询字段,例如
select xx, xx from table
,而不是直接使用select *
进行全查询,不然会导致 MySQL 回表查询,减慢查询效率; - 在 where 条件中,尤其是设置了索引的列条件上,不要使用运算和函数,这会导致 MySQL 在执行语句时,使用函数或运算先对该列数据进行运算后在执行查询导致索引失效,也降低了运行效率
- 在 where 条件使用频繁的字段上添加索引,并且多个条件的话要注意是否符合索引的顺序,防止因为条件顺序不正确而导致索引不生效(索引的最左前缀原则);
- 在使用 LIKE 关键字进行查询时,将“%”放在后面,例如
like xx%
; - 在 where 条件中,如果使用了 OR 关键字,则必须保证 OR 前后条件中列都在索引上,并且是独立索引,查询才会使用索引,可以使用
union(复合查询)
关键字来替换 OR - 在 where 条件中,
- 索引优化方面:
- 表数据较少的时候,不建议添加索引,会导致在数据插入和更新时效率变低;
- 一个数据表中的索引不要太多,添加新索引的时候可以考虑是否能添加到已有的组合索引中;
- 表中数据新增和更新频繁的数据表,而查询较少的表不适合添加索引
- 创建索引时,应该选择值差异性较大的列
- 在经常需要作为查询条件和排序条件的列上添加索引;
- 创建组合索引的时候,需要注意最左匹配原则,以确保索引可以被正常使用
- 数据库优化方面:
- 读写分离
- 主从复制
- 查询缓存
- 外部缓存(redis)
10. 索引失效的情况
- 如果 where 条件中有 or 会导致索引失效,or 需要 左右两边的列都有独立索引
- 使用组合索引时,没有按照最左匹配原则写查询条件
- 如果列类型是字符串,则在查询条件中,值需要用引号包含起来,避免隐式数据类型转换导致不走索引
- 如果 MySQL 的查询优化器认为全表扫描比使用索引快,则不走索引
- 查询到的数量是表的大部分,也会导致不走索引
11. MySQL 三大范式
- 第一范式
- 要求数据表的每个字段的值都必须具备原子性,确保数据表中的每个字段的值都是不可再分解的原子值
- 第二范式
- 第二范式建立在第一范式的基础上,保证一张表只表述一件事,并且所有非关键字段都完全依赖于同一字段,不能产生部分依赖(涉及到数据的分表操作)
- 第三范式
- 在第二范式的基础上,保证每列都和主键直接相关,表中的每列字段应该直接对应主键并且不依赖其他中间字段
12. MySQL 常用存储引擎
- InnoDB
- 特点
- 支持事务
- 锁级别为行锁,比 MyISAM 村吃引擎支持更高的并发
- 支持外键操作
- 在索引存储上,索引和数据存储在同一个文件中,默认按照 B+Tree 组织索引的结构,同时主键索引的叶子节点存储完整的数据记录,非主键索引的叶子节点存储主键的值
- MySQL 5.6 后默认使用 InnoDB 存储引擎,并且支持全文索引
- 更够通过二进制日志恢复数据
- 特点
- MyISAM
- 特点
- 不支持事务
- 锁级别为表锁,在要求高并发的场景下不太适合
- 不支持外键
- 在索引存储上,索引文件和数据文件分离
- 支持全文索引
- 如果数据文件损坏,难以恢复数据
- 特点
13. MySQL 的锁机制
- 表锁
- 开销小,加锁快;
- 不会出现死锁;
- 锁定粒度大,发生锁冲突的概率最高。并发度最低
- 行锁
- 开销大,加锁慢;
- 会出现死锁;
- 锁定粒度小,发生锁冲突的概率最低,并发度最高
- 页面锁
- 开销和加锁事件介于表锁和行锁之间;
- 会出现死锁;
- 锁定粒度介于表锁和行锁之间,并发度一般
3. Redis 缓存 面试题
1. redis 支持哪些数据类型
- String 字符串
- redis 的基本类型,一个 key 对应一个字符串 value
- Hash 哈希
- 是一个键值(key=>value)对集合
- List 列表
- 列表是简单的字符串列表,按照插入顺序排序
- set 集合
- 集合是 String 类型的元素无序集合
- zset 有序集合
- 有序集合是 String 类型的元素的元素集合,且不允许重复,不同的是每个元素都会被关联一个 double 类型的分数,redis 通过分数来为集合中的成员进行从小到大的排序