#
FTP服務主要提供上傳和下載功能。有時間需要我們測試服務器上傳和下載的性能。在這里我通過JMeter做一個FTP測試計劃的例子。
當然,JMeter官方網站的用戶手冊也有例子,但由于版本較早,我也算是對自己學習的一個總結,所以再整理一個。
* 本人使用的是JMeter2.4版本。
* 測試的服務器是IP:124.205.228.54 (由于找不到FTP站點,所以在“主機屋網站http://www.zhujiwu.com申請了一個免費的FTP空間”)
1.創建一個線程組

2.線程組--->添加--->配置元件--->FTP請求缺省值。

3.線程組--->添加--->Sampler--->FTP請求

說明:
IP 為你FTP服務的IP
Remote file 為你FTP服務器上的一個文件。
local file 為本地你存放到本機上的路徑。
選擇 get(RETR) 為下載方式。
填寫你的FTP服務器的用戶名密碼。
3.按照第二步的方式再添加一個“FTP請求”。

說明:
IP 為你FTP服務的IP
Remote file 為你要上傳到FTP服務器上的文件路徑及文件名
local file 為本地你要上傳的文件的路徑。
選擇 put(RETR) 為上傳方式。
填寫你的FTP服務器的用戶名密碼。
4.添加一個監控器:線程組--->添加--->監控器--->Spline Visualizer

一個FTP計劃創建成功 :)
參數化:簡單的來理解一下,我們錄制了一個腳本,這個腳本中有登錄操作,需要輸入用戶名和密碼,假如系統不允許相同的用戶名和密碼同時登錄,或者想更好的模擬多個用戶來登錄系統。
這個時候就需要對用戶名和密碼進行參數化,使每個虛擬用戶都使用不同的用戶名和密碼進行訪問。
前提:
假如,我們錄制好了一個腳本(可以用badboy工具錄制),在jmeter中打開,找到有用戶名和密碼的頁面。如下:

1.
我們需要“參數化”的數據,這里我用記事本寫了五個用戶名和密碼,保存為.dat格式的文件。

我將這個文件放在了我的( D:\test.dat )路徑下。關于如何得到成百上千的用戶名和密碼,首先要在數據庫中創建這些數據,將數據導出,整理保存,這里就不深究。
2.
好,我們要編寫函數來調用這個test.dat文件,怎么弄,
點擊菜單欄“選項”---->函數助手對話框,看下圖。

3.
把我們寫好的函數復制到“登錄”頁面用戶名和密碼胡位置。

好了,現在我們的參數化設置完成,在腳本的時候,會調用我們D盤下面的test.dat文件,第一列是用戶,第二列是密碼。
注意用戶名和密碼是一一對應的,中間用戶逗號(,)隔開。
這兩天接到一個任務,要測試一個服務器的性能,客戶要求向數據庫內 1000/s(每插入一千條數據) 的處理能力,當時腦子賭賽了,想的是用LR來進行,由于LR接觸不深,只知道LR實現參數化的時候可以調用數據庫里面的數據,往里面大批量的插入數據,以前沒試過。
翻閱了一下資料,找一到了一篇《一種特殊的數據庫性能測試》,大概思路是:通過編寫一java程序來循環插入數據,編寫一個批處理文件來調用java程序。再通過LR的system()函數來調用批處理文件來進行壓力測試。但是對于我這種菜鳥來說,好多細節不懂。比如那個批處理就讓我很為難。呵呵。
其實,通過jmeter很簡單就可以完成,可以參考我以前的一篇文章《jmeter創建數據庫(MySql)測試》。
前提條件:一個數據庫:test 數據庫下面有一張表:user 表中有兩個字段:username、passworld 。
要求:往數據庫內大批量插入數據,1000/s
其實和之前的方法一樣,為了簡單,我還是把截圖貼出來吧。
1.
創建一個測試計劃,將我們所使用的數據庫驅動包導入。

2.
添加一個線程組,并設置我們的虛擬用戶數、啟動時間、和循環次數

3.
創建一個線程,并在線程下面,創建一個JDBC Connection Configuration ,設置相關信息。

4.
創建一個JDBC Request.我們需要對數據庫做插入操作。(詳細設置,看截圖上的說明)

5.
添加監聽器,我們這里選擇添加“圖形結果”和“查看結果樹”,點擊菜單欄上的“啟動”--->運行。
查看我們的運行結果。


在測試的過程中,通過數據庫命令,可以查看當前數據庫插入了多少數據

Jmeter 是一個非常流行的性能測試工具,雖然與LoadRunner相比有很多不足,比如:它結果分析能力沒有LoadRunner詳細;很它的優點也有很多:
l 開源,他是一款開源的免費軟件,使用它你不需要支付任何費用,
l 小巧,相比LR的龐大(最新LR11將近4GB),它非常小巧,不需要安裝,但需要JDK環境,因為它是使用java開發的工具。
l 功能強大,jmeter設計之初只是一個簡單的web性能測試工具,但經過不段的更新擴展,現在可以完成數據庫、FTP、LDAP、WebService等方面的測試。因為它的開源性,當然你也可以根據自己的需求擴展它的功能。
我覺得它更像一個瑞士軍刀,小巧,且功能齊全。初次認識Jmeter的時候,我覺得它不好,是因為相比LR來說,它沒有腳本錄制功能,也許不是沒有,只是我不知道,因為文檔上介紹的是這樣,我要做一個web性能測試的話,就手動的一個個添加循環控制器、http信息管理頭、http請求等等各種元件。如果測試的腳本較多時,這無疑是個體力活。
Badboy是一款不錯web自動化測試工具,利用它來錄制腳本,并且錄制的腳本可以直接保存為JMeter文件來使用。我無疑給我們帶來了很大我方便。
----------------------我的環境------------
Badboy version 2.1.1
Apache JMeter-2.3.4 (需要JDK環境來運行)
--------------------------------------------
第一種方法:通過bodboy來錄制腳本。
1.打開人badboy工具,點擊工欄目上的紅色圓形按鈕,在地址欄目中輸入被測試項目的地址。

錄制完成后,點擊工具欄旁邊黑色按鈕,結束錄制。
選擇“文件”--àExport to Jmeter…

2.打開Jmeter工具,選擇“文件”-->“打開”選擇剛才保存的文件(.jmx類型),將文件導入進來了。

第二種方法,通過JMeter自身設置來錄制腳本。
這種方法是我才發現的(鄙視一下自己的無知,嘻嘻~!),覺得方法比較簡單。
<!--[if !supportLists]-->1. <!--[endif]-->打開JMeter工具
創建一個線程組(右鍵點擊“測試計劃”--->“添加”---->“線程組”)
創建一個http代理服務器(右鍵點擊“工作臺”--->“添加”--->“非測試元件”--->“http代理服務器”)
完整的設置參照下圖:

2. 下面來設置一下IE瀏覽器
IE--->“internet屬性”--->“連接”--->“局域網設置”

設置為本機IP就可以了,注意端口號要與Jmeter上的端口號一致。默認都是8080端口。
3. 現在點擊jmeter上的“啟動”按鈕,打開瀏覽器輸入需要錄制web項目地址,jmeter會自動記錄你IE所訪問的頁面。

