PHP 面試遇到的問題,後期會不定期更新一下,大家也可以把認為經典的問題評論留言,感謝大家!

wacho發表於2019-08-27
1、GET在瀏覽器回退時是無害的,而POST會再次提交請求。
2、GET產生的URL地址可以被Bookmark,而POST不可以。
3、GET請求會被瀏覽器主動cache,而POST不會,除非手動設定。
4、GET請求只能進行url編碼,而POST支援多種編碼方式。
5、GET請求引數會被完整保留在瀏覽器歷史記錄裡,而POST中的引數不會被保留。
6、GET請求在URL中傳送的引數是有長度限制的,而POST沒有。
7、對引數的資料型別,GET只接受ASCII字元,而POST沒有限制。
8、GET比POST更不安全,因為引數直接暴露在URL上,所以不能用來傳遞敏感資訊。
9、GET引數通過URL傳遞,POST放在Request body中。
10、GET產生一個TCP資料包,POST產生兩個TCP資料包
require是無條件包含也就是如果一個流程里加入require,無論條件成立與否都會先執行require
 include有返回值,而require沒有(可能因為如此require的速度比include快)
 包含檔案不存在或者語法錯誤的時候require是致命的錯誤終止執行,include不是
1xx訊息:這一型別的狀態碼,代表請求已被接受,需要繼續處理。由於HTTP/1.0協議中沒有定義任何1xx狀態碼,所以除非在某些試驗條件下,伺服器禁止向此類客戶端傳送1xx響應。

2xx成功:這一型別的狀態碼,代表請求已成功被伺服器接收、理解、並接受
200 OK:請求已成功,請求所希望的響應頭或資料體將隨此響應返回。實際的響應將取決於所使用的請求方法。在GET請求中,響應將包含與請求的資源相對應的實體。在POST請求中,響應將包含描述或操作結果的實體
202 Accepted:伺服器已接受請求,但尚未處理。最終該請求可能會也可能不會被執行,並且可能在處理髮生時被禁止。
204 No Content:伺服器成功處理了請求,沒有返回任何內容

3xx重定向:這類狀態碼代表需要客戶端採取進一步的操作才能完成請求。通常,這些狀態碼用來重定向,後續的請求地址(重定向目標)在本次響應的Location域中指明。
301 Moved Permanently:被請求的資源已永久移動到新位置,並且將來任何對此資源的引用都應該使用本響應返回的若干個URI之一。如果可能,擁有連結編輯功能的客戶端應當自動把請求的地址修改為從伺服器反饋回來的地址。除非額外指定,否則這個響應也是可快取的。新的永久性的URI應當在響應的Location域中返回。除非這是一個HEAD請求,否則響應的實體中應當包含指向新的URI的超連結及簡短說明。如果這不是一個GET或者HEAD請求,那麼瀏覽器禁止自動進行重定向,除非得到使用者的確認,因為請求的條件可能因此發生變化。注意:對於某些使用HTTP/1.0協議的瀏覽器,當它們傳送的POST請求得到了一個301響應的話,接下來的重定向請求將會變成GET方式。
4xx客戶端錯誤:這類的狀態碼代表了客戶端看起來可能發生了錯誤,妨礙了伺服器的處理。除非響應的是一個HEAD請求,否則伺服器就應該返回一個解釋當前錯誤狀況的實體,以及這是臨時的還是永久性的狀況。這些狀態碼適用於任何請求方法。瀏覽器應當向使用者顯示任何包含在此類錯誤響應中的實體內容
400 Bad Request:由於明顯的客戶端錯誤(例如,格式錯誤的請求語法,太大的大小,無效的請求訊息或欺騙性路由請求),伺服器不能或不會處理該請求
401 Unauthorized:類似於403 Forbidden,401語義即“未認證”,即使用者沒有必要的憑據。[32]該狀態碼錶示當前請求需要使用者驗證。該響應必須包含一個適用於被請求資源的WWW-Authenticate資訊頭用以詢問使用者資訊。客戶端可以重複提交一個包含恰當的Authorization頭資訊的請求。
403 Forbidden:伺服器已經理解請求,但是拒絕執行它。與401響應不同的是,身份驗證並不能提供任何幫助,而且這個請求也不應該被重複提交。如果這不是一個HEAD請求,而且伺服器希望能夠講清楚為何請求不能被執行,那麼就應該在實體內描述拒絕的原因。當然伺服器也可以返回一個404響應,假如它不希望讓客戶端獲得任何資訊。
404 Not Found:請求失敗,請求所希望得到的資源未被在伺服器上發現,但允許使用者的後續請求。[35]沒有資訊能夠告訴使用者這個狀況到底是暫時的還是永久的。假如伺服器知道情況的話,應當使用410狀態碼來告知舊資源因為某些內部的配置機制問題,已經永久的不可用,而且沒有任何可以跳轉的地址。404這個狀態碼被廣泛應用於當伺服器不想揭示到底為何請求被拒絕或者沒有其他適合的響應可用的情況下。
405 Method Not Allowed:請求行中指定的請求方法不能被用於請求相應的資源。
408 Request Timeout:請求超時
5xx伺服器錯誤:表示伺服器無法完成明顯有效的請求。[56]這類狀態碼代表了伺服器在處理請求的過程中有錯誤或者異常狀態發生,也有可能是伺服器意識到以當前的軟硬體資源無法完成對請求的處理。除非這是一個HEAD請求,否則伺服器應當包含一個解釋當前錯誤狀態以及這個狀況是臨時的還是永久的解釋資訊實體。瀏覽器應當向使用者展示任何在當前響應中被包含的實體。這些狀態碼適用於任何響應方法
500 Internal Server Error:通用錯誤訊息,伺服器遇到了一個未曾預料的狀況,導致了它無法完成對請求的處理。沒有給出具體錯誤資訊
502 Bad Gateway:作為閘道器或者代理工作的伺服器嘗試執行請求時,從上游伺服器接收到無效的響應
503 Service Unavailable:由於臨時的伺服器維護或者過載,伺服器當前無法處理請求。這個狀況是暫時的,並且將在一段時間以後恢復。
504 Gateway Timeout:作為閘道器或者代理工作的伺服器嘗試執行請求時,未能及時從上游伺服器(URI標識出的伺服器,例如HTTP、FTP、LDAP)或者輔助伺服器(例如DNS)收到響應。注意:某些代理伺服器在DNS查詢超時時會返回400或者500錯誤。
區別:

