# 01 課程介紹 #
## 1-1 課程介紹 ##
本課程以作者5年的行業招聘經驗和8年的開發和培訓經驗,講述就業面試的答案。
各大企業常見的PHP面試題
- 面試考點
- 考官考察思路
- 復習PHP面試考點
- 總結面試難點
- 掌握解題方法和技巧
- 挖掘知識點
- 面試官的角度
- 深度剖析知識點
- 一網打盡所有考點內容
一句話:全面的剖析面試題和面試技巧,快速的提升技能以及面試技巧,找到更好的工作。
### 95%以上的PHP面試考察點
- PHP基礎知識
- JavaScript,jQuery,Ajax基礎知識
- Linux基礎知識
- MySQL數據庫的基礎與優化
- 程序設計題
- PHP框架基礎知識
- 算法、邏輯思維
- 高并發解決方案
## 1-2 怎樣看待面試這回事 ##
面試是一個程序員生涯開始必須要經歷的過程,也是證明自我、體現自我價值的敲門磚,我們的課程重點引領大家用好“自身技術”撬開步入理想企業的勝利之門。
面試基本流程
1. 篩選個人簡歷(HR,技術Leader)
- 基本信息
- 掌握技能(重要)
- 項目經驗
2. 進行技術面試(電話面試,facetoface)
3. 商議薪資待遇,雙方達成共識(HR)
4. 辦理入職流程,上崗
面試前需要了解的
- PHP市場需求
- 為什么還是找不到工作(技術要點復習)
- 技術能力為核心
求職者的七個等級階段
- PHP愛好者
- 初學者
- 初級程序員
- 中級程序員
- 高級程序員
- 服務端技術專家
- 架構師
## 1-3 基礎的重要性 ##
重要性:
- 以基礎為前提的面試考察
- 堅實基礎的重要性
- 保持謙卑之心
### 常見經典面試題
- 什么是引用變量,在PHP當中,用什么符號定義引用變量?
- 要求寫出jQuery中,可以處理Ajax的幾種方法。
- 寫出盡可能多的Linux命令
- 寫出三種以上MySQL數據庫存儲引擎的名稱
- 編寫一個在線留言本,實現用戶的在線留言功能
- 談談你對MVC的認識,介紹幾種目前比較流行的MVC框架
- 請寫出常見的排序算法
- PHP中如何解決網站的大流量與高并發的問題
## 1-4 透過現象看本質 ##
解題思路和技巧
- 回憶知識點
- 揣測面試官的考察思路
- 量的前提是精
# 第2章 PHP基礎知識考察點 #
## 2-1至2-2 PHP引用變量考察點 ##
全方位剖析三大步驟:
- 回顧真題
- 考點分析
- 一網打盡
回顧真題:
什么是引用變量?在PHP中用什么符號定義引用變量。
考官分析:
- PHP的引用變量的概念和定義方式。
- 延伸:PHP引用變量的原理
概念:
在PHP中引用意味著用不同的名字訪問同一個變量內容。
定義方式:
使用符號&
工作原理:
代碼實例...
階梯方法:
畫圖分析法
一網打盡:
真題
## 2-3 常量及數據類型考察點##
回顧真題:
PHP中字符串可以使用哪三種定義方法以及各自的區別是什么?
考官分析:
PHP的字符串的定義方式及各自區別。
延伸:PHP數據類型及常量
PHP中定義字符串的三種方式:
- 單引號
- 雙引號
- heredoc和newdoc
單引號區別:
- 單引號不能解析變量
- 單引號不能解析轉義字符,只能解析單引號和反斜線本身
- 變量和變量、變量和字符串、字符串和字符串之間可以用.連接
- 單引號效率更高
雙引號區別:
- 雙引號可以解析變量,變量可以使用特殊字符和{}包含
- 雙引號可以解析所有轉義字符
- 也可以用.來連接
實例
....
doc區別:
- Heardoc類似于雙引號
- Newdoc類似于單引號
- 兩者主要用于處理大文本
實例
...
知識點延伸:數據類型
- 三大數據類型(標量、復合、特殊)
- 浮點:浮點類型不能用于比較運算符,例如:(0.1+0.7)==0.8 返回值是FALSE
- 布爾類型:FALSE的七種情況。0,0.0,' ','0',false,array(),NULL
- 數組類型:超全局數組。$GLOBALS, $_GET, $_POST, $_REQUEST, $_SESSION, $_COOKIE, $_SERVER, $_FILES, $_ENV。
- NULL:三種情況,直接賦值NULL,未定義變量,unset銷毀的變量。
- 常量:定義const, define。const更快,是語言結構,define是函數。define不能用于類常量的定義,const可以。常量一旦定義,不可以被修改和刪除。
- 預定義常量:__FILE__, __DIR__, __LINE__, __FUNCTION__, __CLASS__, __TARIT__, __METHOD__, __NAMESPACE__。
備注:記住`$_SERVER`的一些選項。
解題方法:
總之常用知識點進行梳理和復習,“牢記”。
一網打盡:
- 用PHP寫出顯示客戶端IP與服務器IP的代碼。
- `__FILE__`表示什么意思?
## 2-4 運算符考察點##
回顧真題:
foo()和@foo()之間的區別。
考官分析:
- PHP的運算符和錯誤控制符@
- 延伸:PHP的所有運算符
- 運算符的優先級
- 比較運算符
- 邏輯運算符
- 遞增/遞減運算符
...
一網打盡:
真題...
## 2-5 流程控制考察點##
回顧真題:
請列出3種PHP數組循環操作的語法,并注明各種循環的區別。
考官考點:
一網打盡:
PHP中如何優化多個if...else語句的情況?
- 將可能性較大的條件盡可能往前挪;
- 如果條件表達式的結果為:字符串、浮點數或整型,則可以使用switch...case。
## 2-6至2-7 自定義函數及內部函數考察點(上)##
考官考點:
- 變量的作用域和靜態變量
- 延伸:函數的參數及參數的引用傳遞
- 延伸:函數的返回值及引用返回
- 延伸:外部文件的導入
- 延伸:系統內置函數
## 2-8 正則表達式考察點##
回顧真題:
至少寫出一種驗證139開頭的11位手機號碼的正則表達式
考官考點:
- 手機號碼的正則表達式編寫
- 正則表達式的組成及編寫方法
正則表達式知識點:
- 正則表達式的作用:分割、查找、匹配、替換字符串。
- 分隔符:正斜線/,hash符號#, 以及取反符號~
- 通用原子:\d, \D, \w, \W, \s, \S
- 元字符:. * ? ^ $ + {n} {n,} {n,m} `[]` `()` [^] | [-]
- 模式修正符:i m e s U x A D u
## 2-9 文件及目錄處理相關考點##
回顧真題:
不斷在文件hello.txt頭部寫入一行"hello world"字符串,要求代碼完整。
考官考點:
- 文件讀取與寫入操作
- 延伸:
## 2-10 會話控制技術##
回顧真題:
簡述cookie和session的區別及各自的工作機制,存儲位置等,簡述cookie的優缺點。
考官考點:
- PHP的會話控制技術
為什么要使用會話控制技術?
## 2-11 面向對象考點## 模塊
回顧真題:
請寫出PHP類權限控制修飾符
考官考點:
- PHP的類權限控制修飾符
- 延伸:面向對象的封裝、繼承和多態
- 延伸:魔術方法
- 延伸:設計模式
## 2-12 網絡協議考察點##
回顧真題:
HTTP/1.1中,狀態碼200, 301, 304, 403, 404, 500的含義。
考官考點:
- HTTP協議狀態碼
- 延伸:OSI七層模型
- 延伸:HTTP協議的工作特點和工作原理
- 延伸:HTTP協議常見請求/響應頭和請求方法
- 延伸:HTTPs協議的工作原理
- 延伸:常見網絡端口協議含義及端口
## 2-13 開發環境及配置相關考點##
回顧真題:
您是否使用過版本控制軟件?如果有您用的版本控制軟件的名字是什么?
# 第3章 JavaScript、jQuery以及AJAX基礎考察點 #
## 3-1 JavaScript和jQuery基礎考察點 ##
回顧真題:
下列不屬于JavaScript語法關鍵/保留字的是(var, $, function, while)
考官考點:
- JavaScript基本語法
- 延伸:JavaScript內置對象
- 延伸:JavaScript HTML DOM對象
- 延伸:jQuery基礎知識
### JavaScript基礎語法
變量的定義:
變量必須以字母開頭
變量也能以$和_開頭
變量名稱對大小寫敏感
使用關鍵字var來聲明變量
可以在一條語句中聲明多個變量
未使用值來聲明的變量,值是undefined
如果重新聲明javascript變量,該變量的值不會丟失
var a=1;
var a;
數據類型:
字符串、數字、布爾、數組、對象、Null、undefined
JavaScript變量均為對象,當您聲明了一個變量,就聲明了一個對象
創建對象:
new Object()
使用對象構造器
使用JSON對象
函數:
定義函數
無默認值
函數內部聲明的變量是局部變量
在函數外部聲明的變量是全局變量,所有腳本和函數都能訪問它
運算符:
+號用來拼接字符串
流程控制:
else if必須分開寫
### 延伸:JavaScript內置對象
Number
var pi = 3.14;
var myNum = new Number(value);
var myNum = Number(value);
String
var str = 'This is String';
var str = new String(s);
var str = String(s);
Boolean
var bol = true;
var bol = new Boolean(value);
var bol = Boolean(value);
Array
var arr = new Array();
var arr = new Array(size);
var arr = new Array(e1,e2,e3,...en);
Date
var date = new Date();
Math
var pi_value = Math.PI;
var sqrt_value = Math.sqrt(15);
RegExp
/pattern/attributes
new RegExp(pattern, attributes);
### 延伸:JavaScript Window對象
Window對象
Window, Navigator, Screen, History, Location
### 延伸:JavaScript HTML DOM對象
DOM對象
Dcoument, Element, Attr, Event
### 延伸:jQuery基礎知識
jQuery選擇器:
基本選擇器,層次選擇器,過濾選擇器,可見性過濾選擇器,屬性過濾選擇器,子元素過濾選擇器,表單對象屬性過濾選擇器
jQuery事件:
$("button").click(function(){...do somthing...})
jQuery效果:
$("p").show()
jQuery DOM操作:
屬性,值,節點,CSS,尺寸
### 解題方法
牢記以上基礎知識點,比較常考察的是JavaScript的HTML樣式操作以及jQuery的選擇器和事件、樣式操作。
document.getElementById('test').className = 'good'
### 一網打盡
JavaScript中的id為test的元素設置樣式為good;
要求使用jQuery事件寫在頁面元素加載完成后,動態綁定click事件到btnOk元素;
$(function(){
$(".btnOk").click(function(){
...
})
});
## 3-2 AJAX基礎內容考察點 ##
回顧真題:
Ajax技術利用了什么協議?簡述Ajax的工作機制?
考官考點:
- Ajax的基本工作原理
- 延伸:jQuery的Ajax操作
### Ajax的基本工作原理
Ajax基礎概念:
Asynchronous JavaScript and XML
通過在后臺與服務器進行少量數據交換,AJAX可以使網頁實現異步更新;
Ajax工作原理:
XMLHttpRequest是Ajax的基礎
XMLHttpRequest用于在后臺與服務器交換數據
XMLHttpRequest對象請求:
open(method, url, async)
XMLHttpRequest對象響應:
- responseText
- responseXML
- onreadystatechange
- readyState: 0(請求未初始化) 1(服務器連接已建立) 2(請求已接收) 3(請求處理中) 4(請求已完成,且響應已就緒)
- status: 200, 400
### 延伸:jQuery的Ajax操作
常用方法:
$(ele).load(), $.ajax(), $.get(), $.post(), $.getJSON(), $.getScript()
### 解題方法
理解AJXA工作原理,這也是與面試官面聊時可能會被問到的;
牢記jQuery的AJAX操作方法,遇到AJAX編程題,先考慮jQuery的AJAX操作方式,判斷是GET還是POST請求,然后選擇對應的方法,通常不會考察JavaScript的原生操作方式;
### 一網打盡
要求寫出jQuey中,可以處理AJAX的幾種方法。
# 第4章 Linux基礎考察點 #
## 4-1 Linux基礎考察點 ##
回顧真題:
寫出盡可能多的Linux命令。
考官考點:
- Linux常用命令
- 延伸:系統定時任務
- 延伸:vi/vim編輯器
- 延伸:shell基礎
## Linux常用命令
### 進程管理
w, top, ps, kill, pkill, pstree, killall
### 用戶管理
id, usermod, useradd, groupadd, userdel
### 文件系統
mount, umount, fsck, df, du
### 網絡應用
### 網絡測試
### 網絡配置
hostname, ifconfig
### 常用工具
ssh, screen, clear, who, date
### 軟件包管理
yum, rpm, apt-get
### 文件查找和比較
locate, find
### 文件內容查看
head, tail, less, more
### 文件處理
touch, unlink, rename, ln, cat
### 目錄操作
cd, mv, rm, pwd, tree, cp, ls
### 文件權限屬性
setfacl, chmod, chown, chgrp
## 延伸:系統定時任務
crontab -e
* * * * * 命令(分 時 日 月 周)
at命令:
# at 2:00 tomorrow
at> /home/Jason/do_job
at> Ctrl+D
## 延伸:vi/vim編輯器
一般模式:
- 一般模式,編輯模式,命令行模式
- 一般模式:刪除,復制和粘貼
- 切換編輯模式:i, I, o, O, a, A, r, R
- 切換命令行模式::, /, ?
移動光標:
ctrl+f, ctrl+d, 0或者Home,$或者END,G,gg,N+enter
查找和替換:
/word, ?word, :n1,n2s/word1/word2/g
:1,$s/word1/word2/g
:1,$s/word1/word2/gc
刪除、復制和粘貼:
x,X dd, ndd, yy, nyy, p, P, ctrl+r, .
保存退出:
w, q, wq
配置行號:
:setnu, :setnonu
## 延伸:shell基礎
腳本執行方式
賦予權限,直接執行,例如:chmod +x test.sh; ./test.sh
調用解釋器使得腳本執行,例如:bash, csh, ash, bsh, ksh等等;
編寫基礎:
開頭用#!指定腳本解釋器,如:#!/bin/sh
編寫具體功能
## 解題方法
牢記以上知識點
## 一網打盡
如何實現每天0點重新啟動服務器
crontab -e
0 0 * * * reboot
# 第5章 MySQL數據庫考察點 #
## 5-1 MySQL數據庫基礎考察點 ##
回顧真題:
- 請寫出下面MySQL數據類型表達的意義: int(0), char(16), varchar(16), datetime, text
考官考點:
- MySQL數據類型
- 延伸:MySQL基礎操作
- 延伸:MySQL存儲引擎
- 延伸:MySQL鎖機制
- 延伸:MySQL事務處理、存儲過程、觸發器
### MySQL數據類型:
整數類型:
- TINYINT,SMALLINT,MEDIUMINT,INT,BIGINT
- 屬性:UNSIGNED
- 長度:可以為整數指定寬度,例如:INT(11),對大多數應用是沒有意義的,它不會限制值的合法范圍,只會影響顯示字符的個數,配合ZEROFILL使用。
實數類型:
- 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不容易產生碎片;
- 對于非常短的列,CHAR比VARCHAR在存儲空間上更有效率;
- 只分配真正需要的空間,更長的列會消耗更多的內存;
- 盡量避免使用BLOB/TEXT類型,查詢會使用臨時表,導致嚴重的性能開銷;
枚舉:
- 有時可以使用枚舉代替常用的字符串類型
- 把不重復的集合存儲成一個預定義的集合
- 非常緊湊,把列表值壓縮到一個或兩個字節
- 內部存儲的是整數
- 盡量避免使用數字作為ENUM枚舉的常量,易混亂
- 排序是按照內部存儲的整數進行排序
- 枚舉表會使表大小大大減少
日期和時間類型:
- 盡量使用TIMESTAMP,比DATETIME空間效率高
- 用整數保存時間戳的格式通常不方便處理
- 如果需要存儲微秒,可以使用bigint存儲
列屬性:
- auto_increment, default, not null, zerofill
常見操作:
- MySQL的連接和關閉:mysql -u -p -h -p
- 其他:\G, \c, \q, \s, \h, \d
InnoDB表引擎:
- 默認事務型引擎,最重要最廣泛的存儲引擎,性能非常優秀
- 數據存儲在共享表空間,可以通過配置分開
- 對主鍵查詢的性能高于其他類型的存儲引擎
- 內部做了很多優化,從磁盤讀取數據時自動在內存構建hash索引
- 插入數據時自動構建插入緩沖區
- 通過一些機制和工具支持真正的熱備份
- 支持崩潰后的安全恢復
- 支持行級鎖
- 支持外鍵
MyISAM表引擎:
- 5.1版本前,MyISAM是默認的存儲引擎
- 擁有全文索引,壓縮,空間函數
- 不支持事務和行級鎖,不支持崩潰后的安全恢復
- 表存儲在兩個文件,MYD和MYI
- 設計簡單,某些場景下性能很好
其他表引擎:
- Archive, Blackhole, CSV, Memory
- 優先選擇InnoDB
基礎概念:
- 表鎖是日常開發當中常見的問題,因此也是面試中最常見的考察點,當多個查詢同一時刻進行數據修改時,就會產生并發控制的問題。
寫鎖:
- 排他的,一個寫鎖會阻塞其他的寫鎖和讀鎖,這樣可以只允許一個人進行寫入,防止其他用戶讀取正在寫入的資源。
鎖粒度:
- 表鎖,系統性能開銷最小,會鎖定整張表,MyISAM使用表鎖行鎖,最大程度地支持并發處理,但是也帶來了最大的鎖開銷,InnoDB實現行級鎖。
事務處理:
- MySQL提供事務處理的表引擎,InnoDB
- 服務器層不管理事務,由下層的引擎實現,所以在同一個事務中,使用多種存儲引擎不靠譜,在非事務的表上執行事務操作MySQL不會發出提醒,也不會報錯。
MySQL存儲過程:
- 為以后的使用而保存的一條或者多條MySQL語句的集合
- 存儲過程就是有業務邏輯和流程的集合
- 可以在存儲過程中創建表,更新數據,刪除等等
MySQL存儲過程使用場景:
- 通常把處理封裝在容易使用的單元中,簡化復雜的操作
- 保證數據的一致性
- 簡化對變動的管理
觸發器:
- 提供給程序員和數據分析員來保證數據完整性的一種方法,它是與表事件相關的特殊的存儲過程。
觸發器使用場景:
- 可通過數據庫中的相關表實現級聯更改
- 實現監控某張表中的某個字段的更改而需要作出相應的處理
- 某些業務編號的生成
- 濫用會造成數據庫及應用程序的維護困難
解題方法:
- 牢記以上基礎知識點,理解數據類型Char和Varchar的差異,表存儲引擎InnoDB和MyISAM的區別。
## 5-2 MySQL創建高性能的索引考察點 ##
回顧真題:
簡單描述MySQL中,索引、主鍵、唯一索引、聯合索引的區別,對數據庫的性能有什么影響?
考官考點:
- MySQL索引的基礎和類型
- 延伸:MySQL索引的創建原則
- 延伸:MySQL索引的注意事項
### MySQL索引的基礎和類型
索引的基礎
- 索引類似于書籍的目錄,要想找到一本書的某個主題,需要先找到書的目錄,定位對應的頁碼。
- 存儲引擎使用類似的方式進行數據查詢,先去索引當中找到對應的值,然后根據匹配的索引找到對應的數據行。
索引對性能的影響
- 大大減少服務器需要掃描的數據量
- 幫助服務器避免排序和臨時表
- 將隨機I/O變順序I/O
- 大大提高查詢速度,降低寫的速度,占用磁盤
索引的使用場景
- 對于非常小的表,大部分情況下全表掃描效率最高
- 中到大型表索引非常有效
- 特大型的表,建立和使用索引的代價將隨之增長,可以使用分區技術來解決
索引的類型
- 索引有很多類型,都是實現在存儲引擎層的
- 普通索引:最基本的索引,沒有任何約束限制
- 唯一索引:與普通索引類似,但是具有唯一性約束
- 主鍵索引:特殊的唯一索引,不允許有空值
- 一個表只能有一個主鍵索引,可以有多個唯一索引
- 主鍵索引一定是唯一索引,唯一索引不是主鍵索引
- 主鍵可以與外鍵構成參照完整性約束,防止數據不一致
- 組合索引:將多個列組合在一起創建索引,可以覆蓋多個列
- 外鍵索引:只有InnoDB類型的表才可以使用外鍵索引,保證數據的一致性,完整性和實現級聯操作
- 全文索引:MySQL自帶的全文索引只能用于MyISAM,并且只能對英文進行全文檢索
### 延伸:MySQL索引的創建原則
原則
- 最適合索引的列是出現在WHERE子句中的列,或連接子句中的列而不是出現在SELECT后面的列
- 索引列的基數越大,索引的效果越好
- 對字符串進行索引,應該制定一個前綴長度,可以節省大量的索引空間
- 根據情況創建復合索引,復合索引可以提高查詢效率
- 避免創建過多索引,索引會額外占據磁盤空間,降低寫操作效率
- 主鍵盡可能選擇較短的數據類型,可以有效減少索引的磁盤占用提高查詢效率
### 延伸:MySQL索引的注意事項
注意
- 復合索引遵循前綴原則
- like查詢,%不能在前,可以使用全文索引
- column is null可以使用索引
- 如果MySQL估計使用索引比全表掃描更慢,會放棄使用索引
- 如果or前的條件中的列有索引,后面的沒有,索引都不會被用到
- 列類型是字符串,查詢時一定要給值加上引號,否則索引失效
### 解題方法
在一些MySQL索引基礎考題中,我們可以輕松的通過索引基礎和類型來解決此類問題,對于一些索引創建注意事項方面的考點,我們可以通過索引創建原則和注意事項來解決。
### 一網打盡
創建MySQL復合索引應該注意哪些事項?
## 5-3 MySQL的SQL語句編寫考察點 ##
回顧真題:
有A(id,sex,par,c1,c2),B(id,age,c1,c2)兩張表,其中A.id與B.id關聯,現在要求寫一條SQL語句,將B中age>50的記錄的c1,c2更新到A表中統一記錄的c1,c2字段中。
考官考點:
- MySQL的關聯UPDATE語句
- 延伸:MySQL的關聯查詢語句
### MySQL的關聯UPDATE語句
UPDATE A,B SET A.c1=B.c1,A.c2=B.c2 WHERE A.id=B.id and ...
UPDATE A INNER JOIN B ON A.id=B.id SET A.c1=B.c1,A.c2=B.c2 WHERE ...
### 延伸:MySQL的關聯查詢語句
六種關聯查詢:
交叉連接(CROSS JOIN)
內連接(INNER JOIN)
外連接(LEFT JOIN/RIGHT JOIN)
聯合查詢(UNION與UNION ALL)
全連接(FULL JOIN)
交叉連接
SELECT * FROM A,B(,C) 或者 SELECT * FROM A CROSS JOIN B (CROSS JOIN C)
沒有任何關聯條件,結果是笛卡爾積,結果集會很大,沒有意義,很少使用。
內連接
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
INNER JOIN 可以縮寫為 JOIN
外連接 > 左外連接
LEFT OUTER JOIN, 以左表為主,先查詢出左表,按照ON后的關聯條件匹配右表,沒有匹配到的用NULL填充,可以簡寫成LEFT JOIN
外連接 > 右外連接
RIGHT OUTER JOIN, 以右表為主,先查詢出右表,按照ON后的關聯條件匹配左表,沒有匹配到的用NULL填充,可以簡寫成RIGHT JOIN
聯合查詢
SELECT * FROM A UNION SELECT * FROM B UNION ...
就是把多個結果集集中在一起,UNION前的結果為基準,需要注意的是聯合查詢的列數要相等,相同的記錄行會合并,如果使用UNINON ALL不會合并重復的記錄行。
全連接
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
嵌套查詢
用一條SQL語句的結果作為另外一條SQL語句的條件
SELECT * FROM A WHERE id IN (SELECT id FROM B)
### 解題方法:
根據考題要搞清楚表的結構和多表之間的關系,根據想要的結果思考使用哪種關聯方式,通常把要查詢的列先寫出來,然后分析這些列都屬于哪些表,才考慮使用關聯查詢。
### 一網打盡:
為了記錄足球比賽的結果,設計表如下:
team表:
CREATE TABLE `team`(
`teamID` int unsigned NOT NULL AUTO_INCREMENT PRIMARY KEY,
`teamName` varchar(20) NOT NULL
)ENGINE=InnoDB DEFAULT CHARSET=utf8;
match表:
CREATE TABLE `match`(
`matchID` int unsigned NOT NULL AUTO_INCREMENT PRIMARY KEY,
`hostTeamID` int NOT NULL,
`guestTeamID` int NOT NULL,
`matchResult` varchar(20) NOT NULL,
`matchTime` timestamp NOT NULL
)ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `match`
(hostTeamID, guestTeamID, matchResult, matchTime) VALUES
(1, 2, '1:1', '2018-09-23 18:00'),
(2, 1, '2:1', '2018-09-30 18:00'),
(1, 3, '3:1', '2018-09-23 18:00'),
(1, 4, '4:0', '2018-09-23 18:00'),
(1, 5, '0:4', '2018-09-23 18:00'),
(1, 6, '2:2', '2018-09-23 18:00'),
(1, 7, '3:1', '2018-09-23 18:00');
其中,match賽程表中的hostTeamID和guestTeamID都和team表中的teamID關聯,查詢出2016-6-1至2016-7-1之間所有的比賽,并且用以下形式列出:拜仁 2:0 不萊梅 2006-6-21
SELECT T1.teamName, M.matchResult, T2.teamName, M.matchTime FROM `match` M LEFT JOIN `team` T1 ON T1.teamID=M.hostTeamID LEFT JOIN `team` T2 ON T2.teamID=M.guestTeamID WHERE M.matchTime between '2018-09-01' and '2018-09-30';
## 5-4 MySQL的查詢優化考察點 ##
回顧真題:
請簡述項目中優化SQL語句執行效率的方法,從哪些方面,SQL語句性能如何分析?
考官考點:
- 查找分析查詢速度慢的原因
- 優化查詢過程中的數據訪問
- 優化長難的查詢語句
- 優化特定類型的查詢語句
### 查找分析查詢速度慢的原因
分析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
分析單條SQL語句
### 優化查詢過程中的數據訪問
訪問數據太多導致查詢性能下降
確定應用程序是否在檢索大量超過需要的數據,可能是太多行或列
確認MySQL服務器是否在分析大量不必要的數據行
避免使用如下SQL:
- 查詢不需要的記錄,使用limit
- 多表關聯返回全部列,指定A.id,A.name,B.age
- 總是取出全部列,`SELECT *` 會讓優化器無法完成索引覆蓋掃描的優化
- 重復查詢相同的數據,可以緩存數據,下次直接讀取緩存
是否在掃描額外的記錄:
- 使用explain來進行分析,如果發現查詢需要掃描大量的數據但只返回少數的行,可以通過如下技巧去優化:
- 使用索引覆蓋掃描,把所有用的列都放到索引中,這樣存儲引擎不需要回表獲取對應行就可以返回結果;
- 改變數據庫和表的結構,修改數據表范式;
- 重寫SQL語句,讓優化器可以以更優的方式執行查詢;
### 優化長難的查詢語句
一個復雜查詢還是多個簡單查詢:
- MySQL內部每秒能掃描內存中上百萬行數據,相比之下,響應數據給客戶端就要慢得多;
- 使用盡可能少的查詢是好的,但是有時將一個大的查詢分解為多個小的查詢是很有必要的;
切分查詢:
- 將一個大的查詢分為多個小的相同的查詢
- 一次性刪除1000萬的數據要比一次刪除1萬,暫停一會的方案更加損耗服務器開銷
分解關聯查詢:
- 可以將一條關聯語句分解成多條SQL來執行
- 讓緩存的效率更高
- 執行單個查詢可以減少鎖的競爭
- 在應用層做關聯可以更容易對數據庫進行拆分
- 查詢效率會有大幅提升
- 較少冗余記錄的查詢
### 優化特定類型的查詢語句
優化count()查詢:
- `count(*)`中的`*`會忽略所有的列,直接統計所有的列數,因此不要使用`count(列名)`
- MyISAM中,沒有任何WHERE條件的`count(*)`非常快
- 當有WHERE條件,MyISAM的count統計不一定比其他表引擎快
優化關聯查詢:
- 確保ON或者USING子句的列上有索引
- 確保GROUP BY和ORDER BY中只有一個表中的列,這樣MySQL才有可能使用索引
優化子查詢:
- 盡可能使用關聯查詢來替代
優化GROUP BY和DISTINCT:
- 這兩種查詢均可使用索引來優化,是最有效的優化方法
- 關聯查詢中,使用標識列進行分組的效率會更高
- 如果不需要ORDER BY,進行GROUP BY時使用ORDER BY NULL,MySQL不會再進行文件排序
- WITH ROLLUP超級聚合,可以挪到應用程序處理
優化LIMIT分頁:
- LIMIT偏移量大的時候,查詢效率較低
- 可以記錄上次查詢的最大ID,下次查詢時直接根據該ID來查詢
優化UNION查詢:
- UNION ALL的效率高于UNION
### 解題方法
對于此類考題,先說明如何定位低效SQL語句,然后根據SQL語句可能低效的原因做排查,先從索引著手,如果索引沒有問題,考慮以上幾個方面,數據訪問的問題,長難查詢句的問題還是一些特定類型優化的問題,逐一回答。
### 一網打盡
SQL語句優化的有些方法
## 5-5 MySQL的高可擴展和高可用考察點 ##
### 回顧真題
簡述MySQL分表操作和分區的工作原理,分別說說分區和分表的使用場景和各自優缺點。
### 考官考點
- 分區表的原理
- 分庫分表的原理
- 延伸:MySQL的復制原理及負載均衡
#### 分區表的原理:
工作原理:
對用戶而言,分區表是一個獨立的邏輯表,但是底層MySQL將其分成了多個物理子表,這對用戶來說是透明的,每一個分區表都會使用一個獨立的表文件。
創建表時使用partition by子句定義每個分區存放的數據,執行查詢時,優化器會根據分區定義過濾那些沒有我們需要數據的分區,這樣查詢只需要查詢所需數據在的分區即可。
分區的主要目的是將數據按照一個較粗的粒度分在不同的表中,這樣可以將相關的數據存放在一起,而且如果想一次性刪除整個分區的數據也很方便。
適用場景:
1. 表非常大,無法全部存在內存,或者只在表的最后有熱點數據,其他都是歷史數據
2. 分區表的數據更易維護,可以對獨立的分區進行獨立的操作
3. 分區表的數據可以分布在不同的機器上,從而高效使用資源
4. 可以使用分區表來避免某些特殊的瓶頸
5. 可以備份和恢復獨立的分區
限制:
1. 一個表最多只能有1024個分區
2. 5.1版本中,分區表表達式必須是整數,5.5可以使用列分區
3.
4. 分區表中無法使用外鍵約束
5. 需要對現有表的結構進行修改
6. 所有分區都必須使用相同的存儲引擎
7. 分區函數中可以使用的函數和表達式會有一些限制
8. 某些存儲引擎不支持分區
9. 對于MyISAM的分區表,不能使用load index into cache
10. 對于MyISAM表,使用分區表時需要打開更多的文件描述符
#### 分庫分表的原理:
工作原理:
通過一些HASH算法或者工具實現將一張數據表垂直或者水平進行物理切分。
適用場景:
1. 單表記錄條數達到百萬到千萬級別時
2. 解決表鎖的問題
分表方式:水平分割
表很大,分割后可以降低在查詢時需要讀的數據和索引的頁數,同時也降低了索引的層數,提高查詢速度。
圖1
適用場景:
1. 表中的數據本身就有獨立性,例如表中分別記錄各個地區的數據或者不同時期的數據,特別是有些數據常用,有些不常用
2. 需要把數據存放在多個介質上
水平分表缺點:
1. 給應用增加復雜度,通常查詢時需要多個表名,查詢所有數據都需UNION操作。
2. 在許多數據庫應用中,這種復雜性會超過它帶來的優點,查詢時會增加讀一個索引層的磁盤次數
分表方式:垂直分表
把主鍵和一些列放在一個表,然后把主鍵和另外的列放在另一個表中
圖2
使用場景:
1. 如果一個表中某些列常用,而另外一些列不常用
2. 可以使數據行變小,一個數據頁能存儲更多的數據,查詢時減少I/O次數
垂直分表缺點:
管理冗余列,查詢所有數據需要JOIN操作
分表缺點:
- 有些分表的策略基于應用層的邏輯算法,一旦邏輯算法該表,整個分表邏輯都會改變,擴展性較差
- 對于應用層來說,邏輯算法無疑增加開發成本
#### 延伸:MySQL的復制原理及負載均衡:
MySQL主從復制工作原理:
- 在主庫上把數據更改記錄到二進制日志
- 從庫將主庫的日志復制到自己的中繼日志
- 從庫讀取中繼日志中的事件,將其重放到從庫數據中
MySQL主從復制解決的問題:
- 數據分布:隨意停止或開始復制,并在不同地理位置分布數據備份
- 負載均衡:降低單個服務器的壓力
- 高可用和故障切換:幫助應用程序避免單點失敗
- 升級測試:可以使用更高版本的MySQL作為從庫
### 解題方法
充分掌握分區和分表的工作原理和適用場景,在面試中,此類考題通常比較靈活,會給一些現有公司遇到的問題的場景,大家可以根據分區和分表以及MySQL復制、負載均衡的適用場景來根據情況進行回答。
### 一網打盡
設定網站的用戶數量在千萬級,但是活躍用戶的數量只有1%,如何通過優化數據庫提高活躍用戶的訪問速度?
## 5-6 MySQL的安全性考察點 ##
### 回顧真題
SQL語句應該考察哪些安全性?
### 考官考點
- SQL查詢的安全方案
- 延伸:MySQL的其他安全設置
#### SQL查詢的安全方案
1. 使用預處理語句防止SQL注入
2. 寫入數據庫的數據要進行特殊字符的轉義
3. 查詢錯誤信息不要返回給用戶,將錯誤記錄到日志
delete from user where id=1 or 1=1;
/user/delete?id=1
/user/delete?id=1 or 1=1
注意:
PHP端盡量使用PDO對數據庫進行相關操作,PDO擁有對預處理語句很好的支持的方法,MySQLi也有,但是可擴展性不如PDO,效率略高于PDO,MySQL函數在新版本中已經趨向于淘汰,所以不建議使用,而且它沒有很好的支持預處理的方法。
#### 延伸:MySQL的其他安全設置
1. 定期做數據備份
2. 不給查詢用戶root權限,合理分配權限
3. 關閉遠程訪問數據庫權限
4. 修改root口令,不用默認口令,使用較復雜的口令
5. 改變root用戶的名稱
6. 限制一般用戶瀏覽其他庫
7. 限制用戶對數據文件的訪問權限
### 解題方法
通常情況下,SQL安全的考點都在防SQL注入的問題,因此只要遇到此類考點,優先考慮SQL注入的防護手段。
### 一網打盡
為什么使用PDO和MySQLi連接數據庫會比mysql函數庫更加安全。
# 第6章 程序設計題考察點 #
## 6-1 程序功能設計考察點
### 回顧真題:
編寫一個在線留言本,實現用戶的在線留言功能,留言信息存儲到數據庫,要求設計數據表內容以及使用PHP編碼完成。
### 考官考點:
- 數據表設計
- 數據表創建語句
- 選擇PHP連接數據庫的方式
- 編碼能力
#### 數據表設計
分析數據表結構:
留言板有哪些信息需要存儲
留言信息:ID,留言標題,留言內容,留言時間,留言人
#### 數據表創建語句
```
CREATE TABLE message(
`id` int unsigned not null auto_increment primary key,
`title` varchar(120) not null default '',
`content` varchar(2500) not null default '',
`create_time` int not null default 0,
`user_name` varchar(32) not null default '',
KEY message_user_name(user_name)
)ENGINE=InnoDB DEFAULT CHARSET=utf8;
```
#### 選擇PHP連接數據庫的方式
PDO:
可擴展性好、支持預處理、面向對象
MySQLi:
只支持MySQL操作,支持預處理,面向對象和過程,效率較高
MySQL:
只支持MySQL數據庫,沒有預處理支持,面向過程
PDO操作數據庫的代碼
...
#### 編碼能力
<?php
try{
...
}catch(PDOException $e){
echo $e->getMessage();
}
$pdo = new PDO($dsn,$username,$password,$attr);
$sql = 'SELECT id,title,content FROM message WHERE user_name=:user_name';
$stmt = $pdo->prepare($sql);
$stmt->execute([':user_name'=>$user_name]);
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);
### 解題方法
根據考題所出功能,先分析應該存儲哪些信息,設計好數據表,這一步很關鍵,如果編碼時才發現設計有問題,會浪費大量的時間,基本沒有時間改,所以要先設計好,然后根據設計好的數據表創建數據表,通常建議大家使用PDO來連接MySQL,最終完成編碼,所以一定要熟悉PDO的基本操作。
### 真題:
設計一個無限分類表
# 第7章 PHP框架基礎知識考察點 #
## 7-1 MVC框架基本工作原理考察點 ##
### 回顧真題:
談談你對MVC的認識,介紹幾種目前比較流行的MVC框架。
### 考官考點:
- MVC工作原理
- 常見MVC框架
- 延伸:單一入口的工作原理
- 延伸:模板引擎的理解
#### MVC工作原理
M: Model
V: View
C: Controller
圖1
圖2
#### 常見MVC框架
MVC框架:ThinkPHP, Yii2, CI, Yaf, Phalcon等;
圖3
#### 延伸:單一入口的工作原理
工作原理:
用一個處理程序文件處理所有的HTTP請求,根據請求時的參數的不同區分不同模塊和操作的請求。
圖4
優勢:
- 可以進行統一的安全性檢查
- 集中處理程序
劣勢:
- URL不美觀(URL重寫)
- 處理效率會稍低
#### 延伸:模板引擎的理解
常見模板引擎:
PHP是一種HTML內嵌式的在服務端執行的腳本語言,但是PHP有很多可以使PHP代碼和HTML代碼分開的模板引擎,例如:Smarty, Twig, Haml, Liquid等。
工作原理:
模板引擎就是龐大的完善的正則表達式替換庫。
### 解題方法
牢記MVC思想內容,至少能背出來
嘗試使用PHP的一個MVC框架完成一個小功能,例如:簡單的用戶管理系統,完成用戶的增刪改查即可。
### 一網打盡
框架中什么是單一入口和多入口,單一入口的優缺點。
## 7-2 常見框架特性考察點 ##
### 回顧真題
PHP框架有哪些,你用過哪些?各自的優缺點是什么?
### Yaf框架
Yaf使用PHP擴展的形式寫的一個PHP框架,也就是以C語言為底層編寫的,性能上要比PHP代碼寫的框架要快一個數量級。
優點:執行效率高』輕量級框架、可擴展性強
缺點:高版本兼容性差、底層代碼可讀性差、需要安裝擴展、功能單一、開發需要編寫大量的插件。
### Yii2框架
YII2是一款非常優秀的通用Web后端框架,結構優雅簡單,實用功能豐富,擴展性強,性能高是它最突出的優點。
缺點:學習成本高、相比Yaf,量級較重
#### 常見框架特性:
根據自己的框架使用經驗,理解所使用框架的特性
例如:Yii2框架的路由配置等;
### 解題方法
此類題目中,說明的最好是自己真正用過的框架,最好結合自己的簡歷,簡歷當中提到的框架,要著重準備,可以說說在開發過程中,你使用該框架最讓你印象深刻的功能和特性,最好多進行框架間的對比,展現你對PHP框架的理解,側面說明你的開發經驗。
### 一網打盡
Yii2框架如何實現數據的自動驗證?
# 第8章 算法、邏輯思維考察點 #
## 8-1 常見算法考察點 ##
回顧真題:
請寫出常見的排序算法,并用PHP實現冒泡排序,將數組按照從小到大的方式進行排序。
## 8-2 常見數據結構考察點 ##
## 8-3 其他邏輯算法考察點 ##
## 8-4 模擬內置函數實現考察點 ##
# 第9章 高并發解決方案類考察點 #
## 9-1 高并發和大流量解決方案考察點 ##
回顧真題:
PHP如何解決網站大流量和高并發的問題?
考官分析:
- 高并發架構相關概念
- 高并發解決方案案例
### 高并發架構相關概念
并發:
并發,在操作系統中,是指一個時間段內有幾個程序都處于已啟動運行到運行完畢之間,且這幾個程序都是在同一個處理機上運行,但任一個時刻點上只有一個程序在處理機上運行。
我們說的高并發是什么?
上面的定義明顯不是我們通常所言的并發,在互聯網時代,所講的并發、高并發,通常是指并發訪問。也就是在某一個時間點,有多少個訪問同時到來。
通常如果一個系統在日PV在千萬以上,有可能是一個高并發的系統有的公司完全不走技術路線,全靠機器堆,這不在我們的討論范圍。
高并發的問題,我們具體該關心什么?
- QPS:每秒鐘請求或者查詢的數量,在互聯網領域,指每秒響應請求數(指HTTP請求)。
- 吞吐量:單位時間內處理的請求數量(通常由QPS與并發數決定)
- 響應時間:從請求發出到收到響應發費的時間。例如系統處理一個HTTP請求需要100ms,這個100ms就是系統的響應時間。
- PV:綜合瀏覽量(Page View),即頁面瀏覽量或者點擊量,一個訪客在24小時內訪問的頁面數量。同一個人瀏覽你的網站同一頁面,只記作一次PV。
- UV:獨立訪客(Unique Vistor),即一定時間范圍內相同訪客多次訪問網站,只計算為1個獨立訪客。
- 帶寬:計算帶寬大小需關注兩個指標,峰值瀏覽和頁面的平均大小。
日網站帶寬=PV/統計時間(換算成秒) * 平均頁面大小(單位KB) * 8
峰值一般是平均值的倍數,根據實際情況來定。
- QPS不等于并發連接數
QPS是每秒HTTP請求數量,并發連接數是系統同時處理的請求數量
(總PV數*80%)/(6小時秒數*20%)=峰值每秒請求數(QPS)
80%的訪問量集中在20%的時間
- 壓力測試
- 測試能承受的最大并發
- 測試最大承受的QPS值
### 常用的性能測試工具
ab,wrk,http_load,Web Bench,Siege,Apache JMeter
#### ab
全稱是apache benchmark,是apache官方推出的工具創建多個并發訪問線程,模擬多個訪問者同時對某一URL地址進行訪問。它的測試目標是基于URL的,因此,它既可以用來測試apache的負載壓力,也可以測試nginx, lighthttp, tomcat, iis等其他Web服務器的壓力。
ab的使用:
模擬并發請求100次,總共請求5000次。
ab -c 100 -n 5000 待測試網站
注意事項:
- 測試機器與被測試機器分開
- 不要對線上服務做壓力測試
- 觀察測試工具ab所在機器,以及被測試的前端機的CPU,內存,網絡等都不超過最高限度的75%
### QPS達到極限 QPS達到極限:隨著QPS的增長,每個階段需要根據實際情況來進行優化,優化的方案也與硬件條件、網絡帶寬息息相關。
- QPS達到50:可以稱為小型網站,一般的服務器就可以應付。
- QPS達到100:假設關系型數據庫的每次請求在0.01秒完成。假設單頁面只有一個SQL查詢,那么100QPS意味著1秒鐘完成100次請求,但是此時我們并不能保證數據庫查詢能完成100次。
方案:數據庫緩存、數據庫的負載均衡。
- QPS達到800:假設我們使用百兆帶寬,意味著網站出口的實際帶寬是8M左右。假設每個頁面只有10K,在這個并發條件下,百兆帶寬已經吃完。
方案:CDN加速,負載均衡
- QPS達到1000:假設使用Memcache緩存數據庫查詢數據,每個頁面對Memcache的請求遠大于直接對DB的請求
Memcache的悲觀并發數在2W左右,但有可能在之前內網帶寬已經吃光,表現出不穩定
方案:靜態HTML緩存
- QPS達到2000:這個級別下,文件系統訪問鎖都成為了災難。
方案:做業務隔離,分布式存儲。
### 流量優化
- 防盜鏈處理
- 前端優化
- 減少HTTP請求
- 添加異步請求
- 啟用瀏覽器緩存和文件壓縮
- CDN加速
- 建立獨立圖片服務器
- 服務端優化
- 頁面靜態化
- 并發處理
- 隊列處理
- 數據庫優化
- 數據庫緩存
- 分庫分表、分區操作
- 讀寫分離
- 負載均衡
- Web服務器優化
- 負載均衡
## 9-2 web資源防盜鏈 ##
相關概念:
- 什么是防盜鏈
- 防盜鏈的工作原理
- 防盜鏈的實現方法
### 什么是防盜鏈?
盜鏈是指在自己的頁面上展示一些并不在自己服務器上的內容,獲得他人服務器上的資源地址,繞過別人的資源展示頁面,直接在自己的頁面上向最終用戶提供此內容。
常見的是小站盜用大站的圖片、音樂、視頻、軟件等資源
通過盜鏈的方法可以減輕自己服務器的負擔,因為真實的空間和流量均是來自別人的服務器
防盜鏈概念:
防止別人通過一些技術手段繞過本站的資源展示頁面,盜用本站的資源,讓繞開本站資源展示頁面的資源鏈接失效
可以大大減輕服務器及帶寬的壓力
### 工作原理:
通過Referer或者簽名,網站可以檢測目標網頁訪問的來源網頁,如果是資源文件,則可以跟蹤到顯示它的網頁地址。
一旦檢測到來源不是本站即進行組織或者返回指定的頁面
通過計算簽名的方式,判斷請求是否合法,如果合法則顯示,否則返回錯誤信息。
### 防盜鏈的實現方法
Referer
Nginx模塊 ngx_http_referer_module用來阻擋來源非法的域名請求:
Nginx指令 valid_referers, 全局變量$invalid_referer
valid_referers none|blocked|server_names|string...;
none: "Referer"來源頭部為空的情況
blocked: "Referer"來源頭部不為空,但是里面的值被代理或者防火墻刪除了,這些值都不以http://或者https://開頭
server_names:"Referer"來源頭部包含當前的server_names
代碼實例...
```
location ~ .*\.(gif|jpg|png|flv|swf|rar|zip)&{
valid_referers none blocked imooc.com *.imooc.com;
if($invalid_referer)
{
#return 403;
rewrite ^/ http://www.imooc.com/403.jpg;
}
}
```
### 傳統防盜鏈遇到的問題
偽造Referer:可以使用加密簽名解決
加密簽名:
使用第三方模塊HttpAccessKeyModule實現Nginx防盜鏈。
accesskey on|off 模塊開關
accesskey_hashmethod md5|sha-1 簽名加密方式
accesskey_arg GET參數名稱
accesskey_signature 加密規則
代碼實例:
```
location ~ .*\.(gif|jpg|png|flv|swf|rar|zip)$
{
accesskey on;
accesskey_hashmethod md5;
accesskey_arg "key";
accesskey_signature "mypass$remote_addr";
}
```
```
<?php
$sign = md5('jason'.$_SERVER['REMOTE_ADDR']);
echo '<img src="./long_new.png?sign="' . $sign . '>';
```
## 9-3 減少HTTP請求 ##
相關概念:
- 為什么要減少HTTP請求
- 減少HTTP請求的方式
### 為什么要減少HTTP請求
性能黃金法則
只有10%-20%的最終用戶響應時間花在接收請求的HTML文檔上,剩下的80%-90%時間花在HTML文檔所引用的所有組件(圖片, script, css, flash等等)進行的HTTP請求上。
如何改善
改善響應時間的最簡單途徑就是減少組件的數量,并由此減少HTTP請求的數量
HTTP連接產生的開銷
域名解析-TCP連接-發送請求-等待-下載資源-解析時間
疑問?
- DNS緩存
- Keep-Alive
打破謠言
- 查找DNS緩存也需要時間,多個緩存就要查找多次有可能緩存會被清除
- HTTP1.1協議規定請求只能串行發送,也就是說一百個請求必須依次逐個發送,簽名的一個請求完成才能開始下個請求
### 減少HTTP請求的方式
1. 圖片地圖
圖片地圖允許你在一個圖片上關聯多個URL,目標URL的選擇取決于用戶單擊了圖片上的哪個位置。
我們可以通過使用五個分開的圖片,然后每個圖片對應一個超鏈接。產生了5個HTTP請求,我們的目標是要減少HTTP請求。將五個圖片合并為一張圖片,然后以位置信息定位超鏈接。把HTTP請求減少為一個,可以保證設計的完整性和功能的齊全性。
http://stevesouders.com/hpws/imagemap-no.php
2. CSS Sprites
CSS Sprites中文的意思是CSS精靈,通過使用合并圖片,通過指定CSS的 background-image 和 background-position 來顯示元素。
background-position 屬性:
background-position: x, y; x和y可以寫負值也可以寫正值,我們可以想象圖片的左上方為(0,0),以(0,0)左邊向右是為負數的x軸,以(0,0)坐標向下是負數的y軸。
性能影響:圖片地圖與CSS精靈的響應時間基本上相同,但比使用各自獨立圖片的方式要快50%以上。
3. 合并腳本和樣式表文件
使用外部的JS和CSS文件引用的方式,因為這要比直接寫在頁面中性能要更好一點。
獨立的一個js比用多個js文件組成的頁面載入要快38%。
4. 圖片使用Base64編碼減少頁面請求數
采用Base64的編碼方式將圖片直接嵌入到網頁中,而不是從外部載入。
<img src="data:image/gif;base64,/9j/4AAQSkZJ...">
## 9-4 瀏覽器緩存和壓縮優化技術 ##
相關概念:
- HTTP緩存機制
- Nginx配置緩存策略
- 前端代碼和資源的壓縮
### HTTP緩存機制
高并發下只能通過提升服務器負載解決?
緩存只能做數據庫緩存嗎?
啟用瀏覽器緩存
緩存分類:
HTTP緩存模型中,如果請求成功會有3種情況
- 200 from cache:直接從本地緩存中獲取響應,最快速,最省流量,因為根本沒有向服務器發送請求
- 304 Not Modified:協商緩存,瀏覽器在本地沒有命中的情況下請求頭中發送一定的校驗數據到服務端,如果服務端數據沒有改變瀏覽器從本地緩存響應,返回304。
快速,發送的數據很少,只返回一些基本的響應頭信息,數據量很小,不發送實際響應體。
- 200 OK:以上兩種緩存全部都失敗,服務器返回完整響應。沒有用到緩存,相對最慢。
本地緩存:
瀏覽器認為本地緩存可以使用,不會去請求服務端。
相關Header:
Pragma:Http1.0時代的遺留產物,該字段被設置為no-cache時,會告知瀏覽器禁用本地緩存,即每次都向服務器發送請求。
Expires:HTTP1.0時代用來啟用本地緩存的字段,expires值對應一個形如Thu, 31 Dec 2037 23:55:55 GMT的格林威治時間,告訴瀏覽器緩存實現的時刻,如果還沒到該時刻,標明緩存有效,無需發送請求。
瀏覽器與服務器的時間無法保持一致,如果時間差距大,就會影響緩存結果。
Cache-Control:HTTP1.1針對Expires時間不一致的解決方案,運用Cache-Control告知瀏覽器緩存過期的時間間隔而不是時刻,即使具體時間不一致,也不影響緩存的管理。
- no-store:禁止瀏覽器緩存響應
- no-cache:不允許直接使用本地緩存,先發起請求和服務器協商
- max-age=delta-seconds:告知瀏覽器該響應本地緩存有效的最長期限,以秒為單位
優先級:Pragma>Cache-Control>Expires
協商緩存:
當瀏覽器沒有命中本地緩存,如本地緩存過期或者響應中聲明不允許直接使用本地緩存,那么瀏覽器肯定會發起服務端請求。
服務端會驗證數據是否修改,如果沒有通知瀏覽器使用本地緩存
相關Header
Last-Modified:通知瀏覽器資源的最后修改時間
Last-Modified:Mon, 28 Sep 2015 08:06:43 GMT
If-Modified-Since:得到資源的最后修改時間后,會將這個信息通過If-Modified-Since提交到服務器做檢查,如果沒有修改,返回304狀態碼
ETag:HTTP1.1推出,文件的指紋標識符,如果文件內容修改,指紋會改變
ETag:"78437822c-6739"
If-None-Match:本地緩存失效,會攜帶此值去請求服務端,服務端判斷該資源是否改變,如果沒有改變,直接使用本地緩存,返回304
### 緩存策略的選擇
適合緩存的內容:
- 不變的圖像,如LOGO、圖標等
- js, css靜態文件
- 可下載的內容,媒體文件
建議使用協商緩存:
- HTML文件
- 經常替換的圖片
- 經常修改的JS,CSS文件
- js, css文件的加載可以加入文件的簽名來拒絕緩存
- index.css?簽名
- index.簽名.js
不建議緩存的內容:
- 用戶隱私等敏感數據
- 經常改變的api接口數據
### Nginx配置緩存策略
本地緩存配置:
- add_header指令:添加狀態碼為2XX和3XX的響應頭信息;
- add_header name value [always];
- 可以設置Pragma/Expires/Cache-Control,可以繼承;
- expires指令:通知瀏覽器過期時長
- expires time:為負值時表示Cache-Control: no-cache;
當為正或者0時,就表示Cache-Control: max-age=指定的時間;
當為max時,會把Expires設置為:"Thu, 31 Dec 2037 23:55:55 GMT",Cache-Control設置到10年;
### 前端代碼和資源的壓縮
優勢:
讓資源文件更小,加快文件在網絡中的傳輸,讓網頁更快的展現,降低帶寬和流量開銷。
壓縮方式:
- JS, CSS, 圖片, HTML代碼的壓縮
- Gzip壓縮
JavaScript代碼壓縮:
- JavaScript壓縮的原理一般是去掉多余的空格和回車,替換長變量名,簡化一些代碼寫法等;
- JavaScript代碼壓縮工具很多,有在線工具,有應用程序,有編輯器插件等
- 常用壓縮工具:UglifyJS, YUI Compressor, Closure Compiler
- UglifyJS代碼壓縮:壓縮、語法檢查、美化代碼、代碼縮減、轉化
- YUI Compressor:來自Yahoo,只有壓縮功能
- Closure Compiler:來自Google,功能和UglifyJS類似,壓縮的方式不一樣
CSS代碼壓縮:
- 原理跟JavaScript壓縮原理類似,同樣是取出空白符,注釋并且優化一些CSS語義規則等
- 常用壓縮工具:YUI Compressor,CSS Compressor
- CSS Compressor:壓縮時可以選擇模式
HTML代碼壓縮:
- 不建議使用代碼壓縮,有時會破壞代碼結構,可以使用Gzip壓縮,當然也可以使用htmlcompressor工具,不過轉換后一定要檢查代碼結構
圖片壓縮:
- 除了代碼的壓縮外,有時對圖片的壓縮也是很有必要的,一般情況下,圖片在Web系統的比重都比較大。
- 壓縮工具:tinypng, JpegMini, ImageOptim
Nginx配置:
- gzip on|off:#是否開啟gzip
- gzip_buffers 32 4k|16 8k #緩沖(在內存中緩沖幾塊?每塊多大)
- gzip_comp_level[1-9] #推薦6 壓縮界別(級別越高,壓的越小,越浪費CPU計算資源)
- gzip_disabled #正則匹配UA 什么樣的URL不進行gzip
- gzip_min_length 200 #開始壓縮的最小長度
- gzip_http_version 1.0|1.1 #開始壓縮的http協議版本
- gzip_proxied #設置請求者代理服務器,該如何緩存內容
- gzip_types text/palin application/xml #對哪些類型的文件用壓縮 如txt,xml,html,css
- gzip_vary on|off #是否傳輸gzip壓縮標志

