知识点

PHP

引用 &

验证方法:

- var_dump(memory_get_usage());

- xdebug_debug_zval('变量名称'); //需装xdebug扩展
输出示例:
p1:(refcount=1,is_ref=0)=class Person={.....}
//refcount: 指向该内存空间的变量个数
//is_ref: 是否有引用, 1-是,0-否
  1. 变量
普通传值:$b = $a;
变量独有的cow机制(copy on write),当赋值变量修改时才会拷贝所需内存

引用传值:$b = &$a;
两个变量使用同一个内存区域

  1. 对象
$q = new OneObecjt();
$p = $q;
//对象本身就是引用传递

常量及数据类型

  1. 单引号和双引号
- 单引号只能解析单引号和反斜线本身,无法解析变量
- 单引号效率比较高

  1. 三大数据类型(标量、复合、特殊)
标量:
- 浮点类型不能运用到比较运算中;

- 布尔类型,false的七种情况:
0, 0.0(浮点型),''(空字符串), '0', false, array(), NULL

- 数组类型,超全局数组:
$CLOBALS, $_GET, $_POST, $_REQUEST, $_SESSIONI, $_COOKIE, $_SERVIER, $_FILES, $_ENV

$_SERVER['SERVER_ADDR'] //服务器地址
$_SERVER['REMOTE_ADDR'] //客户端地址,再找下其他信息


- NULL 三种情况:
直接赋值为NULL, 未定义的变量,unset销毁的变量

运算符

- 错误运算符: @ ,在一个PHP表达式之前,该表达式可能产生的任何错误信息都被忽略掉。
- 运算符优先级:

    递增/递减 > ! > 算术运算符 > 大小比较 > 相等比较 > 位运算符(^) > 位运算符(|) > 逻辑与 > 逻辑或 > 三目 > 赋值 > and > xor > or

    括号使用可增加代码的可读性。
- 比较运算符 : == 和 === 的区别
- 递增、递减:
    不影响布尔值
    递减null值没有效果
    递减null值为1
    在前则为先运算符后返回,反之就先返回后运算
- 逻辑运算符: 
    短路作用
    ||和&& 同 or和and 的优先级不同


流程控制

- php遍历数组的三种方式:
    ①使用for循环
    ②使用foreach循环
    ③使用while、list()、each()组合循环
    
    区别:
    for只能遍历索引数组
    foreach以及组合循环可以遍历关联和索引数组
    组合循环不会进行reset()操作
    foreach会对数组进行reset()操作

- if 和 elseif
    使用elseif,总把优先范围小的条件放在前面处理
    
- switch case
    switch后面的控制表达式的数据类型只能是整形,浮点类型, 字符串
    continue在switch中的作用相当于break
    跳出switch外的循环,可以使用continue 2
    

自定义以及内部函数

- 变量的作用域和静态变量
    
    static关键字
    ①仅初始化一次
    ②初始化时需要赋值
    ③每次执行函数该值会保留
    ④static修饰的变量是局部的,仅在函数内部有效
    ⑤可以记录函数的调用次数,从而可以在某些条件下终止递归
    
- 函数的引用返回

    从函数返回一个引用,必须在函数声明和指派返回值给一个变量时都使用引用运算符&
    
    例子:
    function &mgFunc(){
        static $b = 10;
        return $b;
    }
    $a = myFunc();  => 10
    $a = &myFunc();
    $a = 100;
    echo myFunc(); => 100

- 内置函数【简略】

    看手册或者之前记录的函数使用

正则表达式

- 正则表达式的作用:分割、查找、匹配、替换字符串
    相关匹配规则【简略】

- 后向引用

    $str = '<b>abc</b>';
    $pattern = '/<b>(.*)<\/b>/';
    preg_replace($pattern, '\\1', $str);  => abc
    
- 贪婪模式

    $str = '<b>abc</b><b>abc</b>';
    $pattern = '/<b>.*<\/b>/';
    preg_replace_all($pattern, '\\1', $str);  => abc</b><b>abc
    //取消贪婪模式切换为懒惰模式
    //① 添加 ? 符号
    $pattern = '/<b>.*?<\/b>/'; => abc
    //② 添加 U
    $pattern = '/<b>.*<\/b>/U'; => abc
    
- 中文匹配
    utf8汉字编码范围 0x4e00-0x9fa5,
    ansi(gb2312)是 0xb0-0xf7, 0xa1-0xfe
    
    utf8要使用u模式修正符使模式字符串被当成utf-8,在gb2312环境下,要使用chr将ascii码转换为字符
    
    示例:
    $str = '中文';
    //utf-8
    $pattern = '/[\x{4e00}-\x{9fa5}]+/u';
    //gb2312
    $pattern = '/['. chr(0xb0) . '-' . chr(0xf7) . '][' . chr(0xa1) . '-' . chr(0xfe) . ']/';
    preg_match($pattern, $str, $match);
    var_dump($match);
    
- 模式修饰符
    模式修饰符的作用是设定模式,也就是正则表达式如何解释。php中主要模式如下表:
    
    修饰符|	说明
    i |	忽略大小写
    m |	多文本模式
    s |	单行文本模式
    x |	忽略空白字符    
    