PS:第二種方法是我剛才知道的一種,關于這兩種方法哪個更好,現在還不知道,但第二方法有通過IE瀏覽器輔助的,我想可能只要IE能打開的,它都能記錄,但它錄制的腳本看上去比較亂(感覺上)
還就是http代理服務器的設置,(比如:分組:每一個組放入一個新的服務器---只有這一個選項才能正常錄制),有時間再仔細比較一下兩種方法的不同之處。
對于,我們做測試的新手來說,自動化測試一直是一個比較高級的領域,當然是相對于手工測試來說。最近,對自動化測試產生了興趣。不,具體點應該是對selenium工具產生了興趣。為什么不是QTP呢,之前,QTP也有學習,后來還買了本《QTP自動化測試進階指南》,看了幾天,不知為什么看不下去。嗯!我一直偏愛于開源的技術和工具。最早用LR做性能測試,后來發現了JMeter那個小工具后,基本上能用JMeter解決的問題,就不在用LR了。開源的東西好處多多,當然了不足也多多。這里就不啰嗦了。呵呵。
下面說說selenium吧!想學一樣東西,找相關學習資料是第一步。說說我覺得比較好的資料:《selenium私房菜系列》、selenium官方文檔、《selenium 1.0 testing tools 》。不過,我還是買了一本書,我把在當當網的評論貼過來。
"本來想買,后來聽朋友說,內容行間距很大,有湊頁數的意思,前面部分是在翻譯(selenium)官網的文檔,包括后面也?有真正寫出作者公司的實戰經驗。打開一看基本和朋友說的一樣。為什么后來又要買了,有幾分無奈在里面。selenium 的中文資料并不多,網上的都是零散的皮毛,本人英語很差,所以,英文的資料看起來太吃力。《selenium 1.0 testing tools 》其實是一本很好的書,可惜沒有中文的,其實可以慢慢啃,但selenium 2.0都出來了,selenium RC 已經被selinum server替代,又加了很多新技術,跟不上啊。所以,只能選了這本書,希望對我有所幫助。" 下面我的筆記也算是基于《零成本實現web自動化測試---基于seleinum與Bromine》這本書的。
關于selenium IDE的安裝,請參考我的上一篇文章《selenium RC 配置》

為了方便簡潔,我們就按照上圖的數字標記介紹:
1。文件:創建、打開和保存測試案例和測試案例集。編輯:復制、粘貼、刪除、撤銷和選擇測試案例中的所有命令。Options : 用于設置seleniunm IDE。
2。用來填寫被測網站的地址。
3。速度控制:控制案例的運行速度。
4。運行所有:運行一個測試案例集中的所有案例。
5。運行:運行當前選定的測試案例。
6。暫停/恢復:暫停和恢復測試案例執行。
7。單步:可以運行一個案例中的一行命令。
8。錄制:點擊之后,開始記錄你對瀏覽器的操作。
9。案例集列表。
10。測試腳本;table標簽:用表格形式展現命令及參數。source標簽:用原始方式展現,默認是HTML語言格式,也可以用其他語言展示。
11。查看腳本運行通過/失敗的個數。
12。當選中前命令對應參數。
13。日志/參考/UI元素/Rollup
日志:當你運行測試時,錯誤和信息將會自定顯示。
參考:當在表格中輸入和編輯selenese命令時,面板中會顯示對應的參考文檔。
UI元素/Rollup:參考幫助菜單中的,UI-Element Documentation。
selenium為我們錄制的腳本不是100%符合我們的需求的,所以,編輯錄制的腳本是必不可少的工作。
1. 編輯一行命令或注釋。
在Table標簽下選中某一行命令,命令由command、Target、value三部分組成。可以對這三部分內容那進行編輯。

2. 插入命令。
在某一條命令上右擊,選擇“insert new command”命令,就可以插入一個空白,然后對空白行進程編輯。

3. 插入注解
以上面同樣的方式右擊選擇“insert new comment”命令插入注解空白行,本行內容不被執行,可以幫助我們更好的理解腳本,插入的內容以紫色字體顯示。

4. 移動命令或注解
有時我們需要移動某行命令的順序,我們只需要左擊鼠標拖動到相應的位置即可。