1. 存放位置:Session 儲存在伺服器,Cookie 儲存在客戶端。

2. 存放的形式:Session 是以物件的形式儲存在伺服器,Cookie 以字串的形式儲存在客戶端。

3. 用途:Cookies 適合做儲存使用者的個人設定,愛好等,Session 適合做客戶的身份驗證

4. 路徑:Session 不能區分路徑,同一個使用者在訪問一個網站期間,所有的 Session 在任何一個地方都可以訪問到。而 Cookie 中如果設定了路徑引數,那麼同一個網站中不同路徑下的 Cookie 互相是訪問不到的。

5. 安全性:Cookie 不是很安全,別人可以分析存放在本地的 COOKIE 並進行 COOKIE 欺騙,考慮到安全應當使用 session

6. 大小以及數量限制:每個域名所包含的 cookie 數:IE7/8,FireFox:50 個,Opera30 個; Cookie 總大小:Firefox 和 Safari 允許 cookie 多達 4097 個位元組,Opera 允許 cookie 多達 4096 個字 節,InternetExplorer 允許 cookie 多達 4095 個位元組;一般認為 Session 沒有大小和數量限制。

關係:

Session 需要藉助 Cookie 才能正常工作。如果客戶端完全禁止 Cookie,Session 將失效!

Session 是由應用伺服器維持的一個 伺服器端的儲存空間,使用者在連線伺服器時,會由伺服器生成一個唯一的 SessionID, 用該 SessionID 為識別符號來存取伺服器端的 Session 儲存空間。而 SessionID 這一資料則是儲存到客戶端,用 Cookie 儲存的,使用者提交頁面時,會將這一 SessionID 提交到伺服器端,來存取 Session 資料。這一過程,是不用開發人員干預的。所以一旦客戶端禁用 Cookie,那麼 Session 也會失效。
session存在於伺服器端,cookie存在於使用者端。之前說如果禁用了cookie那麼session就使用不了了,可以說這是正確的,也可以說這是錯誤的。因為禁用了cookie,session_id就不能儲存,而伺服器正是根據session_id來判斷使用者的session,所以說這是正確的。經過測試,當我們禁用cookie時,重新整理頁面session_id會改變,說明session_id是用cookie儲存的。使用者禁止cookie,伺服器仍會將sessionId以cookie的方式傳送給瀏覽器,只是瀏覽器不能儲存了而已,我們可以用其他方法獲取這個 sessionID。
解決cookie禁用然後引用session的方法。
1.修改 php.ini
session.use_cookies = 0  //設定客戶端是否使用cookie來儲存session值  該引數的值不影響上述機制的進行。
但是為了驗證該機制,這裡把該引數設為0,排除cookie攜帶seesionid的可能
session.use_only_cookies = 0  //是否只使用cookie來儲存session值  該引數為1時,上述機制失效。
設定session.use_trans_sid = 1或者編譯時開啟開啟了--enable-trans-sid選項
這樣他會在每個url後面自動加上PHPSESSID的值,然後正常使用session就可以了。

2.
在url後面加上session_id的值或者儲存session_id的值於資料庫或redis中,然後在下一次要呼叫session前,執行session_id($session_id),還有這條語句要在session_start()前。
PHP 可以自動進行記憶體管理,清除不需要的物件。

PHP 使用了引用計數 (reference counting) GC 機制。

每個物件都內含一個引用計數器 refcount,每個 reference 連線到物件,計數器加 1。當 reference 離開生存空間或被設為 NULL,計數器減 1。當某個物件的引用計數器為零時,PHP 知道你將不再需要使用這個物件,釋放其所佔的記憶體空間。
長連線:client 方與 server 方先建立連線,連線建立後不斷開,然後再進行報文傳送和接收。這種方式下由於通訊連線一直存在。此種方式常用於 P2P 通訊。

短連線:Client 方與 server 每進行一次報文收發交易時才進行通訊連線,交易完畢後立即斷開連線。此方式常用於一點對多點通訊。C/S 通訊。

長連線與短連線的使用時機:

長連線:

長連線多用於操作頻繁,點對點的通訊,而且連線數不能太多的情況。每個 TCP 連 接的建立都需要三次握手,每個 TCP 連線的斷開要四次握手。如果每次操作都要建立連線然後再操作的話處理速度會降低,所以每次操作下次操作時直接傳送資料 就可以了,不用再建立 TCP 連線。例如:資料庫的連線用長連線,如果用短連線頻繁的通訊會造成 socket 錯誤,頻繁的 socket 建立也是對資源的浪 費。

短連線:

