我叫李云锋,由于最近想跳槽,参加了几场面试后发现自己的不足之处,所以将自己面试遇到的问题一一记录下来,毕竟好记性不如烂笔头嘛
mysql 基础知识 及 php常见的面试题
MySQL 索引
MySQL索引的建立对于MySQL的高效运行是很重要的,索引可以大大提高MySQL的检索速度。
打个比方,如果合理的设计且使用索引的MySQL是一辆兰博基尼的话,那么没有设计和使用索引的MySQL就是一个人力三轮车。
拿汉语字典的目录页(索引)打比方,我们可以按拼音、笔画、偏旁部首等排序的目录(索引)快速查找到需要的字。
索引分单列索引和组合索引。单列索引,即一个索引只包含单个列,一个表可以有多个单列索引,但这不是组合索引。组合索引,即一个索引包含多个列。
创建索引时,你需要确保该索引是应用在 SQL 查询语句的条件(一般作为 WHERE 子句的条件)。
实际上,索引也是一张表,该表保存了主键与索引字段,并指向实体表的记录。
虽然索引大大提高了查询速度,同时却会降低更新表的速度,如对表进行INSERT、UPDATE和DELETE。因为更新表时,MySQL不仅要保存数据,还要保存一下索引文件。
索引可以加快表的查询速度,通常我们将经常用来查询的一个或者几个字段设置为索引,但不宜过多,3个内最好
索引的优缺点
1)优点 A.加快数据检索速度和表与表之间的连接; B.可以显著减少查询中分组和排序的时间(使用分组和排序子句进行数据检索时)。
2)缺点 A.占物理空间 (会占用磁盘空间的索引文件)。 B.需要动态维护,降低数据维护速度(update、delete、insert)。
- 普通索引:最基本的索引,它没有任何限制
- 唯一索引:索引列的值必须唯一,但允许有空值。如果是组合索引,则列值的组合必须唯一
MySQL 事务
事务是必须满足4个条件(ACID):原子性(Atomicity,或称不可分割性)、一致性(Consistency)、隔离性(Isolation,又称独立性)、持久性(Durability)。
原子性:一个事务(transaction)中的所有操作,要么全部完成,要么全部不完成,不会结束在中间某个环节。事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。
一致性:在事务开始之前和事务结束以后,数据库的完整性没有被破坏。这表示写入的资料必须完全符合所有的预设规则,这包含资料的精确度、串联性以及后续数据库可以自发性地完成预定的工作。
隔离性:数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。事务隔离分为不同级别,包括读未提交(Read uncommitted)、读提交(read committed)、可重复读(repeatable read)和串行化(Serializable)。
持久性:事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。
mysql四种搜索引擎
InnoDB
InnoDB是事务型数据库的首选引擎,支持事务安全表(ACID),支持行锁定和外键
InnoDB是默认的MySQL引擎。
InnoDB 表是基于聚簇索引建立的。InnoDB 的索引结构和 MySQL 的其他存储引擎有很大不同,聚簇索引对主键查询有很高的性能。不过它的二级索引(secondary index,非主键索引)中必须包含主键列,所以如果主键很大的话,其他的所有索引都会很大。因此,若表上的索引较多的话,主键应当尽可能的小。
InnoDB不创建目录,使用InnoDB时,MySQL将在MySQL数据目录下创建一个名为ibdata1的10MB大小的自动扩展数据文件,以及两个名为ib_logfile0和ib_logfile1的5MB大小的日志文件。
InnoDB主要特性有:
InnoDB给MySQL提供了具有提交、回滚和崩溃恢复能力的事物安全(ACID兼容)存储引擎。InnoDB锁定在行级并且也在SELECT语句中提供一个类似Oracle的非锁定读。这些功能增加了多用户部署和性能。在SQL查询中,可以自由地将InnoDB类型
的表和其他MySQL的表类型混合起来,甚至在同一个查询中也可以混合
InnoDB是为处理巨大数据量的最大性能设计。它的CPU效率可能是任何其他基于磁盘的关系型数据库引擎锁不能匹敌的
InnoDB存储引擎完全与MySQL服务器整合,InnoDB存储引擎为在主内存中缓存数据和索引而维持它自己的缓冲池。InnoDB将它的表和索引在一个逻辑表空间中,表空间可以包含数个文件(或原始磁盘文件)。这与MyISAM表不同,比如在MyISAM表中每个表被存放在分离的文件中。InnoDB表可以是任何尺寸,即使在文件尺寸被限制为2GB的操作系统上
InnoDB支持外键完整性约束,存储表中的数据时,每张表的存储都按主键顺序存放,如果没有显示在表定义时指定主键, InnoDB会为每一行生成一个6字节的ROWID,并以此作为主键
InnoDB被用在众多需要高性能的大型数据库站点上
如果要提供提交、回滚、崩溃恢复能力的事物安全(ACID兼容)能力,并要求实现并发控制,InnoDB是一个好的选择。
MyISAM
MyISAM基于ISAM存储引擎,并对其进行扩展。它是在Web、数据仓储和其他应用环境下最常使用的存储引擎之一。MyISAM拥有较高的插入、查询速度,但不支持事务。
MyISAM表格可以被压缩,而且它们支持全文搜索。不支持事务,而且也不支持外键。如果事物回滚将造成不完全回滚,不具有原子性。在进行updata时进行表锁,并发量相对较小。如果执行大量的SELECT,MyISAM是更好的选择。
MyISAM的索引和数据是分开的,并且索引是有压缩的,内存使用率就对应提高了不少。能加载更多索引,而Innodb是索引和数据是紧密捆绑的,没有使用压缩从而会造成Innodb比MyISAM体积庞大。
MyISAM缓存在内存的是索引,不是数据。而InnoDB缓存在内存的是数据,相对来说,服务器内存越大,InnoDB发挥的优势越大。
MyISAM主要特性有:
大文件(达到63位文件长度)在支持大文件的文件系统和操作系统上被支持
当把删除和更新及插入操作混合使用的时候,动态尺寸的行产生更少碎片。这要通过合并相邻被删除的块,以及若下一个块被删除,就扩展到下一块自动完成
每个MyISAM表最大索引数是64,这可以通过重新编译来改变。每个索引最大的列数是16
最大的键长度是1000字节,这也可以通过编译来改变,对于键长度超过250字节的情况,一个超过1024字节的键将被用上
BLOB和TEXT列可以被索引
NULL被允许在索引的列中,这个值占每个键的0~1个字节
所有数字键值以高字节优先被存储以允许一个更高的索引压缩
每个MyISAM类型的表都有一个AUTO_INCREMENT的内部列,当INSERT和UPDATE操作的时候该列被更新,同时 AUTO_INCREMENT列将被刷新。所以说,MyISAM类型表的AUTO_INCREMENT列更新比InnoDB类型的AUTO_INCREMENT更快
可以把数据文件和索引文件放在不同目录
每个字符列可以有不同的字符集
有VARCHAR的表可以固定或动态记录长度
VARCHAR和CHAR列可以多达64KB
使用MyISAM引擎创建数据库,将产生3个文件。文件的名字以表名字开始,扩展名之处文件类型:frm文件存储表定义、数据文件的扩展名为.MYD(MYData)、索引文件的扩展名时.MYI(MYIndex)
如果数据表主要用来插入和查询记录,则MyISAM引擎能提供较高的处理效率。并且,如果你的应用程序对查询性能要求较高,就要使用MYISAM了。MYISAM索引和数据是分开的,而且其索引是压缩的,可以更好地利用内存。所以它的查询性能明显优于INNODB。压缩后的索引也能节约一些磁盘空间。MYISAM拥有全文索引的功能,这可以极大地优化LIKE查询的效率。
MEMORY
使用MySQL Memory存储引擎的出发点是速度。为得到最快的响应时间,采用的逻辑存储介质是系统内存。虽然在内存中存储表数据确实会提供很高的性能,但当mysqld守护进程崩溃时,所有的Memory数据都会丢失。获得速度的同时也带来了一些缺陷。它要求存储在Memory数据表里的数据使用的是长度不变的格式,这意味着不能使用BLOB和TEXT这样的长度可变的数据类型,VARCHAR是一种长度可变的类型,但因为它在MySQL内部当做长度固定不变的CHAR类型,所以可以使用
MEMORY主要特性有: MEMORY表的每个表可以有多达32个索引,每个索引16列,以及500字节的最大键长度
MEMORY存储引擎执行HASH和BTREE缩影 可以在一个MEMORY表中有非唯一键值 MEMORY表使用一个固定的记录长度格式
MEMORY不支持BLOB或TEXT列 MEMORY支持AUTO_INCREMENT列和对可包含NULL值的列的索引
MEMORY表在所由客户端之间共享(就像其他任何非TEMPORARY表)
MEMORY表内存被存储在内存中,内存是MEMORY表和服务器在查询处理时的空闲中,创建的内部表共享
当不再需要MEMORY表的内容时,要释放被MEMORY表使用的内存,应该执行DELETE FROM或TRUNCATE
TABLE,或者删除整个表(使用DROP TABLE)
一般在以下几种情况下使用Memory存储引擎:
1)目标数据较小,而且被非常频繁地访问。在内存中存放数据,所以会造成内存的使用,可以通过参数max_heap_table_size控制Memory表的大小,设置此参数,就可以限制Memory表的最大大小。
2)如果数据是临时的,而且要求必须立即可用,那么就可以存放在内存表中。
3)存储在Memory表中的数据如果突然丢失,不会对应用服务产生实质的负面影响。
4)如果只是临时存放数据,数据量不大,并且不需要较高的数据安全性,可以选择将数据保存在内存中的Memory引擎,MySQL中使用该引擎作为临时表,存放查询的中间结果。
MERGE
MERGE存储引擎是一组MyISAM表的组合,这些MyISAM表结构必须完全相同,尽管其使用不如其它引擎突出,但是在某些情况下非常有用。说白了,Merge表就是几个相同MyISAM表的聚合器;Merge表中并没有数据,对Merge类型的表可以进行查询、更新、删除操作,这些操作实际上是对内部的MyISAM表进行操作。
主要应用于服务器日志这种信息,一般常用的存储策略是将数据分成很多表,每个名称与特定的时间端相关。例如:可以用12个相同的表来存储服务器日志数据,每个表用对应各个月份的名字来命名。当有必要基于所有12个日志表的数据来生成报表,这意味着需要编写并更新多表查询,以反映这些表中的信息。与其编写这些可能出现错误的查询,不如将这些表合并起来使用一条查询,之后再删除Merge表,而不影响原来的数据,删除Merge表只是删除Merge表的定义,对内部的表没有任何影响。
如果只有INSERT和SELECT操作,可以选择Archive,Archive支持高并发的插入操作,但是本身不是事务安全的。Archive非常适合存储归档数据,如记录日志信息可以使用Archive。
对日志的一些综合操作,通常使用的是MERGE存储引擎。
我目前遇到的面试问题
数据库相关
问:char 和 varchar 那个查询效率比较高?
答: CHAR 的效率比 VARCHAR 的效率稍高.
char 固定长度,所以在处理速度上要比varchar快速很多,但是相对费存储空间 . 所以对存储不大,但在速度上有要求的可以使用char类型
问:什么情况下会导致索引失效?
答:
1.没有遵循最佳左前缀原则
2.对索引进行了数值运算,类型转换等操作
3.尽量不要使用or,否则or左侧索引失效
4.like查询时,不要以%开头,否则索引失效
5.复合索引不能使用不等于(!= <>)或is null (is not null),否则自身以及右侧所有全部失效。
复合索引中如果有>,则自身和右侧索引全部失效
问:现在拥有以下数据: (表名 sales)
需要得到以下结果
请写出原生SQL语句:
答:
SELECT
year,
SUM( IF(quarter=‘1’, quantity, 0) ) AS m1,
SUM( IF(quarter=‘2’, quantity, 0) ) AS m2,
SUM( IF(quarter=‘3’, quantity, 0) ) AS m3,
SUM( IF(quarter=‘4’, quantity, 0) ) AS m4
FROM
sales
GROUP BY
year
知识点
:
SUM () 函数: 函数返回数值列的总数
IF() 函数: 判断值是否符合条件 ,这里 当条件为 true 等于 quantity 否则 等于 0
SUM(IF()) 此处 满足条件 和 加上 quantity 不满足条件 和 加上 0
group by 根据某个字段 进行分组
运算相关
问:
$i=11;printf("%d\n",printf("%d",printf("%d",$i)));
输出结果是多少?
答:1121
分析
:首先 printf() 函数不仅会输出 一个值 而且还有一个返回值供下一级使用了解这个原理之后我们看第一级: printf("%d",$i) 得到的值是 11 ,返回值是 字符长度 2,将2带入下一级运算
在分析第二层 :我们参加运算的值就是 2 ,输出结果 2 并且返回值 为 1;
第三层参加运算的值就死 1 ,输出结果 1,并且返回值 为 1
最后得到的结果 就是分别输出的结果 11 2 1
问:请使用php写一段经典的冒泡排序
我只是知道冒泡排序原理,但是在我的实际项目中,我是真没遇到过需要这种排序来处理的业务,还是经验太少惹的祸,只要背下来就行,我甚至怀疑 只要一个木工背下来,面试官是否都会觉得他会写代码
但是不得不说,你要是会写,并且能背下来那无疑是最好最优秀的,感谢面试官提的建议
答:
效果如图
分析
:冒泡排序是将两个相邻的树进行比较,然后进行位置的互换.
/**
* 冒泡排序
* @param $array
* @return array
*/
function mp($array){
$newArray = $array;
for($i=0;$i<count($array);$i++){
for ($k=$i+1;$k<count($array);$k++){
if($array[$i] > $newArray[$k]){
//设置新数组的排序规则
$newArray[$i] = $array[$k];
$newArray[$k] = $array[$i];
//设置老数组的排序规则
$array[$i] = $newArray[$i];
$array[$k] = $newArray[$k];
}
}
}
return $newArray;
}
既然讲了冒泡排序,那就在拓展一下快速排序
分析
:快速排序是定义一个临界值,将数组分成两部分,然后递归进行排序
效果如下:
/**
* 快速排序
* @param $array
*/
function ks($array){
$count = count($array);
if($count <= 1){
return $array;
}
//定义一个中间值,一般是取数组的第一条数据的值
$middle = $array[0];
$left_array = [];
$right_array = [];
for($i=1;$i<$count;$i++){
if($array[$i] < $middle){
$left_array[] = $array[$i];
}else{
$right_array[] = $array[$i];
}
}
$left_array = $this->ks($left_array);
$right_array = $this->ks($right_array);
$newArray = array_merge($left_array,array($middle),$right_array);
return $newArray;
}
PHP相关
问:写一个php函数,验证邮箱格式是否正确
答:
$email = “test@qq.com”;if (filter_var($email, FILTER_VALIDATE_EMAIL))
{ echo ‘"’ . $email . ‘" 是有效的。’;}else{ echo ‘"’ . $email . ‘" 是无效的。’;}
分析
这里主要是想考查的知识点在于 filter_var(), 使用特定的过滤器过滤一个变量
FILTER_VALIDATE_EMAIL 过滤器把值作为 e-mail 地址来验证.
这个全靠自己背,在我的印象中几个主流框架中都有封装的验证类,所以原生的验证方法我还真没记过