我們的錄制流程:
用火狐瀏覽器,打開一個新的標簽-----輸入谷歌網址(http://www.google.com.hk/)----在搜索框輸入:selenium----點擊“google搜索”按鈕。
注:注意開啟和關閉selenium IDE面板上的紅色圓形的錄制按鈕。
錄制的腳本:

1. 設置斷點。
要設置斷點,先選擇一行命令,點擊鼠標右鍵,在下拉菜單中選擇“Toggle Breakpoint”命令,點擊“運行”按鈕,腳本會運行到斷點處停止。用過myecilpse的debug功能來調試腳本的同學懂的!

2. 通過頁面源代碼來調試腳本
很多情況下,調試自動化測試案例都離不開查看頁面源代碼,我們可以借助firefox的firebug工具,關于firebug的安裝(瀏覽器菜單欄---工具---查看組件---搜索firebug---安裝并重啟瀏覽器即可)。
如:我們不確定或想獲得谷歌搜索按鈕的屬性。在按鈕上右擊---查看元素

在瀏覽器下方打開的firebug工具里面,就可以查看按鈕代碼了。

3. 定位輔助
當selenium IDE錄制腳本時,它會存儲額外的信息,支持用戶挑選其他格式的定位器來代替默認格式的定位器,這種特殊性對于學習定位器很有用。

我們可以選擇其他的命令來代替“name=btnG” 命令,當然,腳本依然是可以運行的。
安全測試應該是測試中非常重要的一部分,但他常常最容易被忽視掉。
盡管國內經常出現各種安全事件,但沒有真正的引起人們的注意。不管是開發還是測試都不太關注產品的安全。當然,這也不能怪我們苦B的“民工兄弟”。因為公司的所給我們的時間與精力只要求我們對產品的功能的實現以及保證功能的正常運行。一方面出于僥幸心理。誰沒事會攻擊我?
關于安全測試方面的資料也很少,很多人所知道的就是一本書,一個工具。
一本書值《web安全測試》,這應該是安全測試領域維數不多又被大家熟知的安全測試書,我曾看過前面幾個章節,唉,鄙視一下自己,做事總喜歡虎頭蛇尾。寫得非常好,介紹了許多安全方面的工具和知識。我覺得就算你不去做專業的安全開發\測試人員。起碼可以開闊你的視野,使你在做開發或測試時能夠考慮到產品安全方面的設計。防患于未然總是好的,如果你想成為一個優秀的人。
一個工具,其實本文也只是想介紹一下,這個工具----AappScan,IBM的這個web安全掃描工具被許多人熟知,相關資料也很多,因為我也摸了摸它的皮毛,所以也來人說兩句,呵呵!說起sappScan,對它也頗有些感情,因為,上一份工作的時候,我摸過于測試相關的許多工具,AappScan是其它一個,當時就覺得這工具這么強大,而且還這么傻瓜!!^_^! 于是,后面在面試的簡歷上寫了這個工具,應聘現在的這家公司,幾輪面試下來都問到過這個工具,因為現在這家公司一直在使用這個工具做安全方面的掃描。我想能來這家公司和我熟悉AappScan應該有一點點的關系吧!呵呵
AappScan下載與安裝
IBM官方下載;http://download2.boulder.ibm.com ... 2-AppScan_Setup.exe
本連接為7.8 簡體中文版本的
破解補丁;http://www.vdisk.cn/down/index/4760606A4753
破解補丁中有相應的注冊機與破解步驟,生成注冊碼做一下替換就OK了,這里不細說。

AppScan其實是一個產品家族,包括眾多的應用安全掃描產品,從開發階段的源代碼掃描的AppScan source edition,到針對WEB應用進行快速掃描的AppScan standard edition.以及進行安全管理和匯總整合的AppScan enterprise Edition等,我們經常說的AppScan就是指的桌面版本的AppScan,即AppScan standard edition.其安裝在Windows操作系統上,可以對網站等WEB應用進行自動化的應用安全掃描和測試。
使用AppScan來進行掃描
我們按照PDCA的方法論來進行規劃和討論; 建議的AppScan使用步驟:PDCA: Plan,Do,check, Action and Analysis.
計劃階段:明確目的,進行策略性的選擇和任務分解。
1) 明確目的:選擇合適的掃描策略
2) 了解對象:首先進行探索,了解網站結構和規模
3) 確定策略:進行對應的配置
a) 按照目錄進行掃描任務的分解
b) 按照掃描策略進行掃描任務的分解
執行階段:一邊掃描一遍觀察
4) 進行掃描
5) 先爬后掃(繼續僅測試)
檢查階段(Check)
6) 檢查和調整配置
結果分析(Analysis)
7) 對比結果
8) 匯總結果(整合和過濾)
AppScan的工作原理
當我們單擊“掃描”下面的小三角,可以出現如下的三個選型“繼續完全掃描”,“繼續僅探索”,“繼續僅測試“,有木有?什么意思? 理解了這個地方,就理解了AppScan的工作原理,我們慢慢展開:
還沒有正式開始,所以先不管“繼續“,直接來討論’完全掃描”,“僅探索”,“僅測試”三個名詞:
AppScan是對網站等WEB應用進行安全攻擊,通過真刀真槍的攻擊,來檢查網站是否存在安全漏洞;既然是攻擊,肯定要有明確的攻擊對象吧,比如北約現在的對象就是卡扎菲上校還有他的軍隊。對網站來說,一個網站存在的頁面,可能成千上萬。每個頁面也都可能存在多個字段(參數),比如一個登陸界面,至少要輸入用戶名和密碼吧,這就是一個頁面存在兩個字段,你提交了用戶名密碼等登陸信息,網站總要有地方接受并且檢查是否正確吧,這就可能存在一個新的檢查頁面。這里的每個頁面的每個參數都可能存在安全漏洞,所有都是被攻擊對象,都需要來檢查。
這就存在一個問題,你領命來檢查一個網站的安全性,這個網站有多少個頁面,有多少個參數,頁面之間如何跳轉,你可能很不明確,如何知道這些信息? 看起來很復雜,盤根錯節;那就更需要找到那個線索,提綱挈領; 那就想一想,訪問一個網站的時候,我們需要知道的最重要的信息是哪個?網站主頁地址吧? 從網站地址開始,很多其他頻道,其他頁面都可以鏈接過去,對不對,那么可不可以有種技術,告訴了它網站的入口地址,然后它“順藤摸瓜”,找出其他的網頁和頁面參數? OK,這就是”爬蟲” 技術,具體說,是”網站爬蟲“,其利用了網頁的請求都是用http協議發送的,發送和返回的內容都是統一的語言HTML,那么對HTML語言進行分析,找到里面的參數和鏈接,紀錄并繼續發送之,最終,找到了這個網站的眾多的頁面和目錄。這個能力AppScan就提供了,這里的術語叫“探索”,explorer,就是去發現,去分析,了解未知的,記錄。
在使用AppScan的時候,要配置的第一個就是要檢查的網站的地址,配置了以后,AppScan就會利用“探索”技術去發現這個網站存在多少個目錄,多少個頁面,頁面中有哪些參數等,簡單說,了解了你的網站的結構。
“探索”了解了,測試的目標和范圍就大致確定了,然后呢,利用“軍火庫”,發送導彈,進行安全攻擊,這個過程就是“測試”;針對發現的每個頁面的每個參數,進行安全檢查,檢查的彈藥就來自AppScan的掃描規則庫,其類似殺毒軟件的病毒庫,具體可以檢查的安全攻擊類型都在里面做好了,我們去使用即可。
那么什么是“完全測試呢”,完全測試就是把上面的兩個步驟整合起來,“探索”+ “測試”;在安全測試過程中,可以先只進行探索,不進行測試,目的是了解被測的網站結構,評估范圍; 然后選擇“繼續僅測試”,只對前面探索過的頁面進行測試,不對新發現的頁面進行測試。“完全測試”就是把兩個步驟結合在一起,一邊探索,一邊測試。
上圖更容易理解:

步驟1:探索(爬行,爬網)
步驟2:真對找到的頁面進行測試,生成安全攻擊
AppScan掃描大型網站
經常有客戶抱怨,說AppScan無法掃描大型的網站,或者是掃描接近完成時候無法保存,甚至保存后的結果文件下次無法打開?;同時大家又都很奇怪,作為一款業界出名的工具,如此的脆弱?是配置使用不當還是自己不太了解呢?我們今天就一起來討論下AppScan掃描大型網站會遇到的問題以及應對。
什么叫大型網站,顧名思義,網站規模大,具體說是頁面很多,內容很全。比如www.sina.com.cn,比如http://music.10086.cn/,都包括上萬個頁面。而且除了這個,可能還有一個特點---頁面參數多,即要填寫的地方多,和用戶的交互多;比如一個網站如果都是靜態頁面(.html,.jpg等),沒有讓用戶輸入的地方,那么可以利用,可以作為攻擊點的地方也就不多。如果頁面到處都是有輸入,有查詢,要求用戶來參與的,你輸入的越多,可能泄露的信息也越多,可能被別人利用的攻擊點也就越多,所以和頁面參數也是有關系的。AppScan聲稱測試用例的時候,也是根據每個參數來產生的,簡單說,如果一個參數,對應了200個安全攻擊測試用例,那么一個登陸界面至少就對應400個了,為什么?登陸界面至少有用戶名和密碼兩個字段吧? 每個字段200個攻擊用例。
這個簡單吧,還可以更復雜:如果遇到下面的兩個地址,那要掃描多少次呢?
http://www.cnblogs.com/fnng/focus/satisfy/file.jsp?id=1
http://www.cnblogs.com/fnng/focus/satisfy/file.jsp?id=2
上面的兩個地址有類似的,“?”號以前的URL地址完全一樣,”?”號后面帶的參數不同,這種可以認為是重復頁面,那么對于重復頁面,是否要重復測試呢?
這取決于“冗余路徑設置”,默認的是最多測試5次;即,這種類型URL出現的前5次,那么就是要測試1000個攻擊用例了。
如果再繼續修改下:遇到下面的URL呢
http://www.cnblogs.com/fnng/focus/satisfy/file.jsp?id=1&Item=open
http://www.cnblogs.com/fnng/focus/satisfy/file.jsp?id=2&Item=close
每個URL里面都有2個參數,測試的次數就更多了。想象下,如果這個網頁里面的參數如果是10個,或者更多的呢?比如很多網站提交注冊信息的時候,要填寫的內容足夠多吧?
要進行的安全測試用例也就隨之不斷增加…
這是網站規模的影響,還有一個問題,就出在“每個參數,發送200個安全測試用例”這個假設上。這個假設的前提來源于哪里? 來源于我們選擇的掃描規則庫。即你關心那些安全威脅,這個需要在測試策略里面選擇。同樣來參照殺毒軟件,你會用殺毒軟件來查找一些專用的病毒嗎,比如CIH,比如木馬;應用安全掃描也是一樣的道理,如果有明確的安全指標或者安全規則范圍,那么就選擇之。這些可能來源于企業的規范,來源于政府的法律法規。就要根據你的理解,在這里選擇。