web 網站的 http 服務一般都用短連線。因為長連線對於伺服器來說要耗費一定 的資源。像 web 網站這麼頻繁的成千上萬甚至上億客戶端的連線用短連線更省一些資源。試想如果都用長連線,而且同時用成千上萬的使用者,每個使用者都佔有一個 連線的話,可想而知伺服器的壓力有多大。所以併發量大,但是每個使用者又不需頻繁操作的情況下需要短連線。
參考連結:https://blog.csdn.net/qq_31332467/article/details/79217262
echo __FILE__ ; // 獲取當前所在檔案的絕對路徑及地址,結果:D:\aaa\my.php 
echo dirname(__FILE__); // 取得當前檔案所在的絕對目錄,結果:D:\aaa\ 
echo dirname(dirname(__FILE__)); //取得當前檔案的上一層目錄名,結果:D:\ 

原文:https://blog.csdn.net/viqecel/article/details/80765275 
* 什麼是主從複製
主從複製,是用來建立一個和主資料庫完全一樣的資料庫環境,稱為從資料庫;

* 主從複製的原理:
1.資料庫有個bin-log二進位制檔案,記錄了所有的sql語句。
2.只需要把主資料庫的bin-log檔案中的sql語句複製。
3.讓其從資料的relay-log重做日誌檔案中在執行一次這些sql語句即可。

* 主從複製的作用
1.做資料的熱備份,作為後備資料庫,主資料庫伺服器故障後,可切換到從資料庫繼續工作,避免資料丟失。
2.架構的擴充套件。業務量越來越大,I/O訪問頻率過高,單機無法滿足,此時做多庫的儲存,降低磁碟I/O訪問頻率,提高單機的I/O效能
3.主從複製是讀寫分離的基礎,使資料庫能製成更大 的併發。例如子報表中,由於部署報表的sql語句十分慢,導致鎖表,影響前臺的服務。如果前臺服務使用master,報表使用slave,那麼報表sql將不會造成前臺所,保證了前臺的訪問速度。

* 主從複製的幾種方式:
1.同步複製:所謂的同步複製,意思是master的變化,必須等待slave-1,slave-2,...,slave-n完成後才能返回。
2.非同步複製:如同AJAX請求一樣。master只需要完成自己的資料庫操作即可。至於slaves是否收到二進位制日誌,是否完成操作,不用關心。MYSQL的預設設定。
3.半同步複製:master只保證slaves中的一個操作成功,就返回,其他slave不管。
這個功能,是由google為MYSQL引入的。

* 關於讀寫分離
在完成主從複製時,由於slave是需要同步master的。所以對於insert/delete/update這些更新資料庫的操作,應該在master中完成。而select的查詢操作,則落下到slave中。

原文:
https://blog.csdn.net/darkangel1228/article/details/80004222
https://www.cnblogs.com/KTblog/p/5122825.html
**什麼是索引**
索引是對資料庫表中一列或多列的值進行排序的一種結構,使用索引可快速訪問資料庫表中的特定資訊。(摘自百度百科)

**索引型別**
1.FULLTEXT 全文索引
    全文索引,僅MyISAM引擎支援。其可以在CREATE TABLE ,ALTER TABLE ,CREATE INDEX 使用,不過目前只有 CHAR、VARCHAR ,TEXT 列上可以建立全文索引。
2.HASH 雜湊索引
    HASH索引的唯一性及類似鍵值對的形式十分適合作為索引,HASH索引可以一次定位,不需要像樹形索引那樣逐層參照,因此具有極高的效率。但是這種高效是有條件的。即只在“=”和“in”條件下高效,對於範圍查詢,排序及組合索引仍然效率不高。
3.BTREE 樹形索引
    BTREE所以是一種將索引按一定演算法,存入一個樹形的資料結構中(二叉樹),每次查詢都是從樹的入口root開始,一次遍歷node,獲取leaf。這是MySQL中預設也是最常用的索引型別。
4.RTREE
    RTREE在MySQL中很少使用,僅支援geometry資料型別,支援該儲存引擎只有MyISAM、BDb、InnoDb、NDb、Archive幾種。相對於BTREE,RTREE的優勢在於範圍查詢。

**索引種類**
普通索引:僅加速查詢
唯一索引:加速查詢+列值唯一(可以有null)
主鍵索引:加速查詢+列值唯一(不可以有null)+表中只有一個
組合索引:多列值組成一個索引,專門用於組合搜尋,其效率大於索引合併
全文索引:對文字內容進行分詞,進行搜尋
外來鍵索引:與主鍵索引形成聯絡,保證資料的完整性。

**索引使用的注意事項**
1.符合索引遵循字首原則
2.like查詢%不能再前,否則索引失效。如有需要,使用全文索引
3.column is null可以使用索引
4.如果MySQL估計使用索引比全表掃描慢,則放棄使用索引
5.如果or前的條件中列有索引,後面的沒有,索引不會生效。
6.列型別是字串,查詢時,一定要給值加引號,否則索引失效。
7.確定order by 和 group by 中只有一個表的列,這樣才能使用索引。換句話說,當order by 中的欄位出現在where條件中時,才會利用索引而不排序,更準確的說,order by 中的欄位在執行計劃中利用了索引時,不用排序操作。
8.使用的索引列不能參與運算,否則失效。
web伺服器優化 :負載均衡 
流量優化:防盜鏈處理 將惡意請求遮蔽,
前端優化:減少http請求、新增非同步請求、啟用瀏覽器快取和檔案壓縮、cdn加速、建立獨立的圖片伺服器、
服務端優化:  頁面靜態化、併發處理、佇列處理、
資料庫優化: 資料庫快取、分庫分表、分割槽操作 、讀寫分離、負載均衡
1. 氣泡排序
思路分析:在要排序的一組數中,對當前還未排好的序列,從前往後對相鄰的兩個數依次進行比較和調整,讓較大的數往下沉,較小的往上冒。即,每當兩相鄰的數比較後發現它們的排序與排序要求相反時,就將它們互換。

