MySQL 分区分表

1. MySQL 分区 && 分库分表

1. 分区表

分区表是一个独立的逻辑表,但是底层 MySQL 将其分成了多个物理子表,每一个分区表都会使用一个独立的表文件

客户端和 PHP 无感知,代码不需要修改,对业务逻辑没有任何影响

1. 工作原理

创建表时使用 partition by 子句定义每个分区存放的数据,执行查询时,优化器会根据分区定义过滤那些没有所需数据的分区,这样查询只需要查询所需数据所在的分区即可,大大提高查询效率

分区的主要目的是将数据按照一个较粗的粒度分在不同的表中,这样可以将相关的数据存放在一起,而且如果想一次性删除整个分区的数据也很方便

2. 适用场景

  1. 表非常大,无法全部存在内存,或者只在表的最后有热点数据,其他都是历史数据
  2. 分区表的数据更易维护,可以对独立的分区进行独立的操作
  3. 分区表的数据可以分布在不同的机器上,从而高效使用资源
  4. 可以使用分区表来避免某些特殊的瓶颈
  5. 可以备份和恢复独立的分区

3. 限制

  1. 一个表最多只能有 1024 个分区
  2. 5.1 版本,分区表表达式必须是整数,5.5 之后可以使用列分区
  3. 分区字段如果有主键和唯一索引列,那么主键列和唯一列都必须包含进来
  4. 分区表中无法使用外键约束
  5. 需要对现有表的结构进行修改
  6. 所有分区都必须使用相同的存储引擎
  7. 可以使用的函数和表达式会有一些限制
  8. 部分存储引擎不支持分区(InnoDB 和 MyISAM 都支持)
  9. 对于 MyISAM 的分区表,不能使用 load index into cache,即不能将索引缓存
  10. 对于 MyISAM 的分区表,使用分区表时需要打开更多的文件描述符,降低查询效率。

2. 分库分表

1. 工作原理

通过一些 hash 算法或者工具实现将一张数据表垂直或者水平进行物理切分。

2. 适用场景

  1. 单表记录条数达到百万或者千万级别时
  2. 解决表锁的问题

3. 分表方式

1. 水平分割

表很大,分割后可以降低在查询时需要读的数据和索引的页数,同时也降低了索引的层数,提高查询速度

1. 使用场景
  1. 表中的数据本身就有独立性,例如表中分别记录各个地区的数据或者不同时期的数据,特别是有些数据常用,有些不常用,比如切分历史数据和活跃数据
  2. 需要把数据存放到多个介质上
2. 缺点
  1. 给应用增加复杂度,通常查询时需要多个表名,查询所有数据都需要 union 操作;
  2. 在许多数据库应用中,这种复杂性会超过带来的优点,查询时会增加读一个索引层的磁盘次数;
2. 垂直分表

把主键和一些列放在一张表,然后把主键和另外的列放在另一张表中

1. 使用场景
  1. 表中某些列常用,而另外一些列不常用
  2. 可以使数据行变小,一个数据页能存储更多数据,查询时减少 I/O 次数
2. 缺点

管理冗余列,查询所有数据都需要 join 操作

3. 分库分表缺点

  1. 有些分表的策略基于应用层的逻辑算法,一旦逻辑算法改变,整个分表逻辑都会改变,扩展性较差
  2. 对于应用层来说,逻辑算法无疑会增加开发成本

2. MySQL 复制原理及负载均衡

1. MySQL 主从复制工作原理

  1. 在主库上把数据更改记录到二进制文件,即所有的写操作都记录到 binlog
  2. 从库将主库的日志复制到自己的中继日志
  3. 从库读取中继日志中的事件,将其重放到从库数据中,即执行了日志中的 SQL 语句

2. 解决了哪些问题

  1. 数据分布:随意停止或开始复制,并在不同地理位置分布数据备份
  2. 负载均衡:降低单个服务器的压力
  3. 高可用和故障切换:帮助应用程序避免单点失败
  4. 升级测试:可以使用更高版本的 MySQL 作为从库

MySQL 知识整理

mysql 关联更新

update 后面跟的表名是即将要使用到的表

1
2
update A,B set A.c1=b.c1, A.c2=b.c2 where A.id=B.id;
update A inner join B on A.id=b.id set A.c1=B.c1, A.c2=B.c2 where ...;