- php中的字符串匹配

    不使用正则匹配:
    
        strstr函数 
        string strstr ( string haystack,mixedneedle [, bool $before_needle = false ]) 
        注1:haystack是当事字符串,needle是被查找的字符串。该函数区分大小写。
        注2:返回值是从needle开始到最后。
        注3:关于$needle,如果不是字符串,被当作整形来作为字符的序号来使用。
        注4:before_needle若为true,则返回前东西。
        
        stristr函数与strstr函数相同,只是它不区分大小写
        
        strpo函数 
        int strpos ( string haystack,mixedneedle [, int $offset = 0 ] ) 
        注1:可选的 offset 参数可以用来指定从 haystack 中的哪一个字符开始查找。返回的数字位置是相对于 haystack 的起始位置而言的。
        
        stripos -查找字符串首次出现的位置(不区分大小定)
        
        strrpos -计算指定字符串在目标字符串中最后一次出现的位置
        
        strripos -计算指定字符串在目标字符串中最后一次出现的位置(不区分大小写)
        
    使用正则表达式匹配
        
        在php中,提供了preg_math()和preg_match_all函数进行正则匹配。关于这两个函数原型如下:
        int preg_match|preg_match_all ( string $pattern , string $subject [, array &$matches [, int $flags = 0 [, int $offset = 0 ]]] )
        
        搜索subject与pattern给定的正则表达式的一个匹配.
        
        pattern:要搜索的模式,字符串类型。 
        subject :输入字符串。 
        matches:如果提供了参数matches,它将被填充为搜索结果。 matches[0]将包含完整模式匹配到的文本,matches[1]将包含第一个捕获子组匹配到的文本,以此类推。 
        flags:flags可以被设置为以下标记值:PREG_OFFSET_CAPTURE 如果传递了这个标记,对于每一个出现的匹配返回时会附加字符串偏移量(相对于目标字符串的)。 注意:这会改变填充到matches参数的数组,使其每个元素成为一个由 第0个元素是匹配到的字符串,第1个元素是该匹配字符串 在目标字符串subject中的偏移量。 
        offset:通常,搜索从目标字符串的开始位置开始。可选参数 offset 用于 指定从目标字符串的某个未知开始搜索(单位是字节)。
        
        返回值:preg_match()返回 pattern 的匹配次数。 它的值将是0次(不匹配)或1次,因为 preg_match()在第一次匹配后 将会停止搜索。 preg_match_all()不同于此,它会一直搜索subject直到到达结尾。 如果发生错误 preg_match()返回 FALSE。

文件/目录操作


文件
- fopen(), 打开时需要指定打开模式
    打开模式:
    r/r+ (读/读写) 文件指针指向开头;
    w/w+ (只写/读写) 文件指针指向开头,清空文件,不存在则创建;
    a/a+  (追加) 文件指针指向末尾, 不存在则创建;
    x/x+ (写入) 文件指针指向开头,如果文件存在报warning错误,返回false.不存在则新建
    b 二进制文件打开可用
    t 系统提供的文件类型打开模式

    写入函数: fwrite() 、 fputs()
    读取函数:fread() fgets() fgetc()
    关闭函数: fclose()

- 不需要fopen打开函数:
    file_get_contents()
    file_put_contents()
    
- 访问远程文件
    开启allow_url_fopen, http连接只能使用只读, ftp协议只能使用只读或者只写

目录
- 目录操作函数
    名称相关:basename()、dirname()、pathinfo()
    目录读取:opendir()  readdir()  closedir() rewinddir() 
    目录删除:rmdir() 只能删除空文件
    目录创建:mkdir() 相关权限设置
- 其他函数
    文件大小:filesize()
    目录大小:disk_free_space()  disk_total_space()
    文件拷贝:copy()
    删除文件:unlink()
    文件类型:filetype()
    重命名(移动)文件或者目录:rename()
    文件截取:ftruncate()
    文件属性:file_exists()  is_readable() is_wrirtable() is_executable()  filectime()修改时间  fileatime()访问时间  filemtime()
    文件锁: flock()
    文件指针:ftell()  fseek()  rewind() 
    
    文件目录删除和复制

    示例:
    输出目录结果
    function loopDir($dir)
    {
        $handle = openidr($dir);
        while(false!==($file = readdir($handle)))
        {
            if($file != '.' && $file != '..')
            {
                echo $file . '\n';
                if(filetype($dir. '/' . $file) == 'dir') 
                {
                    loopDir($dir. '/' . $file);
                }
            }
        }
    }

会话控制

- 产生的原因
    http每次请求都是握手/挥手,第二次和第一次请求时没有任何关联的,属于无状态协议,为了区分用户才需要会话
- Cookie
    setcookie();
    $_COOKIE
- Session
    session_start();//启动新会话或者重用现有会话,发送set-cookie的响应头,告诉浏览器设置一个php_session的cookie 会话,会话id为php随机产生,并在服务器端临时目录产生一个对应的session文件
    $_SESSION['a'] = 1;//存储一个关于该会话id的值
    session_destroy();//销毁会话数据
    //当在脚本结束时,会将超全局变量$_SESSION中的值存储进对应的session文件

面向对象

设计模式

魔术方法