程式碼實現:
$arr=array(1,43,54,62,21,66,32,78,36,76,39);  
function bubbleSort($arr)
{  
  $len=count($arr);
  //該層迴圈控制 需要冒泡的輪數
  for($i=0;$i<$len-1;$i++)
  { //該層迴圈用來控制每輪 冒出一個數 需要比較的次數
    for($k=0;$k<$len-$i-1;$k++)
    {
       if($arr[$k]>$arr[$k+1])
        {
            $tmp=$arr[$k+1];
            $arr[$k+1]=$arr[$k];
            $arr[$k]=$tmp;
        }
    }
  }
  return $arr;
}

2. 選擇排序 
思路分析:在要排序的一組數中,選出最小的一個數與第一個位置的數交換。然後在剩下的數當中再找最小的與第二個位置的數交換,如此迴圈到倒數第二個數和最後一個數比較為止。

程式碼實現:
function selectSort($arr) {
//雙重迴圈完成,外層控制輪數,內層控制比較次數
 $len=count($arr);
    for($i=0; $i<$len-1; $i++) {
        //先假設最小的值的位置
        $p = $i;

        for($j=$i+1; $j<$len; $j++) {
            //$arr[$p] 是當前已知的最小值
            if($arr[$p] > $arr[$j]) {
            //比較,發現更小的,記錄下最小值的位置;並且在下次比較時採用已知的最小值進行比較。
                $p = $j;
            }
        }
        //已經確定了當前的最小值的位置,儲存到$p中。如果發現最小值的位置與當前假設的位置$i不同,則位置互換即可。
        if($p != $i) {
            $tmp = $arr[$p];
            $arr[$p] = $arr[$i];
            $arr[$i] = $tmp;
        }
    }
    //返回最終結果
    return $arr;
}

3.插入排序
思路分析:在要排序的一組數中,假設前面的數已經是排好順序的,現在要把第n個數插到前面的有序數中,使得這n個數也是排好順序的。如此反覆迴圈,直到全部排好順序。

程式碼實現:
function insertSort($arr) {
    $len=count($arr); 
    for($i=1, $i<$len; $i++) {
        $tmp = $arr[$i];
        //內層迴圈控制,比較並插入
        for($j=$i-1;$j>=0;$j--) {
            if($tmp < $arr[$j]) {
                //發現插入的元素要小,交換位置,將後邊的元素與前面的元素互換
                $arr[$j+1] = $arr[$j];
                $arr[$j] = $tmp;
            } else {
                //如果碰到不需要移動的元素,由於是已經排序好是陣列,則前面的就不需要再次比較了。
                break;
            }
        }
    }
    return $arr;
}

4.快速排序  
思路分析:選擇一個基準元素,通常選擇第一個元素或者最後一個元素。通過一趟掃描,將待排序列分成兩部分,一部分比基準元素小,一部分大於等於基準元素。此時基準元素在其排好序後的正確位置,然後再用同樣的方法遞迴地排序劃分的兩部分。

程式碼實現:
function quickSort($arr) {
    //先判斷是否需要繼續進行
    $length = count($arr);
    if($length <= 1) {
        return $arr;
    }
    //選擇第一個元素作為基準
    $base_num = $arr[0];
    //遍歷除了標尺外的所有元素,按照大小關係放入兩個陣列內
    //初始化兩個陣列
    $left_array = array();  //小於基準的
    $right_array = array();  //大於基準的
    for($i=1; $i<$length; $i++) {
        if($base_num > $arr[$i]) {
            //放入左邊陣列
            $left_array[] = $arr[$i];
        } else {
            //放入右邊
            $right_array[] = $arr[$i];
        }
    }
    //再分別對左邊和右邊的陣列進行相同的排序處理方式遞迴呼叫這個函式
    $left_array = quick_sort($left_array);
    $right_array = quick_sort($right_array);
    //合併
    return array_merge($left_array, array($base_num), $right_array);
}

原文:https://www.cnblogs.com/rainblack/p/5808694.html

5、給出一個字串,返回裡面連續字母的個數,比如:abbcddde,返回 1a2b1c3de;
程式碼實現:
  public function str($str)
    {
        $re = '';
        $arr = str_split($str);//把字串變成陣列,開始我想到的是用for迴圈來處理,這個函式同事提醒了才發現
        $key = 0; //key 用來記錄下標,為了方便計算前面的數字
        for ($i = 0; $i < count($arr); $i++) {
            $v = $arr[$i];
            if ($arr[$i] == $arr[$i + 1]) {
                continue;//如果當前的值和下一個值相等,跳出當前迴圈,進入下一個
            } else {
                $re  .= ($i - $key + 1) . $v; //不相等時計算出前面的數字,
                $key = $i + 1;// 同時 key 下標重新複製
            }
        }

        return $re;
    }

6、約瑟夫環問題,猴子選大王
一群猴子排成一圈,按1,2,…,n依次編號。然後從第1只開始數,數到第m只,把它踢出圈,從它後面再開始數,再數到第m只,在把它踢出去…,如此不停的進行下去,直到最後只剩下一隻猴子為止,那隻猴子就叫做大王。要求程式設計模擬此過程,輸入m、n, 輸出最後那個大王的編號。用程式模擬該過程。