其他工具:
- 自動化構建工具Grunt
## 9-5 CDN加速 ##
相關概念:
- 什么是CDN
- 使用CDN的優勢
- CDN的工作原理
- CDN的適用場景
- CDN的實現
### 什么是CDN
CDN的全稱是Content Delivery Network,即內容分發網絡。盡可能避開互聯網上有可能影響數據傳輸速度和穩定性的瓶頸和環節,使內容傳輸的更快,更穩定。
在網絡各處放置節點服務器所構成的在現有的互聯網基礎之上的一層智能虛擬網絡。
CDN系統能夠實時地根據網絡流量和各節點的連接、負載狀況以及到用戶的距離和響應時間等綜合信息將用戶的請求重新導向離用戶最近的服務節點上
### 使用CDN的優勢
本地Cache加速,提高了企業站點(尤其含有大量圖片和靜態頁面站點)的訪問速度
跨運營商的網絡加速,保證不同網絡的用戶都能夠得到良好的訪問質量
遠程訪問用戶根據DNS負載均衡技術只能選擇Cache服務器
自動生成服務器的遠程Mirror(鏡像)cache服務器,遠程用戶訪問時從cache服務器上讀取數據,減少遠程訪問的帶寬,分擔網絡流量、減輕原站點WEB服務器負載等功能
廣泛分布的CDN節點加上節點之間的只能冗余機制,可以有效地預防黑客入侵
### CDN的工作原理
傳統訪問:
用戶在瀏覽器輸入域名發起請求 - 解析域名獲取服務器IP地址 - 根據IP地址找到對應的服務器 - 服務器響應并返回數據
使用CDN訪問:
用戶發起請求 - 智能DNS的解析(根據IP判斷地理位置,接入網類型,選擇路由最短和負載最輕的服務器) - 取得緩存服務器IP - 把內容返回給用戶(如果緩存中有) - 向源站發起請求 - 將結果返回給用戶 - 將結果存入緩存服務器