基本语法

网络协议

相关网络层协议了解

- http协议状态码
    2**开头 (请求成功)表示成功处理了请求的状态代码。
    200 (成功) 服务器已成功处理了请求。 通常,这表示服务器提供了请求的网页。
    201 (已创建) 请求成功并且服务器创建了新的资源。
    202 (已接受) 服务器已接受请求,但尚未处理。
    203 (非授权信息) 服务器已成功处理了请求,但返回的信息可能来自另一来源。
    204 (无内容) 服务器成功处理了请求,但没有返回任何内容。
    205 (重置内容) 服务器成功处理了请求,但没有返回任何内容。
    206 (部分内容) 服务器成功处理了部分 GET 请求。
    
    3** 开头 (请求被重定向)表示要完成请求,需要进一步操作。 通常,这些状态代码用来重定向。
    300 (多种选择) 针对请求,服务器可执行多种操作。 服务器可根据请求者 (user agent) 选择一项操作,或提供操作列表供请求者选择。
    301 (永久移动) 请求的网页已永久移动到新位置。 服务器返回此响应(对 GET 或 HEAD 请求的响应)时,会自动将请求者转到新位置。
    302 (临时移动) 服务器目前从不同位置的网页响应请求,但请求者应继续使用原有位置来进行以后的请求。
    303 (查看其他位置) 请求者应当对不同的位置使用单独的 GET 请求来检索响应时,服务器返回此代码。
    304 (未修改) 自从上次请求后,请求的网页未修改过。 服务器返回此响应时,不会返回网页内容。
    305 (使用代理) 请求者只能使用代理访问请求的网页。 如果服务器返回此响应,还表示请求者应使用代理。
    307 (临时重定向) 服务器目前从不同位置的网页响应请求,但请求者应继续使用原有位置来进行以后的请求。
    
    4**开头 (请求错误)这些状态代码表示请求可能出错,妨碍了服务器的处理。
    400 (错误请求) 服务器不理解请求的语法。
    401 (未授权) 请求要求身份验证。 对于需要登录的网页,服务器可能返回此响应。
    403 (禁止) 服务器拒绝请求。
    404 (未找到) 服务器找不到请求的网页。
    405 (方法禁用) 禁用请求中指定的方法。
    406 (不接受) 无法使用请求的内容特性响应请求的网页。
    407 (需要代理授权) 此状态代码与 401(未授权)类似,但指定请求者应当授权使用代理。
    408 (请求超时) 服务器等候请求时发生超时。
    409 (冲突) 服务器在完成请求时发生冲突。 服务器必须在响应中包含有关冲突的信息。
    410 (已删除) 如果请求的资源已永久删除,服务器就会返回此响应。
    411 (需要有效长度) 服务器不接受不含有效内容长度标头字段的请求。
    412 (未满足前提条件) 服务器未满足请求者在请求中设置的其中一个前提条件。
    413 (请求实体过大) 服务器无法处理请求,因为请求实体过大,超出服务器的处理能力。
    414 (请求的 URI 过长) 请求的 URI(通常为网址)过长,服务器无法处理。
    415 (不支持的媒体类型) 请求的格式不受请求页面的支持。
    416 (请求范围不符合要求) 如果页面无法提供请求的范围,则服务器会返回此状态代码。
    417 (未满足期望值) 服务器未满足"期望"请求标头字段的要求。
    
    5**开头(服务器错误)这些状态代码表示服务器在尝试处理请求时发生内部错误。 这些错误可能是服务器本身的错误,而不是请求出错。
    500 (服务器内部错误) 服务器遇到错误,无法完成请求。
    501 (尚未实施) 服务器不具备完成请求的功能。 例如,服务器无法识别请求方法时可能会返回此代码。
    502 (错误网关) 服务器作为网关或代理,从上游服务器收到无效响应。
    503 (服务不可用) 服务器目前无法使用(由于超载或停机维护)。 通常,这只是暂时状态。
    504 (网关超时) 服务器作为网关或代理,但是没有及时从上游服务器收到请求。
    505 (HTTP 版本不受支持) 服务器不支持请求中所用的 HTTP 协议版本。
  
- OSI七层模型
    物理层: 建立、维护、断开物理连接
    
    数据链路层: 建立逻辑连接、进行硬件地址寻址、差错校验等功能
    
    网络层: 进行逻辑地址寻址、实现不同网络之间的路径选择
    
    传输层:定义传输数据的协议端口号,以及流控和差错校验
    
    会话层:建立、管理、终止会话
    
    表示层:数据的表示、安全、压缩
    
    应用层: 网络服务与最终用户的一个接口
    HTTP FTP TFTP SMTP SNMP DNS TELNET HTTPS POP3 DHCP
    
    
- http协议的工作特点和工作原理

    特点:
    基于b/s模式、通信开销小、简单快速、传输成本低
    工作原理:
    客户端发送请求给服务器、创建一个TCP连接,指定端口号, 默认80,连接到服务器,服务器监听浏览器请求,一旦监听到客户端请求,分析请求类型后,服务器会向客户端返回状态信息和数据内容
    