6 种关联查询

  • 交叉连接 cross join: 笛卡尔积
    • select * from A, B, (,C)
    • select * from A cross join B (cross join C)
    • 没有任何关联条件,结果是笛卡尔积,结果集会很大,没有意义,很少使用
  • 内连接 inner join
    • select * from A,B where A.id=B.id
    • select * from A (inner) join B on A.id=B.id
    • 多表中同时符合某种条件的数据记录的集合
    • 等值连接(on A.id=B.id)、不等值连接(on A.id>B.id)、自连接(select * from A t1 inner join A t2 on t1.id=t2.pid
    • 可以缩写为 join
  • 外连接 left join/right join
    • 左外连接: left outer join,以左表为主,先查询出左表,按照 on 后的关联条件匹配右表,没有匹配到的用 null 填充,可以简写为 left join
    • 右外连接 right outer join
  • 联合查询 union, union all
    • select * from A union select * from B union ...
    • 多条 select 语句的结果集进行累加,union 前的结果为基准
    • 列数要相等,相同的记录行会合并
    • 如果使用 union all,则不会合并重复的记录行
    • union 效率高于 union all
  • 全连接 full join
    • 只是一个概念,mysql 不支持
    • 可以使用 left join,union,right join 联合实现,select * from A left join B on A.id=B.id union select * from A right join B on A.id=B.id

MySQL 查询优化

1. 查找分享查询速度慢的原因

记录慢查询日志

分析查询日志,不建议直接打开慢查询日志进行分析,可以使用 pt-query-digest 工具进行分析

使用 show profile

set profiling=1; 开启,服务器上执行的所有语句都会监测消耗的时间,存到临时表中

1
2
show profiles;
show profile for query 临时表中单条记录ID;
使用 show status

show status 会返回一些计数器,show global status 查看服务器级别的所有计数

有时根据这些计数,可以猜测出哪些操作代价较高或者消耗时间多

使用 show processlist

观察是否有大量进程处于不正常的状态或者特征

使用 explain

分析单条 SQL 语句
explain select * from A;

2. 优化查询过程中的数据访问

  • 访问数据太多导致查询性能下降
  • 确定应用程序是否在检索大量超过需要的数据,可能是太多行或列
  • 确认 mysql 服务器是否在分析大量不必要的数据行

方案

  • 查询不需要的记录,使用 limit
  • 多表关联只返回所需要的列
  • select * 不要用
  • 重复查询相同的数据,可以缓存数据,下次直接读取缓存
  • 使用索引覆盖扫描,把所有用的列都放到索引中,这样存储引擎不需要回表获取对应行就可以返回结果
  • 改变数据库和表的结构,修改数据表范式(冗余字段降低范式,用空间换取时间)
  • 重写 SQL 语句,让优化器可以以更优的方式执行查询

3. 优化长难的查询语句

应当使用一个复杂查询还是多个简单查询?

MySQL 内部每秒能扫描内存中上百万行的数据,相比之下,响应数据给客户端就要慢得多

大多数情况下,使用尽可能少的查询是好的,但是有时将一个大的查询分解为多个小的查询也是很有必要的,这样可以方便地做缓存

切分查询

将一个大的查询分为多个小的相同的查询

一次性删除 1000 万的数据比一次删除一万,暂停一会的方案更加损耗服务器开销。

分解关联查询
  • 可以将一条关联语句分解成多条 SQL 来执行
  • 让缓存效率更高
  • 执行单个查询可以减少锁的竞争
  • 在应用层做关联可以更容易对数据库进行拆分

4. 优化特定类型的查询语句

优化 count(*)
  • count() 中的 会忽略所有的列,直接统计所有列数,速度更快,因此不要使用 count(列名)
  • MyISAM 中,没有任何 where 条件的 count(*) 非常快
  • 当有 where 条件,MyISAM 的 count 统计也不一定比其他表引擎快
  • 或者增加一张汇总表
  • 缓存汇总信息
优化关联查询
  • 确认 on 或者 using 子句的列上有索引,如果没有要添加,否则会导致全表扫描
  • 确保 group by 和 order by 中只有一个表中的列,这样 MySQL 才有可能使用索
优化子查询

尽可能使用关联查询来替代

优化 group by 和 distinct
  • 均可使用索引来优化,是最有效的优化方法
  • 关联查询中,使用标识列进行分组效率更高,即 group by 后面跟的列名是主键列或 auto_increment 列
  • 如果不需要排序,进行 group by 时使用 order by null,MySQL 就不会再进行文件排序
  • with rollup 超级聚合,尽量挪到应用程序处理,而不应该在数据库中处理
优化 limit 分页
  • limit 偏移量大的时候,查询效率较低
  • 可以记录上次查询的最大ID,下次查询时直接根据该ID来查询
优化 union 查询

使用 union all 替代 union 查询,效率更高,数据去重放到应用层面

1. echo(),print(),print_r()的区别?

  • echo 和 print 不是一个函数,是一个语言结构;
  • print(string $arg) 只有一个参数;
  • echo arg1,arg2 可以输出多个参数,返回 void
  • echoprint 只能打印出string,不能打印出结构;
  • print_r 能打印出结构。比如:
    1
    2
    3
    4
    5
    6
    7
    $arr = array("key"=>"value");
    print_r($arr);
    Array
    (
    [key] => value
    )

2. 语句include和require的区别是什么?

在失败的时候:
include 产生一个 warning ,而 require 直接产生错误中断;

require 在运行前载入;

include 在运行时载入;

require_once 和 include_once 可以避免重复包含同一文件。

3. php中传值与传引用有啥区别?

&表示传引用;

函数中参数传引用会将参数进行改变;

一般在输出参数有多个的时候可以考虑使用引用。

4. 下面哪项没有将john添加到users数组中?

1
2
3
4
(a) $users[] = 'john';
(b) array_add($users,'john');
(c) array_push($users,'john');
(d) $users ||= 'john';

答案为bd,php 里面无 array_add 函数,d项为语法错误的表达。

5. HTTP协议中几个状态码的含义。

  • 200 : 请求成功,请求的数据随之返回 OK。
  • 301 : 永久性重定向 Moved permanently。
  • 302 : 暂时行重定向 Moved Temporarily
  • 401 : 当前请求需要用户验证 Unauthorized。
  • 403 : 服务器拒绝执行请求,即没有权限 Forbidden。
  • 404 : 请求失败,请求的数据在服务器上未发现 Not found。
  • 500 : 服务器错误。一般服务器端程序执行错误 Internal server error。
  • 503 : 服务器临时维护或过载。这个状态时临时性的 Service unavailable。
  • 504:超时,Gateway timeout

6. 写出一些php魔术方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
__construct() 实例化类时自动调用。
__destruct() 类对象使用结束时自动调用。
__set() 在给未定义的属性赋值的时候调用。
__get() 调用未定义的属性时候调用。
__isset() 使用isset()或empty()函数时候会调用。
__unset() 使用unset()时候会调用。
__sleep() 使用serialize序列化时候调用。
__wakeup() 使用unserialize反序列化的时候调用。
__call() 调用一个不存在的方法的时候调用。
__callStatic()调用一个不存在的静态方法是调用。
__toString() 把对象转换成字符串的时候会调用。比如 echo。
__invoke() 当尝试把对象当方法调用时调用。
__set_state() 当使用var_export()函数时候调用。接受一个数组参数。
__clone() 当使用clone复制一个对象时候调用。

7. MySQL存储引擎 MyISAM 和 InnoDB 的区别。

1
2
3
4
5
6
7
8
a. MyISAM类型不支持事务处理等高级处理,而InnoDB类型支持.
b. MyISAM类型的表强调的是性能,其执行速度比InnoDB类型更快.
c. InnoDB不支持FULLTEXT类型的索引.
d. InnoDB中不保存表的具体行数,也就是说,执行select count(*) from table时,InnoDB要扫描一遍整个表来计算有多少行,但是MyISAM只要简单的读出保存好的行数即可.
e. 对于AUTO_INCREMENT类型的字段,InnoDB中必须包含只有该字段的索引,但是在MyISAM表中,可以和其他字段一起建立联合索引。
f. DELETE FROM table时,InnoDB不会重新建立表,而是一行一行的删除。
g. LOAD TABLE FROM MASTER操作对InnoDB是不起作用的,解决方法是首先把InnoDB表改成MyISAM表,导入数据后再改成InnoDB表,但是对于使用的额外的InnoDB特性(例如外键)的表不适用.
h. MyISAM支持表锁,InnoDB支持行锁。

8. 说出一些MySQL优化方法?

1
2
3
4
5
6
7
a. 设计良好的数据库结构,允许部分数据冗余,尽量避免join查询,提高效率。
b. 选择合适的表字段数据类型和存储引擎,适当的添加索引。
c. mysql库主从读写分离。
d. 找规律分表,减少单表中的数据量提高查询速度。
e. 添加缓存机制,比如memcached,apc等。
f. 不经常改动的页面,生成静态页面。
g. 书写高效率的SQL。比如 SELECT * FROM TABEL 改为 SELECT field_1, field_2, field_3 FROM TABLE.

9. 下面$a的结果是:

1
2
3
4
5
6
7
8
9
10
<?php
$a = in_array('01', array('1')) == var_dump('01' == 1);
?>
A true
B false
var_dump('01' == 1) // return NULL
in_array('01', array('1')) // return true
$a // false

答案为B

10. 说下php中empty()和isset()的区别。

1
2
3
4
5
6
7
8
9
10
11
isset 用于检测变量是否被设置,使用 isset() 测试一个被设置成 NULL 的变量,将返回 FALSE 。
empty 如果 var 是非空或非零的值,则 empty() 返回 FALSE。换句话说,""、0、"0"、NULL、FALSE、array()、var $var; 以及没有任何属性的对象(只有这8个,记住了)都将被认为是空的,如果 var 为空,则返回 TRUE 。
如果变量为 0 ,则empty()会返回TRUE,isset()会返回TRUE;
如果变量为空字符串,则empty()会返回TRUE,isset()会返回TRUE;
如果变量未定义,则empty()会返回TRUE,isset()会返回FLASE。
注意:isset() 只能用于变量,因为传递任何其它参数都将造成解析错误。若想检测常量是否已设置,可使用 defined() 函数。
当要 判断一个变量是否已经声明的时候 可以使用 isset 函数;
当要 判断一个变量是否已经赋予数据且不为空 可以用 empty函数;
当要 判断 一个变量 存在且不为空 先 isset 函数 再用 empty 函数;

题2:nginx使用哪种网络协议?

答案:nginx是应用层 我觉得从下往上的话 传输层用的是tcp/ip 应用层用的是http fastcgi负责调度进程。

  1. cookie数据存放在客户的浏览器上,session数据放在服务器上。

  2. cookie不是很安全,别人可以分析存放在本地的COOKIE并进行COOKIE欺骗
    考虑到安全应当使用session。

  3. session 会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能
    考虑到减轻服务器性能方面,应当使用COOKIE。

  4. 单个cookie保存的数据不能超过4K,很多浏览器都限制一个站点最多保存20个cookie。

  5. 所以个人建议:
    将登陆信息等重要信息存放为SESSION,其他信息如果需要保留,可以放在COOKIE中

    题9:数据库中的事务是什么?

答案:事务(transaction)是作为一个单元的一组有序的数据库操作。如果组中的所有操作都成功,则认为事务成功,即使只有一个操作失败,事务也不成功。如果所有操作完成,事务则提交,其修改将作用于所有其他数据库进程。如果一个操作失败,则事务将回滚,该事务所有操作的影响都将取消。

题11:简述下面程序的输出结果, 简要说明为什么, 如何解决这类问题?

1
2
3
4
<?php
$tmp = 0 == "a"? 1: 2;
echo $tmp;
?>

答案: 1

int和string类型强制转换造成的,0 == 0 肯定是true啊

PHP是弱类型

1
2
$tmp = 0 === "a"? 1: 2;
echo $tmp;

这样就是2

题12:什么是MVC?

答案:MVC由Model(模型), View(视图)和Controller(控制器)组成,PHP MVC可以更高效地管理好3个不同层的PHP代码。

  • Model:数据信息存取层。
  • View:view层负责将应用的数据以特定的方式展现在界面上。
  • Controller:通常控制器负责从视图读取数据,控制用户输入,并向模型发送数据。

###
题21:简述两种屏蔽php程序的notice警告的方法

答案:

  1. 在程序中添加:error_reporting (E_ALL & ~E_NOTICE);
  2. 修改php.ini中的:error_reporting = E_ALL 改为:error_reporting = E_ALL & ~E_NOTICE
  3. error_reporting(0);或者修改php.inidisplay_errors=Off

题28:写一个排序算法,可以是冒泡排序或者是快速排序,假设待排序对象是一个维数组

答案:

冒泡排序(数组排序):原理:两两相邻的数进行比较,如果反序就交换,否则不交换

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function bubble_sort($array)
{
$count = count($array);
if ($count <= 0) return false;
for($i=0; $i<$count; $i++){
for($j=$count-1; $j>$i; $j--){
if ($array[$j] < $array[$j-1]){
$tmp = $array[$j];
$array[$j] = $array[$j-1];
$array[$j-1] = $tmp;
}
}
}
return $array;
}

快速排序(数组排序):

原理:找到当前数组中的任意一个元素(一般选择第一个元素),作为标准,新建两个空数组,遍历整个数组元素,
如果遍历到的元素比当前的元素要小,那么就放到左边的数组,否则放到右面的数组,然后再对新数组进行同样的操作

不难发现,这里符合递归的原理,所以我们可以用递归来实现。

使用递归,则需要找到递归点和递归出口:

  • 递归点:如果数组的元素大于 1,就需要再进行分解,所以我们的递归点就是新构造的数组元素个数大于 1
  • 递归出口:我们什么时候不需要再对新数组不进行排序了呢?就是当数组元素个数变成 1 的时候,所以这就是我们的出口。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function quicksort($array) {
if (count($array) <= 1) return $array;
$key = $array[0];
$left_arr = array();
$right_arr = array();
for ($i=1; $i<count($array); $i++){
if ($array[$i] <= $key)
$left_arr[] = $array[$i];
else
$right_arr[] = $array[$i];
}
$left_arr = quicksort($left_arr);
$right_arr = quicksort($right_arr);
return array_merge($left_arr, array($key), $right_arr);
}

nginx 入门到实践 慕课网

nginx 是一个开源且高性能、可靠的HTTP中间件、代理服务。

安装 yum install nginx

1. 安装目录

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
[root@iz2ze4kikm9076bxac1noqz opt]# rpm -ql nginx
/etc/logrotate.d/nginx
/etc/nginx
/etc/nginx/conf.d
/etc/nginx/conf.d/default.conf
/etc/nginx/fastcgi_params
/etc/nginx/koi-utf
/etc/nginx/koi-win
/etc/nginx/mime.types
/etc/nginx/modules
/etc/nginx/nginx.conf
/etc/nginx/scgi_params
/etc/nginx/uwsgi_params
/etc/nginx/win-utf
/etc/sysconfig/nginx
/etc/sysconfig/nginx-debug
/usr/lib/systemd/system/nginx-debug.service
/usr/lib/systemd/system/nginx.service
/usr/lib64/nginx
/usr/lib64/nginx/modules
/usr/libexec/initscripts/legacy-actions/nginx
/usr/libexec/initscripts/legacy-actions/nginx/check-reload
/usr/libexec/initscripts/legacy-actions/nginx/upgrade
/usr/sbin/nginx
/usr/sbin/nginx-debug
/usr/share/doc/nginx-1.12.2
/usr/share/doc/nginx-1.12.2/COPYRIGHT
/usr/share/man/man8/nginx.8.gz
/usr/share/nginx
/usr/share/nginx/html
/usr/share/nginx/html/50x.html
/usr/share/nginx/html/index.html
/var/cache/nginx
/var/log/nginx
路径 类型 作用
/etc/logrotate.d/nginx 配置文件 nginx日志轮转,用于logrotate服务的日志切割
/etc/nginx
/etc/nginx/nginx.conf
/etc/nginx/conf.d
/etc/nginx/conf.d/default.conf
目录、配置文件 nginx主配置文件
/etc/nginx/fastcgi_params
/etc/nginx/uwsgi_params
/etc/nginx/scgi_params
配置文件 cgi配置相关,fastcgi配置
/etc/nginx/koi-utf
/etc/nginx/koi-win
/etc/nginx/win-utf
配置文件 编码转换映射转化文件 很少用到
/etc/nginx/mime.types 配置文件 设置HTTP协议的Content-Type与扩展名对应关系
/etc/sysconfig/nginx
/etc/sysconfig/nginx-debug
/usr/lib/system/system/nginx-debug.service
/usr/lib/systemd/system/nginx.service
配置文件 用于配置出系统守护进程管理器管理方式,取代旧的init.d的脚本管理方式
/usr/lib64/nginx/modules
/etc/nginx/modules
目录 nginx 模块目录
/usr/sbin/nginx
/usr/sbin/nginx-debug
命令 nginx 服务的启动管理终端命令, nginx 服务的启动、关闭、配置、管理
/usr/share/doc/nginx-1.12.2
/usr/share/doc/nginx-1.12.2/COPYRIGHT
/usr/share/man/man8/nginx.8.gz
文件、目录 nginx的手册和帮助文件
/var/cache/nginx 目录 nginx的缓存目录
/var/log/nginx 目录 nginx的日志目录

2. 编译参数

查看编译时所用到的参数 nginx -V 大写

1
2
3
4
5
6
[root@iz2ze4kikm9076bxac1noqz opt]# nginx -V
nginx version: nginx/1.12.2
built by gcc 4.8.5 20150623 (Red Hat 4.8.5-16) (GCC)
built with OpenSSL 1.0.2k-fips 26 Jan 2017
TLS SNI support enabled
configure arguments: --prefix=/etc/nginx --sbin-path=/usr/sbin/nginx --modules-path=/usr/lib64/nginx/modules --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --pid-path=/var/run/nginx.pid --lock-path=/var/run/nginx.lock --http-client-body-temp-path=/var/cache/nginx/client_temp --http-proxy-temp-path=/var/cache/nginx/proxy_temp --http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp --http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp --http-scgi-temp-path=/var/cache/nginx/scgi_temp --user=nginx --group=nginx --with-compat --with-file-aio --with-threads --with-http_addition_module --with-http_auth_request_module --with-http_dav_module --with-http_flv_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_mp4_module --with-http_random_index_module --with-http_realip_module --with-http_secure_link_module --with-http_slice_module --with-http_ssl_module --with-http_stub_status_module --with-http_sub_module --with-http_v2_module --with-mail --with-mail_ssl_module --with-stream --with-stream_realip_module --with-stream_ssl_module --with-stream_ssl_preread_module --with-cc-opt='-O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -m64 -mtune=generic -fPIC' --with-ld-opt='-Wl,-z,relro -Wl,-z,now -pie'
路径 作用
--prefix=/etc/nginx
--sbin-path=/usr/sbin/nginx
--modules-path=/usr/lib64/nginx/modules
--conf-path=/etc/nginx/nginx.conf
--error-log-path=/var/log/nginx/error.log
--http-log-path=/var/log/nginx/access.log
--pid-path=/var/run/nginx.pid
--lock-path=/var/run/nginx.lock
安装目的目录或路径 nginx 基础路径
--http-client-body-temp-path=/var/cache/nginx/client_temp
--http-proxy-temp-path=/var/cache/nginx/proxy_temp
--http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp
--http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp
--http-scgi-temp-path=/var/cache/nginx/scgi_temp
执行对应模块时,nginx所保留的临时文件
--user=nginx --group=nginx 设定nginx进程启动的用户和用户组
--with-cc-opt= ... 设置额外的参数将被添加到CFLAGS变量 不需要了解
--with-ld-opt= ... 设置附件的参数,链接系统库

3. 基本配置语法 nginx.conf default.conf

全局性、服务级别配置

配置 作用
user 设置nginx服务的系统使用用户,一般为nginx,不用修改
worker_processes 工作进程数,一般和cpu核数保持一致即可
error_log nginx错误日志
pid nginx服务启动时的pid

事件模块配置 events

配置 作用
worker_connections 每个进程运行的最大连接数 最大65535,一般10000左右最多
use 工作进程数,内核模型

default.conf 配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
server {
listen 80; # 监听的端口号
server_name localhost; # 服务的域名
#charset koi8-r;
#access_log /var/log/nginx/host.access.log main;
# 首页路径或子路径
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
# 错误页面
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
# proxy the PHP scripts to Apache listening on 127.0.0.1:80
#
#location ~ \.php$ {
# proxy_pass http://127.0.0.1;
#}
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
#location ~ \.php$ {
# root html;
# fastcgi_pass 127.0.0.1:9000;
# fastcgi_index index.php;
# fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
# include fastcgi_params;
#}
# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
#location ~ /\.ht {
# deny all;
#}
}

算法、逻辑思维2

算法

真题:1,1,2,3,5,8,13,21,34… 求第 30 位的数是多少,请用伪代码描述其实现方法

考点:逻辑思维能力

解题方法:找到要处理的数组或者字符串的规律,也可以是一个数列的规律,如果要求使用伪代码实现,建议先说明规律,然后白话说明解题步骤即可。

1
2
3
4
5
6
7
<?php
$arr = [1, 1];
for ($i = 2; $i < 30; ++$i) {
$arr[$i] = $arr[$i - 1] + $arr[$i - 2];
}
var_dump($arr);

真题:请写一个函数,实现以下功能:字符串 “open_door” 转换成 “OpenDoor”,”make_by_id” 转换成 “MakeById”

分割–首字母大写–合并

1
2
3
4
5
6
7
8
9
<?php
function strConvert($str) {
$returnData = '';
$arr = explode('_', $str);
foreach ($arr as $value) {
$returnData .= ucfirst($value);
}
return $returnData;
}

模拟内置函数

真题:不使用 PHP 函数,用方法写一个反转字符串的方法

考点:逻辑思维能力;对 PHP 内置函数的熟悉程度;字符串和数组的处理能力

把字符串直接当成数组来处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php
function strReverse($str) {
// 自己实现字符串长度的统计,不能使用 strlen()
for ($i = 0; true; ++$i) {
if (!isset($str[$i])) {
break;
}
}
$returnData = '';
for ($j = $i - 1; $j >= 0; --$j) {
$returnData .= $str[$j];
}
return $returnData;
}

真题:写一个函数,要求不使用 array_merge 完成多个数组的合并

1
2
3
4
5
6
7
8
9
10
11
12
function arrMerge() {
returnData = [];
$arrays = func_get_args();
foreach ($arrays as $arr) {
if (is_array($arr)) {
foreach ($arr as $value) {
$returnData[] = $value;
}
}
}
return $returnData;
}

常见算法

写出常见的排序算法,并用 PHP 实现冒泡排序,将数组按照从小到大的方式进行排序

考点:

  • 冒泡排序的原理和实现
  • 延伸:算法的概念
  • 延伸:时间复杂度和空间复杂度的概念
  • 延伸:常见排序算法
  • 延伸:常见查找算法

1. 算法概念

解决特定问题求解步骤的描述,在计算机中表现为指令的有限序列,并且每条指令表示一个或多个操作

一个问题可以有多种算法,每种算法都有不同的效率

一个算法具有 5 个特性:有穷性(算法能计算完,不能是死循环)、确切性(每一步都要有意义)、输入项、输出项、可行性(可以执行,每一步都是正确的)。

2. 算法评定

算法分析的目的在于选择合适的算法和改进算法

一个算法的评价主要是从时间复杂度和空间复杂度来考虑

1. 时间复杂度

执行算法所需要的计算工作量,也就是时间消耗的效率。一般来说,计算机算法是问题规模 $$n$$ 的函数 $$f(n)$$,算法的时间复杂度也一次记作 $$T(n)=O(f(n))$$

问题的规模 $$n$$ 越大,算法执行的时间的增长率与 $$f(n)$$ 的增长率正相关,称作渐进时间复杂度。

计算方式
  1. 得出算法的计算次数公式
  2. 用常数 $$1$$ 来取代所有时间中的所有加法常数,如 $$O(3)$$ 要写成 $$O(1)$$
  3. 在修改后的运行次数函数中,只保留最高阶项,如 $$O(n^2+n+1)$$ 要写成 $$O(n^2)$$
  4. 如果最高阶存在且不是1,则去除与这个项相乘的常数,如 $$O(3n)$$ 要写成 $$O(n)$$
举例
  1. 常数阶:$$O(1)$$

    1
    2
    3
    4
    5
    <?php
    $n = 3;
    echo $n;
    echo $n;
    echo $n;
  2. 线性阶:$$O(n)$$

    1
    2
    3
    4
    5
    6
    7
    <?php
    $n = 100;
    $sum = 0;
    for ($i = 0; $i < $n; ++$i) {
    $sum += $n;
    }
    echo $sum;
  3. 平(立)方阶:$$O(n^2)/O(n^3)$$

    1
    2
    3
    4
    5
    6
    7
    8
    9
    <?php
    $n = 100;
    $sum = 0;
    for ($i = 0; $i < $n; ++$i) {
    for ($j = 0; $j < $n; ++$j) {
    $sum += $j;
    }
    }
    echo $sum;
  4. 对数阶:$$O(log_2n)$$

1
2
3
4
5
<?php
$n = 1000;
while ($n >= 1) {
$n = $n/2;
}

效率对比
$$$
O(1) > O(log_2n) > O(n) > O(nlog_2n) > O(n^2) > O(n^3) > O(2^n) > O(n!) > O(n^n)
$$$

最坏情况,如果没有特别说明,时间复杂度就是指最坏情况下的时间复杂度

2. 空间复杂度

算法需要消耗的内存空间,记作 $$S(n)=O(f(n))$$

包括程序代码所占用的空间,输入数据所占用的空间和辅助变量所占用的空间三部分

计算和表示方法与时间复杂度类似,一般用复杂度的渐进性来表示

有时用空间换取时间

冒泡排序的元素交换,空间复杂度$$O(1)$$

排序算法:冒泡排序、直接插入排序、希尔排序、选择排序、快速排序、堆排序、归并排序

3. 排序算法

1. 冒泡排序

原理:两两相邻的数进行比较,如果反序就交换,否则不交换

时间复杂度:最坏 $$O(n^2)$$,平均 $$O(n^2)$$

空间复杂度:$$O(1)$$

对于一个长度为 N 的数组,我们需要排序 N-1 轮,每 i 轮 要比较 N-i 次。对此我们可以用双重循环语句,外层循环控制循环轮次,内层循环控制每轮的比较次数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?php
function order($arr) {
  $count = count($arr);
  $temp = 0;
   // 外层控制排序轮次
  for ($i = 0; $i < $count - 1; $i++) {
  // 内层控制每轮比较次数
  for ($j = 0; $j < $count - 1- $i; $j++){
  if ($arr[$j] > $arr[$j + 1]) {
  $temp = $arr[$j];
  $arr[$j] = $arr[$j + 1];
  $arr[$j + 1] = $temp;
  }
   }
  }
return $arr;
}
$arr= array(6, 3, 8, 2, 9, 1);
$res = order($arr);
var_dump($res);

2. 直接插入排序

原理:每次从无序表中取出第一个元素,把它出入到有序表的合适位置,使有序表仍然有序

时间复杂度:最坏 $$O(n^2)$$,平均 $$O(n^2)$$

空间复杂度:$$O(1)$$

3. 希尔排序(shell sort)

希尔排序是基于插入排序的,区别在于插入排序是相邻的一个个比较(类似于希尔中 h=1 的情形),而希尔排序是距离 h 的比较和替换。

希尔排序中一个常数因子 n,原数组被分成各个小组,每个小组由 h 个元素组成,很可能会有多余的元素。当然每次循环的时候,h 也是递减的(h=h/n)。第一次循环就是从下标为 h 开始。希尔排序的一个思想就是,分成小组去排序。

时间复杂度:最坏 $$O(n^2)$$,平均 $$O(n*log_2n)$$

空间复杂度:$$O(1)$$

4. 选择排序

原理:每次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完

时间复杂度:最坏 $$O(n^2)$$,平均 $$O(n^2)$$

空间复杂度:$$O(1)$$

5. 快速排序

原理:找到当前数组中的任意一个元素(一般选择第一个元素),作为标准,新建两个空数组,遍历整个数组元素,
如果遍历到的元素比当前的元素要小,那么就放到左边的数组,否则放到右面的数组,然后再对新数组进行同样的操作,
不难发现,这里符合递归的原理,所以我们可以用递归来实现。
使用递归,则需要找到递归点和递归出口:
递归点:如果数组的元素大于 1,就需要再进行分解,所以我们的递归点就是新构造的数组元素个数大于 1
递归出口:我们什么时候不需要再对新数组不进行排序了呢?就是当数组元素个数变成 1 的时候,所以这就是我们的出口。

时间复杂度:最坏 $$O(n^2)$$,平均 $$O(nlog_2n)$$

空间复杂度:最坏 $$O(n)$$,平均 $$O(log_2n)$$

6 .堆排序

二叉树。。。

时间复杂度:最坏 $$O(nlog_2n)$$,平均 $$O(nlog_2n)$$

空间复杂度:$$O(1)$$

7. 归并排序

就是利用归并(合并)的思想实现的排序方法。它的原理是假设初始序列含有 n 个元素,则可以看成是 n 个有序的子序列,每个子序列的长度为 1,然后两两归并,得到 ⌈ n / 2⌉ (⌈ x ⌉ 表示不小于 x 的最小整数)个长度为 2 或 1 的有序序列;再两两归并,······,如此重复,直至得到一个长度为 n 的有序序列为止,这种排序方法就成为 2 路归并排序。

时间复杂度:最坏 $$O(nlog_2n)$$,平均 $$O(nlog_2n)$$

空间复杂度:$$O(n)$$

8. 总结

快速排序、归并排序的理想时间复杂度都是 $$O(nlog_2n)$$,但是快速排序的时间复杂度并不稳定,最坏情况下复杂度为 $$O(n^2)$$,所以最理想的算法还是归并排序。

4. 查找方法

1. 二分查找

原理:从数组的中间元素开始,如果中间元素正好是要查找的元素,搜索结束,如果某一个特定的元素大于有这小鱼中间元素,则在数组大于或者小于中间元素的那一半中查找,而且跟开始一样从中间开始比较,如果某一步骤数组为空,表示找不到。

时间复杂度:最坏 $$O(log_2n)$$,平均 $$O(log_2n)$$

空间复杂度:迭代 $$O(1)$$,递归 $$O(log_2n)$$

2. 顺序查找

原理:按一定的顺序检查数组中的每一个元素,直到找到所要寻找的特定值为止。

时间复杂度:最差 $$O(n)$$,平均 $$O(n)$$

空间复杂度:$$O(1)$$

3. 总结

二分查找算法的时间复杂度最差是 $$O(log_2n)$$,顺序查找的时间复杂度最差为 $$O(n)$$,所以二分查找更快,但是递归条件下,二分查找更消耗内存。

5. 解题方法

需要充分理解各种排序算法和查找算法的原理以及实现方式,另外还需要理解时间复杂度和空间复杂度的计算方式和概念,考察的是逻辑思维能力,需要仔细研究各种算法的实现方式。

6. 真题

1. 简述时间复杂度和空间复杂度的概念

2. 对无序数组排序,最优的时间复杂度是什么,用 PHP 或者 JavaScript 写出一个实际的例子,该算法的空间复杂度是多少?

快速或归并

3. 一个有序数组中,查询特定 item 是否存在的最优算法是什么?时间复杂度多少?

|