function mk($n ,$m){
        $arr = range(1,$n);//構造一個陣列
        $i = 1; //從第一個開始迴圈
        while(count($arr)>1){ //如果總數大於1
            ($i % $m != 0) && array_push($arr,$arr[$i-1]);//不被踢出則壓入陣列尾部
            unset($arr[$i-1]);//壓入陣列然後刪除
            $i++;//繼續迴圈
        }  
        return $arr[$i-1]; //直至最後剩下一個為大王 
}
print_r(mk(6,8));   //第3只為大王
CGI,通用閘道器介面,用於WEB伺服器和應用程式間的互動,定義輸入輸出規範,使用者的請求通過WEB伺服器轉發給FastCGI程式,FastCGI程式再呼叫應用程式進行處理,如php解析器,應用程式的處理結果如html返回給FastCGI,FastCGI返回給Nginx 進行輸出。假設這裡WEB伺服器是Nginx,應用程式是 PHP,而 php-fpm 是管理 FastCGI 的,這也就是 php-fpm,FastCGI,和 Nginx 之間的關係。
FastCGI 用來提高 cgi 程式效能,啟動一個master,再啟動多個 worker,不需要每次解析 php.ini. 而 php-fpm 實現了 FastCGI 協議,是 FastCGI 的程式管理器,支援平滑重啟,可以啟動的時候預先生成多個程式。
資料結構:memcache僅支援簡單的key-value形式,Redis支援的資料更多(string字串,set集合,list列表,hash雜湊,zset有序集合);
多執行緒:memcache支援多執行緒,Redis支援單執行緒
持久化:Redis支援持久化,memcache不支援持久化
分散式:Redis做主從結構,memcache伺服器需要通過hash一致化來支撐主從結構
實際運用中可以redis,memcache結合,memcache可作為session儲存的方式,session都是KV型別鍵值對。

1.  Redis中,並不是所有的資料都一直儲存在記憶體中的,這是和Memcache相比一個最大的區別。
2.  Redis在很多方面具備資料庫的特徵,或者說就是一個資料庫系統,而Memcache只是簡單的K/V快取。
3.  他們的擴充套件都需要做叢集;實現方式:master-slave、Hash。
4.  在100k以上的資料中,Memcache效能要高於Redis。
5.  如果要說記憶體使用效率,使用簡單的key-value儲存的話,Memcached的記憶體利用率更高,而如果Redis採用hash結構來做key-value儲存,由於其組合式的壓縮,其記憶體利用率會高於Memcache。當然,這和你的應用場景和資料特性有關。
6.  如果你對資料持久化和資料同步有所要求,那麼推薦你選擇Redis,因為這兩個特性Memcache都不具備。即使你只是希望在升級或者重啟系統後快取資料不會丟失,選擇Redis也是明智的。
7.  Redis和Memcache在寫入效能上面差別不大,讀取效能上面尤其是批量讀取效能上面Memcache更強
8.Redis 提供了多種不同級別的持久化方式:
RDB 持久化可以在指定的時間間隔內生成資料集的時間點快照(point-in-time snapshot)。
AOF 持久化記錄伺服器執行的所有寫操作命令,並在伺服器啟動時,通過重新執行這些命令來還原資料集。 AOF 檔案中的命令全部以 Redis 協議的格式來儲存,新命令會被追加到檔案的末尾。 Redis 還可以在後臺對 AOF 檔案進行重寫(rewrite),使得 AOF 檔案的體積不會超出儲存資料集狀態所需的實際大小。
Redis 還可以同時使用 AOF 持久化和 RDB 持久化。 在這種情況下, 當 Redis 重啟時, 它會優先使用 AOF 檔案來還原資料集, 因為 AOF 檔案儲存的資料集通常比 RDB 檔案所儲存的資料集更完整。
你甚至可以關閉持久化功能,讓資料只在伺服器執行時存在。
**快取穿透**:就是訪問redis中一個不存在的key的時候,會直接穿過快取,去資料庫中進行查詢.
如果是黑客,進行惡意攻擊的時候,每次都請求超過2000個/秒的時候,這個時候mysql基本上就掛了.

解決辦法是:每次從資料庫中查詢到一個不存在的key的時候,就寫一個空值到快取庫中,有惡意攻擊的時候,直接從快取中取到這個空值.

**快取雪崩**:就是每秒有5000個請求過來時候,redis快取庫崩了,然後這些請求瞬間落在了mysql資料庫上,直接導致資料庫當機.

解決方案就是:

  事前:提高快取庫的高可用,  使用主從結構加哨兵  cluster叢集, 

  事中:使用ehcache+hystrix限流元件(當請求量非常巨大的時候,就呼叫自己開發好的一個降級餓元件,返回一些預設值,如友情提示,或者空白值)

  事後:做持久化,儘快恢復快取叢集,一旦恢復,自動從磁碟上讀取資料,恢復記憶體中的資料.
通常使用一個list來實現佇列操作,這樣有一個小限制,所以的任務統一都是先進先出,如果想優先處理某個任務就不太好處理了,這就需要讓佇列有優先順序的概念,我們就可以優先處理高階別的任務,實現方式有以下幾種方式:
1)單一列表實現:佇列正常的操作是 左進右出(lpush,rpop)為了先處理高優先順序任務,在遇到高階別任務時,可以直接插隊,直接放入佇列頭部(rpush),這樣,從佇列頭部(右側)獲取任務時,取到的就是高優先順序的任務(rpop)
2)使用兩個佇列,一個普通佇列,一個高階佇列,針對任務的級別放入不同的佇列,獲取任務時也很簡單,redis的BRPOP命令可以按順序從多個佇列中取值,BRPOP會按照給出的 key 順序檢視,並在找到的第一個非空 list 的尾部彈出一個元素,redis> BRPOP list1 list2 0

`list1 做為高優先順序任務佇列`

`list2 做為普通任務佇列`

`這樣就實現了先處理高優先順序任務,當沒有高優先順序任務時,就去獲取普通任務`

`方式1最簡單,但實際應用比較侷限,方式3可以實現複雜優先順序,但實現比較複雜,不利於維護`