- 常见的请求、响应头和请求方法

    http头部属性说明:
    Accept 指定客户端能够接收的内容类型 Accept: text/plain, text/html
    Accept-Charset 浏览器可以接受的字符编码集。 Accept-Charset: iso-8859-5
    Accept-Encoding 指定浏览器可以支持的web服务器返回内容压缩编码类型。 Accept-Encoding: compress, gzip
    Accept-Language 浏览器可接受的语言 Accept-Language: en,zh
    Accept-Ranges 可以请求网页实体的一个或者多个子范围字段 Accept-Ranges: bytes
    Authorization HTTP授权的授权证书 Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
    Cache-Control 指定请求和响应遵循的缓存机制 Cache-Control: no-cache
    Connection 表示是否需要持久连接。(HTTP 1.1默认进行持久连接) Connection: close
    Cookie HTTP请求发送时,会把保存在该请求域名下的所有cookie值一起发送给web服务器。 Cookie: $Version=1; Skin=new;
    Content-Length 请求的内容长度 Content-Length: 348
    Content-Type 请求的与实体对应的MIME信息 Content-Type: application/x-www-form-urlencoded
    Date 请求发送的日期和时间 Date: Tue, 15 Nov 2010 08:12:31 GMT
    Expect 请求的特定的服务器行为 Expect: 100-continue
    From 发出请求的用户的Email From: [email protected]
    Host 指定请求的服务器的域名和端口号 Host: www.zcmhi.com
    If-Match 只有请求内容与实体相匹配才有效 If-Match: “737060cd8c284d8af7ad3082f209582d”
    If-Modified-Since 如果请求的部分在指定时间之后被修改则请求成功,未被修改则返回304代码 If-Modified-Since: Sat, 29 Oct 2010 19:43:31 GMT
    If-None-Match 如果内容未改变返回304代码,参数为服务器先前发送的Etag,与服务器回应的Etag比较判断是否改变 If-None-Match: “737060cd8c284d8af7ad3082f209582d”
    If-Range 如果实体未改变,服务器发送客户端丢失的部分,否则发送整个实体。参数也为Etag If-Range: “737060cd8c284d8af7ad3082f209582d”
    If-Unmodified-Since 只在实体在指定时间之后未被修改才请求成功 If-Unmodified-Since: Sat, 29 Oct 2010 19:43:31 GMT
    Max-Forwards 限制信息通过代理和网关传送的时间 Max-Forwards: 10
    Pragma 用来包含实现特定的指令 Pragma: no-cache
    Proxy-Authorization 连接到代理的授权证书 Proxy-Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
    Range 只请求实体的一部分,指定范围 Range: bytes=500-999
    Referer 先前网页的地址,当前请求网页紧随其后,即来路 Referer: http://www.zcmhi.com/archives...
    TE 客户端愿意接受的传输编码,并通知服务器接受接受尾加头信息 TE: trailers,deflate;q=0.5
    Upgrade 向服务器指定某种传输协议以便服务器进行转换(如果支持) Upgrade: HTTP/2.0, SHTTP/1.3, IRC/6.9, RTA/x11
    User-Agent User-Agent的内容包含发出请求的用户信息 User-Agent: Mozilla/5.0 (Linux; X11)
    Via 通知中间网关或代理服务器地址,通信协议 Via: 1.0 fred, 1.1 nowhere.com (Apache/1.1)
    Warning 关于消息实体的警告信息 Warn: 199 Miscellaneous warning
    
    请求方式:
    GET  POST  PUT DELETE  HEAD  OPTION  TRACE
    
- https协议的工作原理
    

PHP常见配置

```
register_globals, allow_url_fopen, allow_url_include, date.timezone, display_errors, erro_reporting, safe_mode, upload_max_filesize, max_file_up

运行模式
php有着5种运行模式,常见的有4种:

cgi 协议模式
cgi模式 通用网关接口(Common Gateway Interface),它允许web服务器通过特定的协议与应用程序通信, 调用原理大概为:
用户请求->Web服务器接收请求->fork子进程 调用程序/执行程序->程序返回内容/程序调用结束->web服务器接收内容->返回给用户 由于每次用户请求,都得fork创建进程调用一次程序,然后销毁进程,所以性能较低

fast-cgi 协议模式
fast-cgi是cgi模式的升级版,它像是一个常驻型的cgi,只要开启后,就可一直处理请求,不再需要结束进程, 调用原理大概为:
web服务器fast-cgi进程管理器初始化->预先fork n个进程
用户请求->web服务器接收请求->交给fast-cgi进程管理器->fast-cgi进程管理区接收,给其中一个空闲fast-cgi进程处理->处理完成,fast-cgi进程变为空闲状态,等待下次请求->web服务器接收内容->返回给用户

注意,fast-cgi和cgi都是一种协议,开启的进程是单独实现该协议的进程

模块模式
apache+php运行时,默认使用的是模块模式,它把php作为apache的模块随apache启动而启动,接收到用户请求时则直接通过调用mod_php模块进行处理,详细内容可自行百度

php-cli模式
php-cli模式属于命令行模式,对于很多刚开始学php就开始wamp,wnmp的开发者来说是最陌生的一种运行模式
该模式不需要借助其他程序,直接输入php xx.php 就能执行php代码
命令行模式和常规web模式明显不一样的是:

没有超时时间
默认关闭buffer缓冲
STDIN和STDOUT标准输入/输出/错误 的使用
echo var_dump,phpinfo等输出直接输出到控制台
可使用的类/函数 不同
php.ini配置的不同

```