很多時候,我們也很難在最開始的階段,就把掃描規范制定下來,按照項目經理們的口頭禪“漸進明細”,“滾動式規劃”,在實踐中,更多時候也是摸著石頭過河,選擇了一個掃描策略,然后根據結果分析,看是否需要調整,不斷優化。比如選擇默認的“缺省值’掃描策略,對網站進行掃描,發現其”敏感信息“里面會去檢查頁面上是否含有Email地址,是否含有信用卡號碼等,如果我們覺得這些信息,顯示在頁面上是正常的業務需要, 我們就可以取消掉這些規則,所以掃描規則也很大程度上影響著我們的掃描效率。
1.首先我們要有一個可以做測試的數據庫,當然,里面要有數據,不然怎么測呢?我的上一篇文章《Eclipse連接MySQL數據庫(傻瓜篇)》,里面教你如何通過程序批量插入數據。
來看一下我的數據:

我可能有點啰嗦 :) 不管你用什么方式,你的數據庫里要有點數據。
2.
打開JMeter,點擊測試計劃,

點擊“瀏覽...”按鈕,將你的JDBC驅動添加進來。
3.
添加一個線程組,
右鍵點擊“線程組”,在下面添加一個“JDBC Connection Configuration”

來配置一下JDBC Connection Configuration頁面。

4.
右鍵點擊“線程組”,在下面添加一個“JDBC request”

5.
添加斷言。
右鍵點擊線程組---->添加--->斷言---->響應斷言。

6.
我們來添加一些監聽器來行查看
添加一個斷言結果:
右鍵點擊線程組---->添加--->監聽器---->結果斷言。
添加一個圖形結果:
右鍵點擊線程組---->添加--->監聽器---->圖形結果。
添加一個查看結果樹:
右鍵點擊線程組---->添加--->監聽器---->查看結果樹。
下面是添加所有東東的列表:

7.
在線程組頁面設置用戶數、啟動時間、循環次數
點擊菜單欄“運行”----“啟動”
下面是結果:

其它的結果圖片就不貼了。嘻嘻!!用圖片說話,看上去簡單,但比較長。。
---添加主鍵約束
alter table 表名
add constraint 約束名 primary key (主鍵)
---添加唯一約束
alter table 表名
add constraint 約束名 unique (字段)
---添加默認約束
alter table 表名
add constraint 約束名 default ('默認內容') for 字段
--添加檢查check約束,要求字段只能在1到100之間
alter table 表名
add constraint 約束名 check (字段 between 1 and 100 )
---添加外鍵約束(主表stuInfo和從表stuMarks建立關系,關聯字段為stuNo)
alter table 從表
add constraint 約束名
foreign key(關聯字段) references 主表(關聯字段)
GO
sql server中刪除約束的語句是:
alter table 表名 drop constraint 約束名
sp_helpconstraint 表名 找到數據表中的所有列的約束
-----------在創建表時創建約束------------
7.2.1 主關鍵字約束
主關鍵字約束指定表的一列或幾列的組合的值在表中具有惟一性,即能惟一地指定一行記錄。每個表中只能有一列被指定為主關鍵字,且IMAGE 和TEXT 類型的列不能被指定為主關鍵字,也不允許指定主關鍵字列有NULL 屬性。
定義主關鍵字約束的語法如下:
CONSTRAINT constraint_name
PRIMARY KEY [CLUSTERED | NONCLUSTERED]
(column_name1[, column_name2,…,column_name16])
各參數說明如下:
constraint_name
指定約束的名稱約束的名稱。在數據庫中應是惟一的。如果不指定,則系統會自動生成一個約束名。
CLUSTERED | NONCLUSTERED
指定索引類別,CLUSTERED 為缺省值。其具體信息請參見下一章。
column_name
指定組成主關鍵字的列名。主關鍵字最多由16 個列組成。
例7-3: 創建一個產品信息表,以產品編號和名稱為主關鍵字
create table products (
p_id char(8) not null,
p_name char(10) not null ,
price money default 0.01 ,
quantity smallint null ,
constraint pk_p_id primary key (p_id, p_name)
) on [primary]
7.2.2 外關鍵字約束
外關鍵字約束定義了表之間的關系。當一個表中的一個列或多個列的組合和其它表中的主關鍵字定義相同時,就可以將這些列或列的組合定義為外關鍵字,并設定它適合哪個表中哪些列相關聯。這樣,當在定義主關鍵字約束的表中更新列值,時其它表中有與之相關聯的外關鍵字約束的表中的外關鍵字列也將被相應地做相同的更新。外關鍵字約束的作用還體現在,當向含有外關鍵字的表插入數據時,如果與之相關聯的表的列中無與插入的外關鍵字列值相同的值時,系統會拒絕插入數據。與主關鍵字相同,不能使用一個定義為 TEXT 或IMAGE 數據類型的列創建外關鍵字。外關鍵字最多由16 個列組成。
定義外關鍵字約束的語法如下:
CONSTRAINT constraint_name
FOREIGN KEY (column_name1[, column_name2,…,column_name16])
REFERENCES ref_table [ (ref_column1[,ref_column2,…, ref_column16] )]
[ ON DELETE { CASCADE | NO ACTION } ]
[ ON UPDATE { CASCADE | NO ACTION } ] ]
[ NOT FOR REPLICATION ]
各參數說明如下:
REFERENCES
指定要建立關聯的表的信息。
ref_table
指定要建立關聯的表的名稱。
ref_column
指定要建立關聯的表中的相關列的名稱。
ON DELETE {CASCADE | NO ACTION}
指定在刪除表中數據時,對關聯表所做的相關操作。在子表中有數據行與父表中的對應數據行相關聯的情況下,如果指定了值CASCADE,則在刪除父表數據行時會將子表中對應的數據行刪除;如果指定的是NO ACTION,則SQL Server 會產生一個錯誤,并將父表中的刪除操作回滾。NO ACTION 是缺省值。
ON UPDATE {CASCADE | NO ACTION}
指定在更新表中數據時,對關聯表所做的相關操作。在子表中有數據行與父表中的對應數據行相關聯的情況下,如果指定了值CASCADE,則在更新父表數據行時會將子表中對應的數據行更新;如果指定的是NO ACTION,則SQL Server 會產生一個錯誤,并將父表中的更新操作回滾。NO ACTION 是缺省值。
NOT FOR REPLICATION
指定列的外關鍵字約束在把從其它表中復制的數據插入到表中時不發生作用。
例7-4:創建一個訂貨表,與前面創建的產品表相關聯
create table orders(
order_id char(8),
p_id char(8),
p_name char(10) ,
constraint pk_order_id primary key (order_id) ,
foreign key(p_id, p_name) references products(p_id, p_name)
) on [primary]
注意:臨時表不能指定外關鍵字約束。
7.2.3 惟一性約束
惟一性約束指定一個或多個列的組合的值具有惟一性,以防止在列中輸入重復的值。惟一性約束指定的列可以有NULL 屬性。由于主關鍵字值是具有惟一性的,因此主關鍵字列不能再設定惟一性約束。惟一性約束最多由16 個列組成。
定義惟一性約束的語法如下:
CONSTRAINT constraint_name
UNIQUE [CLUSTERED | NONCLUSTERED]
(column_name1[, column_name2,…,column_name16])
例7-5:定義一個員工信息表,其中員工的身份證號具有惟一性。
create table employees (
emp_id char(8),
emp_name char(10) ,
emp_cardid char(18),
constraint pk_emp_id primary key (emp_id),
constraint uk_emp_cardid unique (emp_cardid)
) on [primary]
7.2.4 檢查約束
檢查約束對輸入列或整個表中的值設置檢查條件,以限制輸入值,保證數據庫的數據完整性。可以對每個列設置符合檢查。
定義檢查約束的語法如下:
CONSTRAINT constraint_name
CHECK [NOT FOR REPLICATION]
(logical_expression)
各參數說明如下:
NOT FOR REPLICATION
指定檢查約束在把從其它表中復制的數據插入到表中時不發生作用。
logical_expression
指定邏輯條件表達式返回值為TRUE 或FALSE。
例7-6: 創建一個訂貨表其中定貨量必須不小于10。
create table orders(
order_id char(8),
p_id char(8),
p_name char(10) ,
quantity smallint,
constraint pk_order_id primary key (order_id),
constraint chk_quantity check (quantity>=10) ,
) on [primary]
注意:對計算列不能作除檢查約束外的任何約束。
7.2.5 缺省約束
缺省約束通過定義列的缺省值或使用數據庫的缺省值對象綁定表的列,來指定列的缺省值。SQL Server 推薦使用缺省約束,而不使用定義缺省值的方式來指定列的缺省值。有關綁定缺省約束的方法請參見“數據完整性”章節。
定義缺省約束的語法如下:
CONSTRAINT constraint_name
DEFAULT constant_expression [FOR column_name]
例7-7:
constraint de_order_quantity default 100 for order_quantity
注意:不能在創建表時定義缺省約束,只能向已經創建好的表中添加缺省約束。
7.2.6 列約束和表約束
對于數據庫來說,約束又分為列約束(Column Constraint)和表約束(Table Constraint)。
列約束作為列定義的一部分只作用于此列本身。表約束作為表定義的一部分,可以作用于
多個列。
下面舉例說明列約束與表約束的區別。
例7-8:
create table products (
p_id char(8) ,
p_name char(10) ,
price money default 0.01 ,
quantity smallint check (quantity>=10) , /* 列約束 */
constraint pk_p_id primary key (p_id, p_name) /* 表約束 */
/*--示例說明
示例在數據庫pubs中創建一個擁有表jobs的所有權限、擁有表titles的SELECT權限的角色r_test
隨后創建了一個登錄l_test,然后在數據庫pubs中為登錄l_test創建了用戶賬戶u_test
同時將用戶賬戶u_test添加到角色r_test中,使其通過權限繼承獲取了與角色r_test一樣的權限
最后使用DENY語句拒絕了用戶賬戶u_test對表titles的SELECT權限。
經過這樣的處理,使用l_test登錄SQL Server實例后,它只具有表jobs的所有權限。
--*/
USE pubs
--創建角色 r_test
EXEC sp_addrole 'r_test'
--授予 r_test 對 jobs 表的所有權限
GRANT ALL ON jobs TO r_test
--授予角色 r_test 對 titles 表的 SELECT 權限
GRANT SELECT ON titles TO r_test
--添加登錄 l_test,設置密碼為pwd,默認數據庫為pubs
EXEC sp_addlogin 'l_test','pwd','pubs'
--為登錄 l_test 在數據庫 pubs 中添加安全賬戶 u_test
EXEC sp_grantdbaccess 'l_test','u_test'
--添加 u_test 為角色 r_test 的成員
EXEC sp_addrolemember 'r_test','u_test'
--拒絕安全賬戶 u_test 對 titles 表的 SELECT 權限
DENY SELECT ON titles TO u_test
/*--完成上述步驟后,用 l_test 登錄,可以對jobs表進行所有操作,但無法對titles表查詢,雖然角色 r_test 有titles表的select權限,但已經在安全賬戶中明確拒絕了對titles的select權限,所以l_test無titles表的select權限--*/
--從數據庫 pubs 中刪除安全賬戶
EXEC sp_revokedbaccess 'u_test'
--刪除登錄 l_test
EXEC sp_droplogin 'l_test'
--刪除角色 r_test
EXEC sp_droprole 'r_test'
- SQL code
--1. 創建示例環境。
首先使用下面的代碼創建一個登錄l_test,并且為登錄在數據庫pubs中創建關聯的用戶賬戶u_test,并且授予用戶賬戶u_test對表titles的SELECT權限,用以實現登錄l_test連接到SQL Server實例后,可以訪問表titles。然后創建了一個應用程序角色r_p_test,授予該角色對表jobs的SELECT權限,用以實現激活r_p_test時,允許訪問特定的表jobs。
USE pubs
--創建一個登錄 l_test, 密碼 pwd, 默認數據庫 pubs
EXEC sp_addlogin 'l_test','pwd','pubs'
--為登錄 l_test 在數據庫 pubs 中添加安全賬戶 u_test
EXEC sp_grantdbaccess 'l_test','u_test'
--授予安全賬戶 u_test 對 titles 表的 SELECT 權限
GRANT SELECT ON titles TO u_test
--創建一個應用程序角色 r_p_test, 密碼 abc
EXEC sp_addapprole 'r_p_test','abc'
--授予角色 r_p_test 對 jobs 表的 SELECT 權限
GRANT SELECT ON jobs TO r_p_test
GO
--2. 激活應用程序角色。
/*--激活說明
示例環境創建完成后,在任何地方(比如查詢分析器、應用程序)
使用登錄l_test連接SQL Server實例,均只能訪問表titles,或者是guest用戶
和public角色允許訪問的對象。
如果要在某些特定的應用程序中,允許登錄訪問表jobs,那么,
可以激活應用程序角色r_p_test,激活應用程序角色后,登錄本身的權限會消失。
下面在查詢分析器中登錄,演示激活應用程序角色r_p_test前后對數據訪問的區別。
--*/
--激活應用程序角色 r_p_test 前,登錄具有表 titles 的訪問權,但無表 jobs 的訪問權
SELECT titles_count=COUNT(*) FROM titles
SELECT jobs_count=COUNT(*) FROM jobs
/*--結果:
titles_count
------------
18
(所影響的行數為 1 行)
服務器: 消息 229,級別 14,狀態 5,行 2
拒絕了對對象 'jobs'(數據庫 'pubs',所有者 'dbo')的 SELECT 權限。
--*/
GO
--用密碼 abc 激活 r_p_test 應用程序角色,并且在將此密碼發送到SQL Server之前對其加密
EXEC sp_setapprole 'r_p_test',{Encrypt N'abc'},'ODBC'
GO
--激活應用程序角色 r_p_test 后,登錄失去表 titles 的訪問權,獲取表 jobs 的訪問權
SELECT titles_count=COUNT(*) FROM titles
SELECT jobs_count=COUNT(*) FROM jobs
/*--結果
服務器: 消息 229,級別 14,狀態 5,行 2
拒絕了對對象 'titles'(數據庫 'pubs',所有者 'dbo')的 SELECT 權限。
jobs_count
-----------
14
(所影響的行數為 1 行)
--*/
- SQL code
exec sp_dropsrvrolemember N'aa', sysadmin
go
exec sp_addsrvrolemember N'aa', securityadmin
go
--作好SQL的安全管理
--作者:鄒建
首先,做好用戶安全:
--簡單的,只允許sql的用戶訪問sql(防止利用administrator組用戶訪問)
1.企業管理器--右鍵SQL實例--屬性--安全性--身份驗證--選擇"sql server和windows"--確定
2.企業管理器--安全性--登陸--右鍵sa--設置密碼--其他用戶也設置密碼
3.刪除用戶:
BUILTIN\Administrators
<機器名>\Administrator --這個用戶不一定有
這樣可以防止用windows身份登陸SQL
4.設置進入企業管理器需要輸入密碼
在企業管理器中
--右鍵你的服務器實例(就是那個有綠色圖標的)
--編輯SQL Server注冊屬性
--選擇"使用 SQL Server 身份驗證"
--并勾選"總是提示輸入登錄名和密碼"
--確定
--經過上面的設置,你的SQL Server基本上算是安全了.
------------------------------------------------------------------------
其次,改默認端口,隱藏服務器,減少被攻擊的可能性
SQL Server服務器
--開始
--程序
--Microsoft SQL Server
--服務器網絡實用工具
--啟用的協議中"TCP/IP"
--屬性
--默認端口,輸入一個自已定義的端口,比如2433
--勾選隱藏服務器
----------------------------------------------------------------------------
--管好sql的用戶,防止訪問他不該訪問的數據庫(總控制,明細還可以控制他對于某個數據庫的具體對象具有的權限)
--切換到你新增的用戶要控制的數據庫
use 你的庫名
go
--新增用戶
exec sp_addlogin 'test' --添加登錄
exec sp_grantdbaccess N'test' --使其成為當前數據庫的合法用戶
exec sp_addrolemember N'db_owner', N'test' --授予對自己數據庫的所有權限
--這樣創建的用戶就只能訪問自己的數據庫,及數據庫中包含了guest用戶的公共表
go
--刪除測試用戶
exec sp_revokedbaccess N'test' --移除對數據庫的訪問權限
exec sp_droplogin N'test' --刪除登錄
如果在企業管理器中創建的話,就用:
企業管理器--安全性--右鍵登錄--新建登錄
常規項
--名稱中輸入用戶名
--身份驗證方式根據你的需要選擇(如果是使用windows身份驗證,則要先在操作系統的用戶中新建用戶)
--默認設置中,選擇你新建的用戶要訪問的數據庫名
服務器角色項
這個里面不要選擇任何東西
數據庫訪問項
勾選你創建的用戶需要訪問的數據庫名
數據庫角色中允許,勾選"public","db_ownew"
確定,這樣建好的用戶與上面語句建立的用戶一樣
---------------------------------------------------------------------------
最后一步,為具體的用戶設置具體的訪問權限,這個可以參考下面的最簡示例:
--添加只允許訪問指定表的用戶:
exec sp_addlogin '用戶名','密碼','默認數據庫名'
--添加到數據庫
exec sp_grantdbaccess '用戶名'
--分配整表權限
GRANT SELECT , INSERT , UPDATE , DELETE ON table1 TO [用戶名]
--分配權限到具體的列
GRANT SELECT , UPDATE ON table1(id,AA) TO [用戶名]
-------------------------------------------------------------------
至于具體的安全設置和理論知道,參考SQL聯機幫助
- SQL code
/*--創建一個只允許特定程序使用的數據庫用戶
創建一個用戶,這個用戶只有用我們特定的應用程序登錄
才具有訪問數據庫的權限,用其他工具登錄沒有任何權限
在下面的示例中,演示了如何控制登錄l_test
使其登錄后只允許訪問pubs數據庫的titles表
而對jobs表的訪問權限,只允許在某些許可的應用程序中訪問。
--鄒建 2004.09(引用請保留此信息)--*/
--創建測試環境
USE pubs
--創建一個登錄 l_test, 密碼 pwd, 默認數據庫 pubs
EXEC sp_addlogin 'l_test','pwd','pubs'
--為登錄 l_test 在數據庫 pubs 中添加安全帳戶 u_test
EXEC sp_grantdbaccess 'l_test','u_test'
--授予安全帳戶 u_test 對 titles 表的 SELECT 權限
GRANT SELECT ON titles TO u_test
--創建一個應用程序角色 r_p_test, 密碼 abc
EXEC sp_addapprole 'r_p_test','abc'
--授予角色 r_p_test 對 jobs 表的 SELECT 權限
GRANT SELECT ON jobs TO r_p_test
GO
--創建好上面的測試后,現在來測試如何使用應用程序角色
--我們把用戶及密碼告訴使用者,即告訴使用者,用戶是: l_test,密碼是: pwd
--使用者可以用我們這個用戶在任何地方登錄,包含查詢分析器
--但是,用戶只能訪問 titles 表,不能訪問其他對象,如果建立用戶時不授予它任何權限,則它不訪問除guest用戶和public角色允許訪問外的任何對象
--OK,到這里,我們是把用戶控制住了
--下面我們再來說在程序中的處理,因為用戶在程序中登錄后,需要對jobs表有訪問權限的
--我們只需要在用戶登錄后,執行一句
EXEC sp_setapprole 'r_p_test',{Encrypt N'abc'},'ODBC'
--這樣,我們登錄的用戶就轉變為 r_p_test 角色的權限,而它自身的權限丟失
--只要這個用戶不退出應用程序,他的權限就會保持
--如果用戶退出了當前應用程序,則他的權限自動收回
--同時,這個用戶即使沒有退出應用程序,他也是只在我們的應用程序中有權限,在其他地方登錄,也不會有權限
--因為這個密碼我們是不用給用戶的,所以,用戶沒有這個角色的密碼,也就限制了他只能在程序中使用我們的數據
--激活應用程序角色 r_p_test 前,登錄具有表 titles 的訪問權,但無表 jobs 的訪問權
SELECT titles_count=COUNT(*) FROM titles
SELECT jobs_count=COUNT(*) FROM jobs
/*--結果:
titles_count
------------
18
(所影響的行數為 1 行)
服務器: 消息 229,級別 14,狀態 5,行 2
拒絕了對對象 'jobs'(數據庫 'pubs',所有者 'dbo')的 SELECT 權限。
--*/
GO
--用密碼 abc 激活 r_p_test 應用程序角色,并且在將此密碼發送到SQL Server之前對其加密
EXEC sp_setapprole 'r_p_test',{Encrypt N'abc'},'ODBC'
GO
--激活應用程序角色 r_p_test 后,登錄失去表 titles 的訪問權,獲取表 jobs 的訪問權
SELECT titles_count=COUNT(*) FROM titles
SELECT jobs_count=COUNT(*) FROM jobs
/*--結果
服務器: 消息 229,級別 14,狀態 5,行 2
拒絕了對對象 'titles'(數據庫 'pubs',所有者 'dbo')的 SELECT 權限。
jobs_count
-----------
14
(所影響的行數為 1 行)
--*/
go
--刪除測試
EXEC sp_dropapprole 'r_p_test'
EXEC sp_revokedbaccess 'u_test'
EXEC sp_droplogin 'l_test'
1.盡量靜態化:
如果一個方法能被靜態,那就聲明它為靜態的,速度可提高1/4,甚至我測試的時候,這個提高了近三倍。
當然了,這個測試方法需要在十萬級以上次執行,效果才明顯。
其實靜態方法和非靜態方法的效率主要區別在內存:靜態方法在程序開始時生成內存,實例方法在程序運行中生成內存,所以靜態方法可以直接調用,實例方法要先成生實例,通過實例調用方法,靜態速度很快,但是多了會占內存。
任何語言都是對內存和磁盤的操作,至于是否面向對象,只是軟件層的問題,底層都是一樣的,只是實現方法不同。靜態內存是連續的,因為是在程序開始時就生成了,而實例申請的是離散的空間,所以當然沒有靜態方法快。
靜態方法始終調用同一塊內存,其缺點就是不能自動進行銷毀,而是實例化可以銷毀。
2.echo的效率高于print,因為echo沒有返回值,print返回一個整型;
測試:
Echo
0.000929 - 0.001255 s (平均 0.001092 seconds)
Print
0.000980 - 0.001396 seconds (平均 0.001188 seconds)
相差8%左右,總體上echo是比較快的。
注意,echo大字符串的時候,如果沒有做調整就嚴重影響性能。使用打開apached的mod_deflate進行壓縮或者打開ob_start先將內容放進緩沖區。
3.在循環之前設置循環的最大次數,而非在在循環中;
傻子都明白的道理。
4.銷毀變量去釋放內存,特別是大的數組;
數組和對象在php特別占內存的,這個由于php的底層的zend引擎引起的,
一般來說,PHP數組的內存利用率只有 1/10, 也就是說,一個在C語言里面100M 內存的數組,在PHP里面就要1G。
特別是在PHP作為后臺服務器的系統中,經常會出現內存耗費太大的問題。
5.避免使用像__get, __set, __autoload等魔術方法;
對于__開頭的函數就命名為魔術函數,此類函數都在特定的條件下初訪的。總得來說,有下面幾個魔術函數
__construct(),__destruct(),__get(),__set(),__unset(),__call(),__callStatic(),__sleep(),__wakeup(),__toString(),__set_state(),__clone(),__autoload()
其實,如果__autoload不能高效的將類名與實際的磁盤文件(注意,這里指實際的磁盤文件,而不僅僅是文件名)對應起來,系統將不得不做大量的文件是 否存在(需要在每個include path中包含的路徑中去尋找)的判斷,而判斷文件是否存在需要做磁盤I/O操作,眾所周知磁盤I/O操作的效率很低,因此這才是使得autoload機制效率降低的原因。
因此,我們在系統設計時,需要定義一套清晰的將類名與實際磁盤文件映射的機制。這個規則越簡單越明確,autoload機制的效率就越高。
結論:autoload機制并不是天然的效率低下,只有濫用autoload,設計不好的自動裝載函數才會導致其效率的降低.
所以說盡量避免使用__autoload魔術方法,有待商榷。
6.requiere_once()比較耗資源;
這是因為requiere_once需要判斷該文件是否被引用過),所以能不用盡量不用。常用require/include方法避免。
7.在includes和requires中使用絕對路徑。
如果包含相對路徑,PHP會在include_path里面遍歷查找文件。
用絕對路徑就會避免此類問題,因此解析操作系統路徑所需的時間會更少。
8.如果你需要得到腳本執行時的時間,$_SERVER['REQUSET_TIME']優于time();
可以想象。一個是現成就可以直接用,一個還需要函數得出的結果。
9.能用PHP內部字符串操作函數的情況下,盡量用他們,不要用正則表達式; 因為其效率高于正則;
沒得說,正則最耗性能。
有沒有你漏掉的好用的函數?例如:strpbrk()strncasecmp()strpos()/strrpos()/stripos()/strripos()加速 strtr如果需要轉換的全是單個字符的時候,
用字符串而不是數組來做 strtr:
<?php
$addr = strtr($addr, "abcd", "efgh"); // good
$addr = strtr($addr, array('a' => 'e', )); // bad
?>
效率提升:10 倍。
10.str_replace字符替換比正則替換preg_replace快,但strtr比str_replace又快1/4;
另外不要做無謂的替換即使沒有替換,str_replace 也會為其參數分配內存。很慢!解決辦法:
用 strpos 先查找(非常快),看是否需要替換,如果需要,再替換效率:- 如果需要替換:效率幾乎相等,差別在 0.1% 左右。
如果不需要替換:用 strpos 快 200%。
11.參數為字符串
如果一個函數既能接受數組又能接受簡單字符做為參數,例如字符替換函數,并且參數列表不是太長,可以考慮額外寫一段替換代碼,使得每次傳遞參數都是一 個字符,而不是接受數組做為查找和替換參數。大事化小,1+1>2;
12.最好不用@,用@掩蓋錯誤會降低腳本運行速度;
用@實際上后臺有很多操作。用@比起不用@,效率差距:3 倍。特別不要在循環中使用@,在 5 次循環的測試中,即使是先用 error_reporting(0) 關掉錯誤,在循環完成后再打開,都比用@快。
13.$row['id']比$row[id]速度快7倍
建議養成數組鍵加引號的習慣;
14.在循環里別用函數
例如For($x=0; $x < count($array); $x), count()函數在外面先計算;原因你懂的。
16.在類的方法里建立局部變量速度最快,幾乎和在方法里調用局部變量一樣快;
17.建立一個全局變量要比局部變量要慢2倍;
由于局部變量是存在棧中的,當一個函數占用的棧空間不是很大的時候,這部分內存很有可能全部命中cache,這時候CPU訪問的效率是很高的。
相反,如果一個函數里既使用了全局變量又使用了局部變量,那么當這兩段地址相差較大時,cpu cache需要來回切換,那么效率會下降。
(我理解啊)
18.建立一個對象屬性(類里面的變量)例如($this->prop++)比局部變量要慢3倍;
19.建立一個未聲明的局部變量要比一個已經定義過的局部變量慢9-10倍
20.聲明一個未被任何一個函數使用過的全局變量也會使性能降低(和聲明相同數量的局部變量一樣)。
PHP可能去檢查這個全局變量是否存在;
21.方法的性能和在一個類里面定義的方法的數目沒有關系
因為我添加10個或多個方法到測試的類里面(這些方法在測試方法的前后)后性能沒什么差異;
22.在子類里方法的性能優于在基類中;
23.只調用一個參數并且函數體為空的函數運行花費的時間等于7-8次$localvar++運算,而一個類似的方法(類里的函數)運行等于大約15次$localvar++運算;
24 用單引號代替雙引號來包含字符串,這樣做會更快一些。
因為PHP會在雙引號包圍的字符串中搜尋變量,單引號則不會。
PHP 引擎允許使用單引號和雙引號來封裝字符串變量,但是這個是有很大的差別的!使用雙引號的字符串告訴 PHP 引擎首先去讀取字符串內容,查找其中的變 量,并改為變量對應的值。一般來說字符串是沒有變量的,所以使用雙引號會導致性能不佳。最好是使用字
符串連接而不是雙引號字符串。
BAD:
$output = "This is a plain string";
GOOD:
$output = 'This is a plain string';
BAD:
$type = "mixed";
$output = "This is a $type string";
GOOD:
$type = 'mixed';
$output = 'This is a ' . $type .' string';
25.當echo字符串時用逗號代替點連接符更快些。
echo一種可以把多個字符串當作參數的“函數”(譯注:PHP手冊中說echo是語言結構,不是真正的函數,故把函數加上了雙引號)。
例如echo $str1,$str2。
26.Apache解析一個PHP腳本的時間要比解析一個靜態HTML頁面慢2至10倍。
盡量多用靜態HTML頁面,少用腳本。
28.盡量使用緩存,建議用memcached。
高性能的分布式內存對象緩存系統,提高動態網絡應用程序性能,減輕數據庫的負擔;
也對運算碼 (OP code)的緩存很有用,使得腳本不必為每個請求做重新編譯。
29.使用ip2long()和long2ip()函數把IP地址轉成整型存放進數據庫而非字符型。
這幾乎能降低1/4的存儲空間。同時可以很容易對地址進行排序和快速查找;
30.使用checkdnsrr()通過域名存在性來確認部分email地址的有效性
這個內置函數能保證每一個的域名對應一個IP地址;
31.使用mysql_*的改良函數mysqli_*;
32.試著喜歡使用三元運算符(?:);
33.是否需要PEAR
在你想在徹底重做你的項目前,看看PEAR有沒有你需要的。PEAR是個巨大的資源庫,很多php開發者都知道;
35.使用error_reporting(0)函數來預防潛在的敏感信息顯示給用戶。
理想的錯誤報告應該被完全禁用在php.ini文件里。可是如果你在用一個共享的虛擬主機,php.ini你不能修改,那么你最好添加error_reporting(0)函數,放在每個腳本文件的第一行(或用
require_once()來加載)這能有效的保護敏感的SQL查詢和路徑在出錯時不被顯示;
36.使用 gzcompress() 和gzuncompress()對容量大的字符串進行壓縮(解壓)在存進(取出)數據庫時。
這種內置的函數使用gzip算法能壓縮到90%;
37.通過參數變量地址得引用來使一個函數有多個返回值。
你可以在變量前加個“&”來表示按地址傳遞而非按值傳遞;
38. 完全理解魔術引用和SQL注入的危險。
Fully understand “magic quotes” and the dangers of SQL injection. I’m hoping that most developers reading this are already familiar with SQL injection. However, I list it here because it’s absolutely critical to understand. If you’ve never heard the term before, spend the entire rest of the day googling and reading.
39.某些地方使用isset代替strlen
當操作字符串并需要檢驗其長度是否滿足某種要求時,你想當然地會使用strlen()函數。此函數執行起來相當快,因為它不做任何計算,只返回在zval 結構(C的內置數據結構,用于存儲PHP變量)中存儲的已知字符串長度。但是,由于strlen()是函數,多多少少會有些慢,因為函數調用會經過諸多步驟,如字母小寫化(譯注:指函數名小寫化,PHP不區分函數名大小寫)、哈希查找,會跟隨被調用的函數一起執行。在某些情況下,你可以使用isset() 技巧加速執行你的代碼。
(舉例如下)
if (strlen($foo) < 5) { echo “Foo is too short”$$ }
(與下面的技巧做比較)
if (!isset($foo{5})) { echo “Foo is too short”$$ }
調用isset()恰巧比strlen()快,因為與后者不同的是,isset()作為一種語言結構,意味著它的執行不需要函數查找和字母小寫化。也就是說,實際上在檢驗字符串長度的頂層代碼中你沒有花太多開銷。
40.使用++$i遞增
When incrementing or decrementing the value of the variable $i++ happens to be a tad slower then ++$i. This is something PHP specific and does not apply to other languages, so don’t go modifying your C or Java code thinking it’ll suddenly become faster, it won’t. ++$i happens to be faster in PHP because instead of 4 opcodes used for $i++ you only need 3. Post incrementation actually causes in the creation of a temporary var that is then incremented. While preincrementation increases the original value directly. This is one of the optimization that opcode optimized like Zend’s PHP optimizer. It is a still a good idea to keep in mind since not all opcode optimizers perform this optimization and there are plenty of ISPs and servers running without an opcode optimizer.
當執行變量$i的遞增或遞減時,$i++會比++$i慢一些。這種差異是PHP特有的,并不適用于其他語言,所以請不要修改你的C或Java代碼并指望它們能立即變快,沒用的。++$i更快是因為它只需要3條指令(opcodes),$i++則需要4條指令。后置遞增實際上會產生一個臨時變量,這個臨時變量隨后被遞增。而前置遞增直接在原值上遞增。這是最優化處理的一種,正如Zend的PHP優化器所作的那樣。牢記這個優化處理不失為一個好主意,因為并不是所有的指令優化器都會做同樣的優化處理,并且存在大量沒有裝配指令優化器的互聯網服務
提供商(ISPs)和服務器。
40. 不要隨便就復制變量
有時候為了使 PHP 代碼更加整潔,一些 PHP 新手(包括我)會把預定義好的變量復制到一個名字更簡短的變量中,其實這樣做的結果是增加了一倍的內存消耗,只會使程序更加慢。試想一下,在下面的例子中,如果用戶惡意插入 512KB 字節的文字到文本輸入框中,這樣就會導致 1MB 的內存被消耗!
BAD:
$description = $_POST['description'];
echo $description;
GOOD:
echo $_POST['description'];
41 使用選擇分支語句
switch case好于使用多個if,else if語句,并且代碼更加容易閱讀和維護。
42.在可以用file_get_contents替代file、fopen、feof、fgets
在可以用file_get_contents替代file、fopen、feof、fgets等系列方法的情況下,盡量用 file_get_contents,因為他的效率高得多!但是要注意file_get_contents在打開一個URL文件時候的PHP版本問題;
43.盡量的少進行文件操作,雖然PHP的文件操作效率也不低的;
44.優化Select SQL語句,在可能的情況下盡量少的進行Insert、Update操作(在update上,我被惡批過);
45.盡可能的使用PHP內部函數
46.循環內部不要聲明變量,尤其是大變量:對象
(這好像不只是PHP里面要注意的問題吧?);
47.多維數組盡量不要循環嵌套賦值;
48.foreach效率更高,盡量用foreach代替while和for循環;
49.“用i+=1代替i=i+1。符合c/c++的習慣,效率還高”;
50.對global變量,應該用完就unset()掉;
51 并不是事必面向對象(OOP),面向對象往往開銷很大,每個方法和對象調用都會消耗很多內存。
52 不要把方法細分得過多,仔細想想你真正打算重用的是哪些代碼?
53 如果在代碼中存在大量耗時的函數,你可以考慮用C擴展的方式實現它們。
54、打開apache的mod_deflate模塊,可以提高網頁的瀏覽速度。
(提到過echo 大變量的問題)
55、數據庫連接當使用完畢時應關掉,不要用長連接。
56、split比exploade快