`方式2是推薦用法,實際應用最為合適`
其實redis是不會存在併發問題的,因為他是單程式的,再多的命令都是一個接一個地執行的。我們使用的時候,可能會出現併發問題,比如獲得和設定這一對。Redis的為什麼 有高併發問題?Redis的的出身決定

Redis是一種單執行緒機制的nosql資料庫,基於key-value,資料可持久化落盤。由於單執行緒所以redis本身並沒有鎖的概念,多個客戶端連線並不存在競爭關係,但是利用jedis等客戶端對redis進行併發訪問時會出現問題。發生連線超時、資料轉換錯誤、阻塞、客戶端關閉連線等問題,這些問題均是由於客戶端連線混亂造成。

同時,單執行緒的天性決定,高併發對同一個鍵的操作會排隊處理,如果併發量很大,可能造成後來的請求超時。
在遠端訪問redis的時候,因為網路等原因造成高併發訪問延遲返回的問題。

解決辦法
在客戶端將連線進行池化,同時對客戶端讀寫Redis操作採用內部鎖synchronized。

伺服器角度,利用setnx變向實現鎖機制。
1、HTML靜態化
其實大家都知道,效率最高、消耗最小的就是純靜態化的html頁面,所以我們儘可能使我們的 網站上的頁面採用靜態頁面來實現,這個最簡單的方法其實也是最有效的方法。
2、圖片伺服器分離
把圖片單獨儲存,儘量減少圖片等大流量的開銷,可以放在一些相關的平臺上,如七牛等。
3、資料庫叢集和庫表雜湊及快取
資料庫的併發連線為100,一臺資料庫遠遠不夠,可以從讀寫分離、主從複製,資料庫叢集方面來著手。另外儘量減少資料庫的訪問,可以使用快取資料庫如memcache、redis。
4、映象
儘量減少下載,可以把不同的請求分發到多個映象端。
5、負載均衡:
Apache的最大併發連線為1500,只能增加伺服器,可以從硬體上著手,如F5伺服器。當然硬體的成本比較高,我們往往從軟體方面著手。

負載均衡 (Load Balancing) 建立在現有網路結構之上,它提供了一種廉價有效透明的方法擴充套件網路裝置和伺服器的頻寬、增加吞吐量、加強網路資料處理能力,同時能夠提高網路的靈活性和可用性。目前使用最為廣泛的負載均衡軟體是Nginx、LVS、HAProxy。我分別來說下三種的優缺點:

**Nginx的優點是:**
工作在網路的7層之上,可以針對http應用做一些分流的策略,比如針對域名、目錄結構,它的正則規則比HAProxy更為強大和靈活,這也是它目前廣泛流行的主要原因之一,Nginx單憑這點可利用的場合就遠多於LVS了。
Nginx對網路穩定性的依賴非常小,理論上能ping通就就能進行負載功能,這個也是它的優勢之一;相反LVS對網路穩定性依賴比較大,這點本人深有體會;
Nginx安裝和配置比較簡單,測試起來比較方便,它基本能把錯誤用日誌列印出來。LVS的配置、測試就要花比較長的時間了,LVS對網路依賴比較大。
可以承擔高負載壓力且穩定,在硬體不差的情況下一般能支撐幾萬次的併發量,負載度比LVS相對小些。
Nginx可以通過埠檢測到伺服器內部的故障,比如根據伺服器處理網頁返回的狀態碼、超時等等,並且會把返回錯誤的請求重新提交到另一個節點,不過其中缺點就是不支援url來檢測。比如使用者正在上傳一個檔案,而處理該上傳的節點剛好在上傳過程中出現故障,Nginx會把上傳切到另一臺伺服器重新處理,而LVS就直接斷掉了,如果是上傳一個很大的檔案或者很重要的檔案的話,使用者可能會因此而不滿。
Nginx不僅僅是一款優秀的負載均衡器/反向代理軟體,它同時也是功能強大的Web應用伺服器。LNMP也是近幾年非常流行的web架構,在高流量的環境中穩定性也很好。
Nginx現在作為Web反向加速快取越來越成熟了,速度比傳統的Squid伺服器更快,可以考慮用其作為反向代理加速器。
Nginx可作為中層反向代理使用,這一層面Nginx基本上無對手,唯一可以對比Nginx的就只有 lighttpd了,不過 lighttpd目前還沒有做到Nginx完全的功能,配置也不那麼清晰易讀,社群資料也遠遠沒Nginx活躍。
Nginx也可作為靜態網頁和圖片伺服器,這方面的效能也無對手。還有Nginx社群非常活躍,第三方模組也很多。

**Nginx的缺點是:**
Nginx僅能支援http、https和Email協議,這樣就在適用範圍上面小些,這個是它的缺點。
對後端伺服器的健康檢查,只支援通過埠來檢測,不支援通過url來檢測。不支援Session的直接保持,但能通過ip_hash來解決。
LVS:使用Linux核心叢集實現一個高效能、高可用的負載均衡伺服器,它具有很好的可伸縮性(Scalability)、可靠性(Reliability)和可管理性(Manageability)。

**LVS的優點是:**

抗負載能力強、是工作在網路4層之上僅作分發之用,沒有流量的產生,這個特點也決定了它在負載均衡軟體裡的效能最強的,對記憶體和cpu資源消耗比較低。

配置性比較低,這是一個缺點也是一個優點,因為沒有可太多配置的東西,所以並不需要太多接觸,大大減少了人為出錯的機率。

工作穩定,因為其本身抗負載能力很強,自身有完整的雙機熱備方案,如LVS+Keepalived,不過我們在專案實施中用得最多的還是LVS/DR+Keepalived。