ajax的工作原理

    - XMlHttpRequest对象请求
    open(method, url, async)
    send(string)
    - xmlhttprequest 对象响应

Linux基础

    系统安全
    进程管理
    w  top ps kill pkill  pstree killall
    用户管理
    文件系统
    系统关机和重启
    网络应用
    网络配置
    软件包管理
    文件查找和比较
    文件内容查看
    文件处理
    文件权限
    解压压缩
    
    - crontab 定时任务
    crontab -e 
    (分时日月周)
    
    - vim、vi 编辑器
    一般模式、编辑模式、命令行模式
    一般模式:删除、复制、粘贴
    配置:命令行模式下 setnu setnonu 显示行数
    
    -  shell基础
    赋予权限,直接执行:
    chmod +x test.sh
    ./test.sh
    
    使用source命令,例:
    source test.sh

练手

  • 题目
1. 以下程序$data值是多少?(引用)

    $data = ['a', 'b', 'c'];
    foreach($data as $key => $val) 
    {
        $val = &$data[$key];
    }

2. 以下比较返回什么?(浮点类型不能用于比较运算)
    $a = 0.1;
    $b = 0.7;
    return $a + $b ==  0.8;

3. _FILE_ 表示什么意思(预定义常量)

4. false 的七种情况

5. $a  和 $b 的值是什么?
    $a = false || true;
    $b = false or true;

6. 打印输出的结果是什么?

    $a = 0;
    $b = 0;
    if ($a = 3 > 0 || $b = 3 > 0) 
    {
        $a++;
        $b++;
        echo $a;
        echo $b;
    }

7. php遍历数组的三种方式及各自区别

8. PHP中如何优化多个if....elseif语句的情况?

9. 以下程序的输出结果?

    $count = 5;
    function get_count()
    {
        static $count;
        return $count++;
    }
    echo $count;
    ++$count;
    
    echo get_count():
    echo get_count():
 
10. 写出139开头的11位手机号的正则表达式

11. 请匹配所有img标签中的src值

12. 每天0点重启服务器定时任务

  • 答案
1. $data = ['b', 'c', 'c']; //引用传值会修改原先的引用变量值内存

2. false //浮点型会转换为二进制,0.7转为二进制时会有损耗,两者相加等于 0.79999

3. 所在文件的路径以及文件名

4, 看笔记

5. 运算符的优先级

    $a = true;
    $b = false;
    
    第二个表达式中,= 赋值运算符优先于or 整体运算是 true
    
6. 运算符的优先级
    $a = 1;
    $b = 1;
    
7. 看笔记

8. 表达式可能越大往前放。如果是简单的表达式可考虑使用switch。

9. 5  null  1 //自定义函数中的初始化$count时值为null

10. 如下: 
    $str = '139888888888';
    $pattern = '/^139\d{8}$/' // ^ 以139开头,后面以0到9数字的8位数字, $结束
    preg_match($pattern, $str, $mattch);
    
11. 如下
    $pattern = '/<img.*?src=".*?".*?\/?>/i';//匹配img标签内容 /i 标识不区分大小写
    $pattern = '/<img.*?src="(.*?)".*?\/?>/i';//匹配src的值
    preg_match($pattern, $str, $match);
    var_dump($match);

12. crontab -e
    添加以下一列:
    0 0 * * * reboot
    分 时 日 月 周

MYSQL

having 和 where

where针对表中的列发挥作用,查询数据

having对查询结果中的列发挥作用,筛选数据

数据类型

    - 实数类型
    FLOAT, DOUBLE, DECIMAL
    DECIMAL 可存储比BIGINT还大的整数, 可以用于存储精确的小数
    FLOAT,DOUBLE支持使用标准的浮点进行近似运算
    
    - 字符串类型
    VARCHAR, CHAR, TEXT, BLOB 
    VARCHAR 用于存储可变长字符串, 它比定长类型更节省空间
    VARCHAR 使用1或2个额外字节记录字符串的长度,列长度小于255字节,使用1个字节表示,否则用2个
    VARCHAR长度如果存储内容长度超出指定长度,会被截断
    CHAR是定长的,根据定义的字符串长度分配足够的空间
    CHAR会根据需要采用空格进行填充以方便比较
    CHAR适合存储很短的字符串,或者所有值接近同一个长度(密码)
    CHAR长度超出设定长度也会被截断
    频繁更新的数据,CHAR比VARCHAR更好,不容易产生碎片
    对于非常短的列,CHAR比VACHAR在存储空间上更有效率
    只分配真正需要的空间,更长的列会消耗更多的内存

    - 枚举
    把不重复的集合存储成一个预定义的集合
    非常紧凑,把列表值压缩到一个或字节
    内部存储的是整数
    排序是按照内部存储的整数进行排序的
    
    - 日期和时间类型
    尽量使用TIMESTAMP,比 DATETIME 空间效率高
    用整数保存时间戳的格式通常不方便处理
    如果需要存储微妙, 可以使用bigint存储
    