### CDN的適用場景
- 站點或者應用中大量靜態資源的加速分發,例如:CSS, JS, 圖片和HTML
- 大文件下載
- 直播網站等
### CDN的實現
- BAT等都有提供CDN服務
- 可用LVS做4層負載均衡
- 可用Nginx,Varnish,Squid,Apache Traffic Server做7層負載均衡和Cache
- 使用squid反向代理或者Nginx等的反向代理
## 9-6 建立獨立的圖片服務器 ##
相關概念:
- 獨立的必要性
- 采用獨立域名
- 獨立后的問題
### 獨立的必要性
- 分擔Web服務器的I/O負載-將耗費資源的圖片服務分離出來,提高服務器的性能和穩定性
- 能夠專門對圖片服務器進行優化-為圖片服務設置有針對性的緩存方案,減少帶寬成本,提高訪問速度
- 提高網站的可擴展性:通過增加圖片服務器,提高圖片吞吐能力
### 采用獨立域名
同一域名下瀏覽器的并發連接數有限制,突破瀏覽器連接數的限制由于cookie的原因,對緩存不利,大部分「Web Cache」都只緩存不帶cookie的請求,導致每次的圖片請求都不能命中cache。
### 獨立后的問題
- 如何進行圖片上傳和圖片同步
- NFS共享方式
## 9-7 動態語言靜態化 ##
相關概念:
- 什么是動態語言靜態化
- 為什么要靜態化
- 靜態化的實現方式
### 什么是動態語言靜態化
- 將現有PHP等動態語言的邏輯代碼生成為靜態HTML文件,用戶訪問動態腳本重定向到靜態HTML文件的過程。
- 對實時性要求不高的頁面。
### 為什么要靜態化
- 動態腳本通常會做邏輯計算和數據查詢,訪問量越大,服務器壓力越大
- 訪問量大時可能會造成CPU負載過高,數據庫服務器壓力過大
- 靜態化可以減低邏輯處理壓力,降低數據庫服務器查詢壓力
### 靜態化的實現方式
使用模板引擎:
可以使用Smarty的緩存機制生成靜態HTML緩存文件。
```
$smarty->cache_dir = $ROOT."/cache"; //緩存目錄
$smarty->cache = true; //是否開啟緩存
$smarty->cache_lifetime = "3600"; //緩存時間
$smarty->display(string template[, string cache_id[, string compile_id]]);
$smarty->clear_all_cache(); //清除所有緩存
$smarty->clear_cache('file.html); //清除指定的緩存
$smarty->clear_cache('article.html',$art_id); //清除同一個模板下的指定緩存號的緩存
```
利用ob系列的函數:
```
ob_start() 打開輸出控制緩存
ob_get_contents() 返回輸出緩沖區內容
ob_clean() 清空輸出緩沖區
ob_end_flush() 沖刷出(送出)輸出緩沖區內容并關閉緩沖
```
可以判斷文件的inode修改時間,判斷是否過期,使用filectime函數
## 9-8 動態語言層的并發處理 ##
相關概念:
- 什么是進程、線程、協程
- 什么是多進程、多線程
- 同步阻塞模型
- 異步非阻塞模型
- PHP并發編程實踐
### 什么是進程、線程、協程
- 進程是計算機中的程序關于某數據集合上的一次運行獲得,是系統進行資源分配和調度的基本單位,是操作系統機構的基礎。
- 進程是一個執行中的程序。
- 進程的三態模型:多道程序系統中,進程在處理器上交替運行,狀態不斷的發生變化:運行、就緒、阻塞
- 運行:當一個進程在處理機上運行時,則稱該進程處于運行狀態。處于此狀態的進程的數目小于等于處理器的數目,對于單處理機系統,處于運行狀態的進程只有一個。在沒有其它進程可以執行時(如所有進程都在阻塞狀態),通常會自動執行系統的空閑進程。
- 就緒:當一個進程獲得了除處理機以外的一切所需資源,一旦得到處理機即可運行,則稱此進程處于就緒狀態。就緒狀態可以按多個優先級來劃分隊列。例如當一個進程由于時間片用完而進入就緒狀態時,排入低優先級隊列;當進程由I/O操作完成而進入就緒狀態時,排入高優先級隊列。
- 阻塞:也稱為等待或睡眠狀態,一個進程正在等待某一事件發生(例如請求I/O而等待I/O完成等)而暫時停止運行,這時即使把處理機分配給進程也無法運行,故稱該進程處于阻塞狀態。
進程的五態模型:對于一個實際的系統,進程的狀態及其轉換更為復雜。
新建態、活躍就緒/靜止就緒、運行、活躍阻塞/禁止阻塞、終止態
- 新建態:對于進程剛剛被創建時沒有被提交的狀態,并等待系統完成創建進程的所有必要信息。
- 終止態:進程已結束運行,回收除進程控制塊之外的其它資源,并讓其它進程從進程塊中收集有關信息。
- 活躍就緒:是指進程在主存并且可被調度的狀態。
- 靜止就緒(掛起就緒):是指進程被對換到輔存時的就緒狀態,是不能被直接調度的狀態,只有當主存中沒有活躍就緒態進程,或者是掛起就緒態進程具有更高的優先級,系統將把掛起就緒態進程調回主存并轉換為活躍就緒。
- 活躍阻塞:是指進程已在主存,一旦等待的事件產生便進入活躍就緒狀態。
- 靜止阻塞:進程對換到輔存時的阻塞狀態,一旦等待的事件產生便進入靜止就緒狀態。
用戶用戶的并發請求,為每一個請求都創建一個進程顯然是行不通的,從系統資源開銷方面或是響應用戶請求的效率方面來看。因此操作系統中線程的概念便被引進了。
線程,有時被稱為輕量級進程,是程序執行流的最小單元。
線程是進程中的一個實體,是被系統獨立調度和分派的基本單位,線程自己不擁有系統資源,只擁有一點兒在運行中必不可少的資源。但它可與同屬一個進程的其它線程共享進程所擁有的全部資源。
一個線程可以創建和撤銷另一個線程,同一個進程中的多個線程之間可以并發執行。
線程是程序中一個單一的順序控制流程。進程內一個相對獨立的、可調度的執行單元,是系統獨立調度和分派CPU的基本單位指運行中的程序的調度單位。
在單個程序中同時運行多個線程完成不同的工作,稱為多線程。
每一個程序都至少有一個線程,若程序只有一個線程,那就是程序本身。
線程的狀態:就緒、阻塞、運行
就緒狀態:線程具備運行的所有條件,邏輯上可以運行,在等待處理機。
運行狀態:線程占有處理機正在運行。
阻塞狀態:線程在等待一個事件(如某個信號量),邏輯上不可執行。
協程是一種用戶態的輕量級線程,協程的調度完全由用戶控制。協程擁有自己的寄存器上下文和棧。協程調度切換時,將寄存器上下文和棧保存到其他地方,在切回來的時候,恢復先前保存的寄存器上下文和棧,直接操作棧則基本沒有內核切換的開銷,可以不加鎖的訪問全局變量,所以上下文的切換非常快。
線程與進程的區別:
線程與協程的區別:
### 什么是多進程、多線程
### 同步阻塞模型
### 異步非阻塞模型
### PHP并發編程實踐
## 9-9 數據庫緩存層的優化 ##
相關概念:
- 什么是數據庫緩存
- 為什么要使用緩存
- 使用MySQL查詢緩存
- 使用Memcache緩存
- 使用Redis緩存
## 9-10 Mysql數據層的優化 ##
## 9-11 Web服務器的負載均衡、請求分發 ##