無流量,LVS只分發請求,而流量並不從它本身出去,這點保證了均衡器IO的效能不會受到大流量的影響。

應用範圍比較廣,因為LVS工作在4層,所以它幾乎可以對所有應用做負載均衡,包括http、資料庫、線上聊天室等等。

**LVS的缺點是:**

軟體本身不支援正規表示式處理,不能做動靜分離;而現在許多網站在這方面都有較強的需求,這個是Nginx/HAProxy+Keepalived的優勢所在。

如果是網站應用比較龐大的話,LVS/DR+Keepalived實施起來就比較複雜了,特別後面有 Windows Server的機器的話,如果實施及配置還有維護過程就比較複雜了,相對而言,Nginx/HAProxy+Keepalived就簡單多了。

**HAProxy的特點是:**

HAProxy也是支援虛擬主機的。

HAProxy的優點能夠補充Nginx的一些缺點,比如支援Session的保持,Cookie的引導;同時支援通過獲取指定的url來檢測後端伺服器的狀態。

HAProxy跟LVS類似,本身就只是一款負載均衡軟體;單純從效率上來講HAProxy會比Nginx有更出色的負載均衡速度,在併發處理上也是優於Nginx的。

HAProxy支援TCP協議的負載均衡轉發,可以對MySQL讀進行負載均衡,對後端的MySQL節點進行檢測和負載均衡,大家可以用LVS+Keepalived對MySQL主從做負載均衡。

HAProxy負載均衡策略非常多,HAProxy的負載均衡演算法現在具體有如下8種:

① roundrobin,表示簡單的輪詢,這個不多說,這個是負載均衡基本都具備的;

② static-rr,表示根據權重,建議關注;

③ leastconn,表示最少連線者先處理,建議關注;

④ source,表示根據請求源IP,這個跟Nginx的IP_hash機制類似,我們用其作為解決session問題的一種方法,建議關注;

⑤ ri,表示根據請求的URI;

⑥ rl_param,表示根據請求的URl引數’balance url_param’ requires an URL parameter name;

⑦ hdr(name),表示根據HTTP請求頭來鎖定每一次HTTP請求;

⑧ rdp-cookie(name),表示根據據cookie(name)來鎖定並雜湊每一次TCP請求。

**Nginx和LVS對比的總結:**

Nginx工作在網路的7層,所以它可以針對http應用本身來做分流策略,比如針對域名、目錄結構等,相比之下LVS並不具備這樣的功能,所以Nginx單憑這點可利用的場合就遠多於LVS了;但Nginx有用的這些功能使其可調整度要高於LVS,所以經常要去觸碰觸碰,觸碰多了,人為出問題的機率也就會大。

Nginx對網路穩定性的依賴較小,理論上只要ping得通,網頁訪問正常,Nginx就能連得通,這是Nginx的一大優勢!Nginx同時還能區分內外網,如果是同時擁有內外網的節點,就相當於單機擁有了備份線路;LVS就比較依賴於網路環境,目前來看伺服器在同一網段內並且LVS使用direct方式分流,效果較能得到保證。另外注意,LVS需要向託管商至少申請多一個ip來做Visual IP,貌似是不能用本身的IP來做VIP的。要做好LVS管理員,確實得跟進學習很多有關網路通訊方面的知識,就不再是一個HTTP那麼簡單了。

Nginx安裝和配置比較簡單,測試起來也很方便,因為它基本能把錯誤用日誌列印出來。LVS的安裝和配置、測試就要花比較長的時間了;LVS對網路依賴比較大,很多時候不能配置成功都是因為網路問題而不是配置問題,出了問題要解決也相應的會麻煩得多。

Nginx也同樣能承受很高負載且穩定,但負載度和穩定度差LVS還有幾個等級:Nginx處理所有流量所以受限於機器IO和配置;本身的bug也還是難以避免的。

Nginx可以檢測到伺服器內部的故障,比如根據伺服器處理網頁返回的狀態碼、超時等等,並且會把返回錯誤的請求重新提交到另一個節點。目前LVS中 ldirectd也能支援針對伺服器內部的情況來監控,但LVS的原理使其不能重發請求。比如使用者正在上傳一個檔案,而處理該上傳的節點剛好在上傳過程中出現故障,Nginx會把上傳切到另一臺伺服器重新處理,而LVS就直接斷掉了,如果是上傳一個很大的檔案或者很重要的檔案的話,使用者可能會因此而惱火。

Nginx對請求的非同步處理可以幫助節點伺服器減輕負載,假如使用 apache直接對外服務,那麼出現很多的窄帶連結時apache伺服器將會佔用大 量記憶體而不能釋放,使用多一個Nginx做apache代理的話,這些窄帶連結會被Nginx擋住,apache上就不會堆積過多的請求,這樣就減少了相當多的資源佔用。這點使用squid也有相同的作用,即使squid本身配置為不快取,對apache還是有很大幫助的。

Nginx能支援http、https和email(email的功能比較少用),LVS所支援的應用在這點上會比Nginx更多。在使用上,一般最前端所採取的策略應是LVS,也就是DNS的指向應為LVS均衡器,LVS的優點令它非常適合做這個任務。重要的ip地址,最好交由LVS託管,比如資料庫的 ip、webservice伺服器的ip等等,這些ip地址隨著時間推移,使用面會越來越大,如果更換ip則故障會接踵而至。所以將這些重要ip交給 LVS託管是最為穩妥的,這樣做的唯一缺點是需要的VIP數量會比較多。Nginx可作為LVS節點機器使用,一是可以利用Nginx的功能,二是可以利用Nginx的效能。當然這一層面也可以直接使用squid,squid的功能方面就比Nginx弱不少了,效能上也有所遜色於Nginx。Nginx也可作為中層代理使用,這一層面Nginx基本上無對手,唯一可以撼動Nginx的就只有lighttpd了,不過lighttpd目前還沒有能做到 Nginx完全的功能,配置也不那麼清晰易讀。另外,中層代理的IP也是重要的,所以中層代理也擁有一個VIP和LVS是最完美的方案了。具體的應用還得具體分析,如果是比較小的網站(日PV小於1000萬),用Nginx就完全可以了,如果機器也不少,可以用DNS輪詢,LVS所耗費的機器還是比較多的;大型網站或者重要的服務,機器不發愁的時候,要多多考慮利用LVS。
第一正規化:1NF是對屬性的原子性約束,要求屬性具有原子性,不可再分解;