索引

    - 对性能的影响
    大大减少服务器需要扫描的数据量
    帮助服务器避免排序和临时表
    将随机I/O变顺序I/O
    大大提高查询速度,降低写的速度,占用磁盘

    - 索引类型
    一个表只能有一个主键索引,可以有多个唯一索引
    主键索引一定是唯一索引, 唯一索引不是主键索引
    主键可以与外键构成参照完整性约束,防止数据不一致
    组合索引:将多列组合在一起创建索引,可以覆盖多个列
    外键索引:只有InnoDB类型的表才可以使用外键索引,保证数据的一致性,完整性和实现级联操作
    全文索引:MySql自带的全文索引只能用于MyISAM,并且只能对英文进行全文检索
    
    - 创建原则
    1. 最适合索引的列是出现在WHERE子句中的列,或连接子句中的列而不是出现在select关键字后的列
    2. 索引列的基数越大,索引的效果越好
    3. 对字符串进行索引,应该定制一个前缀长度,可以节省大量的索引空间
    4. 根据情况创建复合索引,复合索引可以提高查询效率
    5. 避免创建过多索引, 索引会额外占用磁盘空间,降低写操作效率
    6. 主键尽可能选择较短的数据类型,可以有效减少索引的磁盘占用,提高查询效率
    
    - 注意:
    1. 复合索引遵循的前缀原则
    例:复合索引的连续性
    KEY(a, b, c) 组合索引 abc  有效查询如下
    WHERE a = 1 and b = 2 and c = 3
    WHERE a = 1 and b = 2
    WHERE a = 1
    无效查询
    WHERE b = 2 and c = 3
    WHERE a = 1 and c = 3
    
    2. like 查询 %不能在前,否则索引失效,可以使用全文索引
    3. column is null 可以使用索引
    4. 如果MYSQL估计使用索引比全表扫描更慢, 会放弃使用索引
    5. 如果or前的条件中的列有索引,后面的没有,索引都不会被用到
    6. 列类型是字符串,查询时一定要给值加引导, 否则索引失效
    例:
    name varchar(18)类型
    “100”
    where name = 100 时不会使用索引
    where name = “100"时才会生效
    
    

mysql操作

    例:有A(id, sex, par, c1, c2) , B(id, age, c1, c2)两张表,其中A.id 同 B.id 关联, 现要求写出一条Sql语句,将B中age>50的记录的c1, c2 更新到A表中统一记录中的C1, c2字段中
    
    - update更新语句
        UPDATE A,B SET A.c1 = B.c1, A.c2= B.c2 WHERE A.id = B.id and B.age > 50;
        UPDATE A INNER JION B ON A.id = B.id SET A.c1 = B.c1, A.c2 = B.c2 WHERE B.age > 50;
    
    - 联合查询
        union 就是把多个结果集集中在一起,以union前的结果为基准,需要注意的是联合查询的列数要相等,相同的记录行会合并
        如果使用union all 不会合并重复的记录行
    
    - 全连接
        mysql不支持全连接
        可以使用左连接和右连接联合使用
        SELECT * FROM A LEFT JOIN B ON A.id = B.id UNION SELECT * FROM A RIGHT JOIN B ON A.id = B.id;
    
    - 例子
        表team
        teamID teamName
        表match
        matchID
        hostTeamId guestTeamID matchTime matchResult 
        根据以上两张表按如下格式查出
        主队  结果  客队  时间
        
        SELECT t1.teamName, m.matchResult, t2.teamName, m.matchTime from match as m left join team as t1 on m.hostTeamID = t1.teamID, left join team t2 on m.guestTeamID = t2.gteamID where m.matchTime between "2006" and "2017";
    
    - mysql 优化
        1. 分析 sql 查询慢的方法
        记录慢查询日志
        ① 分析查询日志,使用pt-query-digest工具进行分析
        
        ② 使用show profile
        set profiling = 1; 开启,服务器上执行的所有语句会检测消耗的时间,存到临时表中
        show profiles;
        show profile for query 临时表id;
        
        ③ 使用show status
        show status 会返回一些计数器,show global status 查看服务器级别的所有计数
        
        ④ 使用 show processlist
        观察是否有大量线程处于不正常的状态或者特征
        
        ⑤ 使用 explain 或者 desc 
        分析单挑sql语句
        explain select * from a; 可查看索引使用情况,扫描行数
        
        2. 优化查询过程中的数据访问
        访问数据太多导致查询性能下降
        
        ① 查询不需要的记录,使用limit解决
        ② 多表关联返回全部列,指定 A.id , A.name, B.age
        ③ 总是取出全部列,SELECT * 会让优化器无法完成索引覆盖扫描的优化
        ④ 重复查询相同的数据,可以缓存数据, 下次直接读取缓存
        ⑤ 是否存在扫描额外的记录
        使用explain 进行分析, 如果发现查询需要扫描大量的数据但只返回少数的行可做如下操作:
        使用索引覆盖扫描, 把所有用的列都放到索引中,这样存储引擎不需要回表获取对应行就可以返回结果
        ⑥ 该表数据库和表的结构,修改数据表范式,添加冗余字段减少关联查询
        
        3. 优化长难的查询语句
        ① 切分查询
        将一个大的查询分为多个小的相同的查询
        一次性删除1000w的数据要比一次删除1w,暂停一会的方案更加损耗服务器开销
        
        ② 分解关联查询
        可以将一条关联语句分解成多条sql来执行,作用如下:
        让缓存的效率更高
        执行单个查询可以减少锁的竞争
        在应用层做关联可以更容易对数据库进行拆分
        
        4. 优化特定类型的查询语句
        
        ①优化count() 查询
        count() 中的* 会忽略所有的列,直接统计所有列数,因此不要使用count(列名)
        
        ② 优化关联查询
        确定 on 或 using 子句的列上有索引
        确保group by 和 order by 只有一个表中的列,这样mysql才有可能使用索引
        
        ③ 优化子查询,使用关联查询来替代
        
        ④ 优化group by 和 distinct 
        这两种查询均可使用索引来优化,是最有效的优化方法
        关联查询中,使用标识列进行分组的效率会更高
        如果不需要order by,进行group by 时使用order by null ,mysql不会再进行文件排序
        
        ⑤ 优化limit分页
        limit 偏移量大的时候,查询效率较低
        可以记录上次查询的最大id,下次查询时直接根据该id来查询
        
        ⑥ 优化union 查询
        union all 的效率高于 union 
    
    - 分表
        1. 分区表的原理
        
        工作原理:创建表时使用partition by 子句定义每个分区存放的数据,执行查询时,优化器会根据分区定义过滤那些没有我们需要数据的分区,这样查询只需要查询所需数据在的分区即可
        
        限制:
            1. 一个表最多只能有1024个分区
            2. 分区字段中如果存在主键或者唯一索引列, 都必须包含进来
            3. 分区表中无法使用外键约束
            4. 需要对现有表的结构进行修改
            5. 所有分区都必须使用相同的存储引擎
            
        2. 分库分表的原理
        工作原理:通过一些hash算法活工具实现将一张数据表垂直或者水平进行物理切分
        
        使用场景:
            1. 单表记录条数达到百万至千万级别时
            2. 解决表锁‘
        
        分表方式:
            水平分割
            缺点:
            ① 给应用增加复杂度,通常查询时需要多个表名,查询所有数据都需要union操作
            ② 在许多数据库应用中,这种复杂性会超过它带来的优点,查询时会增加读一个索引层的磁盘次数
            
            垂直分表
            把主键和一些列放在一个表,然后把主键和另外的列放在另外一个表中
            使用场景:
            ① 如果一个表中某些列常用,而另外一些列不常用
            ② 可以使数据行变小,一个数据页能存储更多数据,查询时减少I/o次数
            
            缺点:
            ① 管理冗余列,查询所有数据需要join操作
            
    - 复制原理以及负载均衡    
    
        mysql 主从复制工作原理
            在主库上把数据更改记录到二进制日志,从库将主库的日志复制到自己的中继日志,从库读取中继日志中的事件,将其重放到从库数据中
            
        mysql主从复制解决的问题
        数据分布:随意停止或开始复制,并在不同地理位置分布数据备份
        负载均衡:降低单个服务器的压力
        
    - mysql 安全     
    1. 使用预处理语句处理sql语句,防止sql注入
    2. 写入数据库的数据要进行特殊字符的转义
    3. 查询错误的信息不要返回给用户, 将错误记录到日志
    
    - PHP操作数据库代码
    $dsn = 'mysql:dbname=test;host=localhost';
    $Username = 'test';
    $password = 'test';
    $attr  = [
        PDO::ATTR_ERRMODE => PDOERRMODE_EXCEPTION
    ];
    $pdo = new PDO($dsn, $username, $password, $attr);
    //$sql = 'SELECT id, title, content FROM message where user_name = :user_name' ;
    $sql = 'INSERT INTO message(title, content, create_at, user_name) values (:title, :content, :create_at, :user_name)';
    $stmt = $pdo->prepare($sql);
    $data = [
        ':title' => $title,
        ....
    ];
    $stmt->execute($data);
    $rows = $stmt->rowCount();
    if($rows){
        exit('添加成功');
    } else {
        exit('添加失败')
    }
    //$result = $stmt->fetchAll(PDO::FETCH_ASSOC);
    

练手

1. having 和 where
#查询两门及两门以上科目不及格的学生的平均分
思路:
#先计算所有学生的平均分
select name,avg(score) as pj from stu group by name;
#查出所有学生的挂科情况
select name,score<60 from stu;
#这里score<60是判断语句,所以结果为真或假,mysql中真为1假为0
#查出两门及两门以上不及格的学生
select name,sum(score<60) as gk from stu group by name having gk > 1;
#综合结果
select name,sum(score<60) as gk,avg(score) as pj from stu group by name having gk >1;

2. 