第二正規化:2NF是對記錄的惟一性約束,要求記錄有惟一標識,即實體的惟一性;

第三正規化:3NF是對欄位冗餘性的約束,即任何欄位不能由其他欄位派生出來,它要求欄位沒有冗餘。。

正規化化設計優缺點:

優點:

可以儘量得減少資料冗餘,使得更新快,體積小

缺點:對於查詢需要多個表進行關聯,減少寫得效率增加讀得效率,更難進行索引優化

反正規化化:

優點:可以減少表得關聯,可以更好得進行索引優化

缺點:資料冗餘以及資料異常,資料得修改需要更多的成本
-   MyISAM支援表鎖,InnoDB支援表鎖和行鎖,預設為行鎖
-   表級鎖:開銷小,加鎖快,不會出現死鎖。鎖定粒度大,發生鎖衝突的概率最高,併發量最低
-   行級鎖:開銷大,加鎖慢,會出現死鎖。鎖力度小,發生鎖衝突的概率小,併發度最高
我們常用的運算元據庫語言SQL語句在執行的時候需要要先編譯,然後執行,而儲存過程(Stored Procedure)是一組為了完成特定功能的SQL語句集,經編譯後儲存在資料庫中,使用者通過指定儲存過程的名字並給定引數(如果該儲存過程帶有引數)來呼叫執行它。

一個儲存過程是一個可程式設計的函式,它在資料庫中建立並儲存。它可以有SQL語句和一些特殊的控制結構組成。當希望在不同的應用程式或平臺上執行相同的函式,或者封裝特定功能時,儲存過程是非常有用的。資料庫中的儲存過程可以看做是對程式設計中物件導向方法的模擬。它允許控制資料的訪問方式。

優點:

(1).儲存過程增強了SQL語言的功能和靈活性。儲存過程可以用流控制語句編寫,有很強的靈活性,可以完成複雜的判斷和較複雜的運算。

(2).儲存過程允許標準元件是程式設計。儲存過程被建立後,可以在程式中被多次呼叫,而不必重新編寫該儲存過程的SQL語句。而且資料庫專業人員可以隨時對儲存過程進行修改,對應用程式原始碼毫無影響。

(3).儲存過程能實現較快的執行速度。如果某一操作包含大量的Transaction-SQL程式碼或分別被多次執行,那麼儲存過程要比批處理的執行速度快很多。因為儲存過程是預編譯的。在首次執行一個儲存過程時查詢,優化器對其進行分析優化,並且給出最終被儲存在系統表中的執行計劃。而批處理的Transaction-SQL語句在每次執行時都要進行編譯和優化,速度相對要慢一些。

(4).儲存過程能過減少網路流量。針對同一個資料庫物件的操作(如查詢、修改),如果這一操作所涉及的Transaction-SQL語句被組織程儲存過程,那麼當在客戶計算機上呼叫該儲存過程時,網路中傳送的只是該呼叫語句,從而大大增加了網路流量並降低了網路負載。

(5).儲存過程可被作為一種安全機制來充分利用。系統管理員通過執行某一儲存過程的許可權進行限制,能夠實現對相應的資料的訪問許可權的限制,避免了非授權使用者對資料的訪問,保證了資料的安全。
事務(transaction)是作為一個單元的一組有序的資料庫操作。如果組中的所有操作都成功,則認為事務成功,即使只有一個操作失敗,事務也不成功。如果所有操作完成,事務則提交,其修改將作用於所有其他資料庫程式。如果一個操作失敗,則事務將回滾,該事務所有操作的影響都將取消。ACID 四大特性,原子性、隔離性、一致性、永續性。
檢視:檢視是一種虛擬的表,具有和物理表相同的功能。可以對檢視進行增,改,查,操作,檢視通常是有一個表或者多個表的行或列的子集。對檢視的修改不影響基本表。它使得我們獲取資料更容易,相比多表查詢。

遊標:是對查詢出來的結果集作為一個單元來有效的處理。遊標可以定在該單元中的特定行,從結果集的當前行檢索一行或多行。可以對結果集當前行做修改。一般不使用遊標,但是需要逐條處理資料的時候,遊標顯得十分重要。
(1)Where子句中:where表之間的連線必須寫在其他Where條件之前,那些可以過濾掉最大數量記錄的條件必須寫在Where子句的末尾.HAVING最後。

(2)用EXISTS替代IN、用NOT EXISTS替代NOT IN。

(3) 避免在索引列上使用計算

(4)避免在索引列上使用IS NULL和IS NOT NULL

(5)對查詢進行優化,應儘量避免全表掃描,首先應考慮在 where 及 order by 涉及的列上建立索引。  

(6)應儘量避免在 where 子句中對欄位進行 null 值判斷,否則將導致引擎放棄使用索引而進行全表掃描

(7)應儘量避免在 where 子句中對欄位進行表示式操作,這將導致引擎放棄使用索引而進行全表掃描
本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章