算法

    时间复杂度计算方式:T(n) = O(f(n))
        用常熟1取代所有时间中的所有加法常数
        在修改后的运行次数函数中,只保留最高阶项
        如果最高阶存在且不是1,则去除与这个项相乘的常数
        一般指最坏情况的时间复杂度
    举例:
    常数阶:O(1)
    线性阶:O(n)
    平(立)方阶:O(n^2)/O(n^3)
    对数阶:O(log2n)
    
    空间复杂度:算法要消耗的内存空间,S(n) = O(f(n))
    包括程序代码所占用的空间,输入数据所占用的空间,辅助变量所占用的空间这三个方面
    计算和表示方法与时间复杂度类似,一般用复杂度的渐进性来表示
    
    冒泡排序元素交换,空间复杂度O(1) 
    快速排序、归并排序的理想时间复杂度都是O(nlog2n), 但是快速排序的时间复杂度并不稳定,最坏情况下复杂度为O(n^2),所以最理想的算法还是归并排序

冒泡排序

 /**
   * 冒泡排序
   * bubble sort algorithm
   * 
   * @param  array $value 待排序数组 the array that is waiting for sorting
   * @return array
   */
  function bubble($value = [])
  {
      $length = count($value) - 1;
      // 外循环
      // outside loop
      for ($j = 0; $j < $length; ++$j) {
          // 内循环
          // inside loop
          for ($i = 0; $i < $length; ++$i) {
              // 如果后一个值小于前一个值,则互换位置
              // if the next value is less than the current value, exchange each other.
              if ($value[$i + 1] < $value[$i]) {
                  $tmp = $value[$i + 1];
                  $value[$i + 1] = $value[$i];
                  $value[$i] = $tmp;
              }
          }
      }
      return $value;
  }


  /**
   * 优化冒泡排序
   * optimized bubble sort algorithm
   * 
   * @param  array $value 待排序数组 the array that is waiting for sorting
   * @return array
   */
  function bubble_better($value = [])
  {
    $flag   = true; // 标示 排序未完成 the flag about the sorting is whether or not finished.
    $length = count($value)-1; // 数组最后一个元素的索引 the index of the last item about the array.
    $index  = $length; // 最后一次交换的索引位置 初始值为最后一位 the last exchange of index position, default value is equal to the last index.
    while ($flag) {
      $flag = false; // 假设排序已完成 let's suppose the sorting is finished.
      for ($i=0; $i < $index; $i++) {
        if ($value[$i] > $value[$i+1]) {
          $flag  = true; // 如果还有交换发生,则排序未完成  if the exchange still happen, it show that the sorting is not finished. 
          $last  = $i; // 记录最后一次发生交换的索引位置 taking notes the index position of the last exchange.
          $tmp   = $value[$i];
          $value[$i] = $value[$i+1];
          $value[$i+1] = $tmp;
        }
      }
      $index = !$flag ? : $last;
    }
    return $value;
  }

快速排序

<?php
/**
 * php算法实战.
 *
 * 排序算法-快速排序
 *
 * @author TIGERB <https://github.com/TIGERB>
 */
 /**
  * 快速排序.
  *
  * @param  array $value 待排序数组
  * @param  array $left  左边界
  * @param  array $right 右边界
  *
  * @return array
  */
  function quick(&$value, $left, $right)
  {
    // 左右界重合 跳出
    if ($left >= $right) {
      return;
    }
    $base = $left;
    do {
      // 从最右边开始找到第一个比基准小的值,互换位置
      // 找到基准索引为止
      for ($i=$right; $i > $base; --$i) {
        if ($value[$i] < $value[$base]) {
          $tmp = $value[$i];
          $value[$i] = $value[$base];
          $value[$base] = $tmp;
          $base = $i; // 更新基准值索引
          break;
        }
      }
      // 从最左边开始找到第一个比基准大的值,互换位置
      // 找到基准索引为止
      for ($j=$left; $j < $base; ++$j) {
        if ($value[$j] > $value[$base]) {
          $tmp = $value[$j];
          $value[$j] = $value[$base];
          $value[$base] = $tmp;
          $base = $j; // 更新基准值索引
          break;
        }
      }
    } while ($i > $j);// 直到左右索引重合为止
    // 开始递归
    // 以当前索引为分界
    // 开始排序左部分
    quick($value, $left, $i-1);
    // 开始排序右边部分
    quick($value, $i+1, $right);
    return $value;
  }
  /**
   * 快速排序.while版本
   *
   * @param  array $value 待排序数组
   * @param  array $left  左边界
   * @param  array $right 右边界
   *
   * @return array
   */
  function quick_while(&$value, $left, $right)
  {
    // 左右界重合 跳出
    if ($left >= $right) {
      return;
    }
    $point = $left;
    $i = $right;
    $j = $left;
    while ($i > $j) {
      //查右边值
      while ($i > $point) {
        if ($value[$i] < $value[$point]) {
          $tmp = $value[$i];
          $value[$i] = $value[$point];
          $value[$point] = $tmp;
          $point = $i;
          break;
        }
        --$i;
      }
      //查左边值
      while ($j < $point) {
        if ($value[$j] > $value[$point]) {
          $tmp = $value[$j];
          $value[$j] = $value[$point];
          $value[$point] = $tmp;
          $point = $j;
          break;
        }
        ++$j;
      }
    }
    // 开始递归
    // 以当前索引为分界
    // 开始排序左部分
    quick_while($value, $left, $i-1);
    // 开始排序右边部分
    quick_while($value, $i+1, $right);
    return $value;
  }

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章