MS SQL BackUp 指令 參數說明

Posted: 2024 年 02 月 16 日 in SQL

選項 描述
BLOCKSIZE 實體區塊大小,單位為字節。
DESCRIPTION 指定備份集合的文字說明。對於還原時定位正確的備份集合十分有用。
DIFFERENTIAL 指定一個差異備份。這個選項只在使用完全數據庫備份有用。
EXPIREDATE = date |
RETAINDAYS = days EXPIREDATE 選項指定備份集合到期的日期(可以被覆寫)。RETAINDAYS 選項指定備份集合到期前的天數。
PASSWORD = password 指定備份的密碼。提供備份本身較大的安全性。
FORMAT | NOFORMAT FORMAT 選項指定媒體標題將被重寫,因此會使媒體中的原始數據無效。NOFORMAT 指定媒體標題將不被重寫。
INIT | NOINIT INIT 選項指定備份集合位於媒體的第一個檔案中並保存媒體標題,但覆寫媒體中的所有數據。也就是說,INIT覆寫在磁帶上的任何內容。NOINIT 選項指定備份附加到媒體中。如果您要重新使用磁帶,您將需要使用這個選項。
MEDIADESCRIPTION = text 設定媒體集合的說明。
MEDIANAME = media_name 指定媒體的名稱。
MEDIAPASSWORD = password 指定媒體集合的密碼
NAME = backup_set_name 設定備份集合名稱
NOSKIP | SKIP NOSKIP 選項指定在備份集合被覆寫前,檢查媒體中備份集合的到期日期。SKIP 選項不檢查到期日期。
NO_TRUNCATE 指定在備份後不刪減交易記錄文件。這個選項只在記錄文件備份中有用。
NOUNLOAD | UNLOAD NOUNLOAD 選項指定在完成備份後,媒體不被卸載(例如,不退出磁帶)。UNLOAD 選項指定在完成備份後,卸載媒體。
RESTART 指示 SQL Server 重新啟動被中斷的備份。
STATS [ = percentage ] 在完成指定備份的百分率後,顯示一個訊息。如果您想要檢視操作的過程,這個選項將會是有用的。
請確認您指定了備份附加到媒體中,或是應該覆寫媒體;您選擇的選項會影響到寫入磁帶中數據的數量。如果您正要備份數據到一個已經使用過的磁帶裝置上,卻沒有清除這個磁帶,也沒有指定要覆寫磁帶,您將發現磁帶的空間很快就用完了。在附加模式中,備份程序將只使用磁帶末端的可用空間。
________________________________________
真實世界 使用BACKUP
這裡有一些使用 BACKUP T-SQL 指令的例子。
下面的例子為 Example 數據庫備份數據文件:
BACKUP DATABASE Example
TO Backup_Dev_1, Backup_Dev_2
WITH
DESCRIPTION = “DB backup of example",
STATS = 5
GO
備份裝置是 Backup_Dev_1 和 Backup_Dev_2,並當每完成備份的 5% 就會顯示統計數字。注意,在先前的例子中提供備份的說明。
如果您在一個小的數據庫上測試這個例子,例如 Northwind,您看到的統計數字並不是 5% 的增量,您可能看到如 7%、16% 等的增量。這種差異的出現是因為備份程序一次讀取和寫入大於整個備份的 5%,這時就顯示那些較大的增量。對於較大的數據集合,寫入的增量將比 5% 小,所以將按照預設的顯示。
下面的陳述式將備份 Example 數據庫的交易記錄文件:
BACKUP LOG Example
TO Backup_Dev_3, Backup_Dev_4
WITH
DESCRIPTION = “DB backup of example",
STATS = 25
GO
備份裝置是 Backup_Dev_3 和 Backup_Dev_4,統計數字將顯示出 25% 的間隔時間。輸出結果顯示已完成操作和備份結果的百分率。您將會被通知備份了多少頁面、備份花了多長時間、以及備份的速度(MB/sec)。

________________________________________

–清除交易紀錄檔
backup log DB_NAME with truncate_only
go

–壓縮資料庫釋放空間
dbcc shrinkdatabase (DB_NAME, 10)
go

________________________________________

USE [master]
GO

-- 完整備份資料庫
BACKUP DATABASE [Source] TO DISK = 'E:\Backup\Source_Full.BAK' WITH INIT
GO

-- 檢查備份檔是否 OK
RESTORE VERIFYONLY FROM DISK = 'E:\Backup\Source_Full.BAK'
GO

-- 列出備份檔案內包含哪些資料庫檔案
RESTORE FILELISTONLY FROM DISK = 'E:\Backup\Source_Full.BAK'
GO

-- 列出備份檔的備份資訊
RESTORE HEADERONLY FROM DISK = 'E:\Backup\Source_Full.BAK'
GO

Posted: 2017 年 11 月 30 日 in Uncategorized

給OOP初學者的建議:

先搞懂「資料跟行為在一起」就好,其它的慢慢來

初學者接觸OOP,幾乎都會有以下疑惑:
我到底為什麼要學OOP?OOP解決了什麼問題?書上這些範例就算不用OOP也寫得出來吧?
然後覺得「繼承」、「多型」、「介面」、「抽象類別」等等的名詞很難,覺得OOP很難。
其實這些名詞雖然重要,但對新手來說,本來就很難在一開始就搞懂。
建議先搞懂「資料跟行為在一起」是什麼,以及它的好處在哪,就可以了,其它的慢慢來。
什麼叫做「資料跟行為在一起」?
假設我們在開發一個「中英文互助學習網」,鼓勵中文人士與英語人士登入討論。
這個系統的貼文、留言功能會顯示「發文日期」。
發文日期要根據使用者的註冊身份(台灣人、英語人士)顯示不同格式(台灣格式、西方格式)。
下面就以這個日期格式的功能舉例說明「資料跟行為在一起」是什麼意思。
作法一:直接硬寫(不OOP、資料跟行為混在一起)
初學者通常會用最簡單、也最直覺的作法,直接硬寫出來,像這樣:
<? php

# 假設資料庫取出來的發文日期長這樣
$postDate = '2016-06-02';

if (/* 判斷是否顯示台灣格式 */) {
# 轉換成這樣 2016.6.2
$arr = explode('-', $postDate);
$year = $arr[0];
$month = $arr[1];
$day = $arr[2];
echo "$year.$month.$day";
} else { // 西方格式
# 轉換成這樣 6/2/2016
$arr = explode('-', $postDate);
$year = $arr[0];
$month = $arr[1];
$day = $arr[2];
echo "$month/$day/$year";
}

這種寫法的資料(日期)跟行為(轉換成各種格式)混在一起。
它的優點是寫起來很簡單,缺點則有兩個:
* 日期格式的邏輯會重複出現在很多地方,整段code會到處重複出現
* 整段code大概會塞在

或是的裡面,導致它跟HTML混在一起,很亂
作法二:自訂函數(不OOP、資料跟行為沒混在一起)
為了解決作法一遇到的問題,聰明的初學者很快就想到可以用「自訂函數」!就像這樣:
<? php
function localFormat($date){
$arr = explode(‘-‘, $date);
$year = $arr[0];
$month = $arr[1];
$day = $arr[2];
return “$year.$month.$day";
}

function englishFormat($date)
{
$arr = explode(‘-‘, $date);
$year = $arr[0];
$month = $arr[1];
$day = $arr[2];
return “$month/$day/$year";
}

$postDate = ‘2016-06-02’; # 假設資料庫取出來的發文日期長這樣

if (/* 判斷是否為台灣人身份 */) {
echo localFormat($postDate);
} else { // 英語人士身份
echo englishFormat($postDate);
}

這種寫法將行為(轉換成各種格式)用自訂函數給獨立出來,也大幅改善了作法一遇到的問題。
對小型的網頁程式來說,這招非常好用,不但開發快速、簡單,還漂亮地將資料跟行為拆開。
但是程式規模變大之後,為了將各種行為拆出來,會寫出很多自訂函數,類似這樣:
<? php
function localFormat($param)
{
// blah blah …
}
function englishFormat($param)
{
// blah blah …
}
function someTask($param)
{
// blah blah …
}
function anotherTask($param)
{
// blah blah …
}
function otherTask($param)
{
// blah blah …
}
//…

於是又衍生出三個問題:
1. 像localFormat、englishFormat這樣的函數名稱意義模糊,看不出是處理日期、人名,還是什麼東西的格式
2. 這些自訂函數各有不同的行為,全部放在一起顯得很亂,應該要想辦法分類、整理這些函數
3. 像localFormat、englishFormat這樣的函數,只吃特定格式的參數,最好能跟某種資料的形式綁在一起,以後要改程式時,能讓相關的資料跟行為一起被看到
問題1很好解決,只要替函數名稱加前綴字變成dateLocalFormat、dateEnglishFormat就行了。
問題2也很好解決,只要多開幾個檔案,把相關的函數放進同一個檔案就行了。
問題3就很棘手,資料跟行為拆開之後,如何在概念上又找方法整理在一起?
作法三:使用class(OOP、資料跟行為在一起)
正是這些處理資料、整理行為的問題,導致了OOP的誕生:
<? php
class Date
{
public $year;
public $month;
public $day;
public function __construct($date)
{

$arr = explode(‘-‘, $date);
$this->year = $arr[0];
$this->month = $arr[1];
$this->day = $arr[2];

}

public function localFormat()
{
return $this->year . ‘.’ .$this->month . ‘.’ . $this->day;
}

public function englishFormat()
{
return $this->month . ‘/’ .$this->day . ‘/’ . $this->year;
}
}

$postDate = ‘2016-06-02’; # 假設資料庫取出來的發文日期長這樣

$date = new Date($postDate);

if (/* 判斷是否為台灣人身份 */) {
echo $date->localFormat();
} else { // 英語人士身份
echo $date->englishFormat();
}

OOP的寫法,一次解決了前述三個問題:
問題1 => 現在從類別名稱就可以知道底下方法的意義了
問題2 => 現在相關的函數都整理進同一個類別底下成為方法了
問題3 => 現在資料的形式都統一在constructor處理一次,之後不管新增多少方法都不用處理資料了
這就是所謂的「資料跟行為在一起」,也正是OOP的核心概念。
利用這種方式整理程式碼、寫出一個又一個的類別,可以大幅提昇程式碼的品質。
結論
上述的作法一跟作法二並沒那麼糟糕,但確實會帶來一些問題。
對於小型的網頁程式來說,可能還算夠用。
但是隨著程式規模變大,如果將概念上相關的資料跟行為整理在一起,會很有幫助。
實務上也可以先從作法二開始寫起,直到發現某些資料跟行為關係密切,再拉出來整理成類別即可。
至於很多OOP教學會提到的「繼承」、「多型」、「介面」、「抽象類別」等等名詞,一時搞不懂沒有關係,你可能實務上也暫時用不到。之後找時間慢慢搞懂它們的用途就好。
光是知道「將資料跟行為放在一起」的技巧,就能夠開始寫OOP程式碼了。

正則表達式 範例

Posted: 2017 年 09 月 13 日 in Uncategorized

幾種基本的數字正則表達式

只能輸入1個數字
表達式 ^/d$
描述 匹配一個數字
匹配的例子 0,1,2,3
不匹配的例子
只能輸入n個數字 
表達式 ^/d{n}$ 例如^/d{8}$
描述 匹配8個數字
匹配的例子 12345678,22223334,12344321
不匹配的例子
只能輸入至少n個數字 
表達式 ^/d{n,}$ 例如^/d{8,}$
描述 匹配最少n個數字
匹配的例子 12345678,123456789,12344321
不匹配的例子
只能輸入m到n個數字 
表達式 ^/d{m,n}$ 例如^/d{7,8}$
描述 匹配m到n個數字
匹配的例子 12345678,1234567
不匹配的例子 123456,123456789
只能輸入數字 
表達式 ^[0-9]*$
描述 匹配任意個數字
匹配的例子 12345678,1234567
不匹配的例子 E,
只能輸入某個區間數字 
表達式 ^[12-15]$
描述 匹配某個區間的數字
匹配的例子 12,13,14,15
不匹配的例子
只能輸入0和非0打頭的數字 
表達式 ^(0|[1-9][0-9]*)$
描述 可以為0,第一個數字不能為0,數字中可以有0
匹配的例子 12,10,101,100
不匹配的例子 01,
只能輸入實數 
表達式 ^[-+]?/d+(/./d+)?$
描述 匹配實數
匹配的例子 18,+3.14,-9.90
不匹配的例子 .6,33s,67-99
只能輸入n位小數的正實數 
表達式 ^[0-9]+(.[0-9]{n})?$以^[0-9]+(.[0-9]{2})?$為例
描述 匹配n位小數的正實數
匹配的例子 2.22
不匹配的例子 2.222,-2.22,
只能輸入mn位小數的正實數 
表達式 ^[0-9]+(.[0-9]{m,n})?$以^[0-9]+(.[0-9]{1,2})?$為例
描述 匹配m到n位小數的正實數
匹配的例子 2.22,2.2
不匹配的例子 2.222,-2.2222,
只能輸入非0的正整數 
表達式 ^/+?[1-9][0-9]*$
描述 匹配非0的正整數
匹配的例子 2,23,234
不匹配的例子 0,-4,
只能輸入非0的負整數 
表達式 ^/-[1-9][0-9]*$
描述 匹配非0的負整數
匹配的例子 -2,-23,-234
不匹配的例子 0,4,
只能輸入n個字符 
表達式 ^.{n}$ 以^.{4}$為例
描述 匹配n個字符,注意漢字只算1個字符
匹配的例子 1234,12we,123清,清清月兒
不匹配的例子 0,123,123www,
只能輸入英文字符 
表達式 ^.[A-Za-z]+$為例
描述 匹配英文字符,大小寫任意
匹配的例子 Asp,WWW,
不匹配的例子 0,123,123www,
只能輸入大寫英文字符 
表達式 ^.[AZ]+$為例
描述 匹配英文大寫字符
匹配的例子 NET,WWW,
不匹配的例子 0,123,123www,
只能輸入小寫英文字符 
表達式 ^.[az]+$為例
描述 匹配英文大寫字符
匹配的例子 asp,csdn
不匹配的例子 0,NET,WWW,
只能輸入英文字符+數字 
表達式 ^.[A-Za-z0-9]+$為例
描述 匹配英文字符+數字
匹配的例子 1Asp,W1W1W,
不匹配的例子 0,123,123,www,
只能輸入英文字符/數字/下劃線 
表達式 ^/w+$為例
描述 匹配英文字符或數字或下劃線
匹配的例子 1Asp,WWW,12,1_w
不匹配的例子 3#,2-4,w#$,
密碼舉例 
表達式 ^.[a-zA-Z] /w{m,n}$
描述 匹配英文字符開頭的mn位字符且只能數字字母或下劃線
匹配的例子
不匹配的例子
驗證首字母大寫 
表達式 /b[^/Wa-z0-9_][^/WA-Z0-9_]*/b
描述 首字母只能大寫
匹配的例子 Asp,Net
不匹配的例子
驗證網址(帶?id=中文)VS.NET2005無此功能 
表達式 ^http:////([/w-]+(/.[/w-]+)+(//[/w- .///?%&=/u4e00-/u9fa5]*)?) ?$
描述 驗證帶?id=中文
匹配的例子 ,
http://blog.csdn.net?id=清清月兒
不匹配的例子
驗證漢字 
表達式 ^[/u4e00-/u9fa5]{0,}$
描述 只能漢字
匹配的例子 清清月兒
不匹配的例子
驗證QQ號 
表達式 [0-9]{5,9}
描述 5-9位的QQ號
匹配的例子 10000,123456
不匹配的例子 10000w,
驗證電子郵件(驗證MSN號一樣)
表達式 /w+([-+.´]/w+)*@/w+([-.]/w+)*/./w+([-.]/w+)*
描述 注意MSN用非hotmail.com郵箱也可以
匹配的例子 aaa@msn.com
不匹配的例子 111@1.
驗證身份證號(粗驗,最好服務器端調類庫再細驗證) 
表達式 ^[1-9]([0-9]{16}|[0-9]{13})[xX0-9]$
描述
匹配的例子 15或者18位的身份證號,支持帶X的
不匹配的例子
驗證手機號(包含159,不包含小靈通) 
表達式 ^13[0-9]{1}[0-9]{8}|^15[9]{1}[0-9]{8}
描述 包含159的手機號130-139
匹配的例子 139XXXXXXXX
不匹配的例子 140XXXXXXXX,
驗證電話號碼號(很複雜,VS.NET2005給的是錯的)
表達式(不完美) 方案一((/(/d{3}/)|/d{3}-)|(/(/d{4}/)|/d{4}-))?(/d{8}|/ d{7})
方案二(^[0-9]{3,4}/-[0-9]{3,8}$)|(^[0-9]{3,8}$)|( ^/([0-9]{3,4}/)[0-9]{3,8}$)|(^0{0,1}13[0-9]{9}$) 支持手機號但也不完美
描述 上海:02112345678 3+8位
上海:021-12345678
上海:(021)-12345678
上海:(021)12345678
鄭州:03711234567 4+7位
杭州:057112345678 4+8位
還有帶上分機號,國家碼的情況由於情況非常複雜所以不建議前台做100%驗證,到目前為止似乎也沒有誰能寫一個包含所有的類型 如果誰有更好 的驗證電話的請留言,其實有很多情況本身就是矛盾的。
匹配的例子
不匹配的例子
驗證護照 
表達式 (P/d{7})|G/d{8})
描述 驗證P+7個數字和G+8個數字
匹配的例子
不匹配的例子
驗證IP 
表達式 ^(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9 ]{1}|[1-9])/.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}| [1-9]{1}[0-9]{1}|[1-9]|0)/.(25[0-5]|2[0-4][0-9]|[0- 1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)/.(25[0-5]|2 [0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[0-9] )$
描述 驗證IP
匹配的例子 192.168.0.1 222.234.1.4
不匹配的例子
驗證域
表達式 ^[a-zA-Z0-9]+([a-zA-Z0-9/-/.]+)?/.(com|org|net|cn|com.cn|edu.cn|grv.cn |)$
描述 驗證域
匹配的例子 csdn.net baidu.com it.com.cn
不匹配的例子 192.168.0.1
驗證信用卡
表達式 ^((?:4/d{3})|(?:5[1-5]/d{2})|(?:6011)|(?:3[68]/d{2})|( ?:30[012345]/d))[ -]?(/d{4})[ -]?(/d{4})[ -]?(/d{4}|3[4,7]/ d{13})$
描述 驗證VISA卡,萬事達卡,Discover卡,美國運通卡
匹配的例子
不匹配的例子
驗證ISBN 國際標準書號
表達式 ^(/d[- ]*){9}[/dxX]$
描述 驗證ISBN國際標準書號
匹配的例子 7-111-19947-2
不匹配的例子
驗證GUID 全球唯一標識符
表達式 ^[A-Z0-9]{8}-[A-Z0-9]{4}-[A-Z0-9]{4}-[A-Z0-9]{4}-[A-Z0- 9]{12}$
描述 格式8-4-4-4-12
匹配的例子 2064d355-c0b9-41d8-9ef7-9d8b26524751
不匹配的例子
驗證文件路徑和擴展名
表達式 ^([a-zA-Z]/:|//)//([^//]+//)*[^//:*?"<>|]+/.txt(l)?$
描述 檢查路徑和文件擴展名
匹配的例子 E:/mo.txt
不匹配的例子 E:/ , mo.doc, E:/mo.doc ,
驗證Html顏色值
表達式 ^#?([af]|[AF]|[0-9]){3}(([af]|[AF]|[0-9]){3})?$
描述 檢查顏色取值
匹配的例子 #FF0000
不匹配的例子

 

php _server

Posted: 2017 年 09 月 13 日 in Uncategorized

網路上抓下來的

$_SERVER[‘PHP_SELF’] #當前正在執行腳本的文件名,與 document root相關。
$_SERVER[‘argv’] #傳遞給該腳本的參數。
$_SERVER[‘argc’] #包含傳遞給程序的命令行參數的個數(如果運行在命令行模式)。
$_SERVER[‘GATEWAY_INTERFACE’] #服務器使用的 CGI 規範的版本。例如,「CGI/1.1」。
$_SERVER[‘SERVER_NAME’] #當前運行腳本所在服務器主機的名稱。
$_SERVER[‘SERVER_SOFTWARE’] #服務器標識的字串,在響應請求時的頭部中給出。
$_SERVER[‘SERVER_PROTOCOL’] #請求頁面時通信協議的名稱和版本。例如,「HTTP/1.0」。
$_SERVER[‘REQUEST_METHOD’] #訪問頁面時的請求方法。例如:「GET」、「HEAD」,「POST」,「PUT」。
$_SERVER[‘QUERY_STRING’] #查詢(query)的字符串。
$_SERVER[‘DOCUMENT_ROOT’] #當前運行腳本所在的文檔根目錄。在服務器配置文件中定義。
$_SERVER[‘HTTP_ACCEPT’] #當前請求的 Accept: 頭部的內容。
$_SERVER[‘HTTP_ACCEPT_CHARSET’] #當前請求的 Accept-Charset: 頭部的內容。例如:「iso-8859-1,*,utf-8」。
$_SERVER[‘HTTP_ACCEPT_ENCODING’] #當前請求的 Accept-Encoding: 頭部的內容。例如:「gzip」。
$_SERVER[‘HTTP_ACCEPT_LANGUAGE’]#當前請求的 Accept-Language: 頭部的內容。例如:「en」。
$_SERVER[‘HTTP_CONNECTION’] #當前請求的 Connection: 頭部的內容。例如:「Keep-Alive」。
$_SERVER[‘HTTP_HOST’] #當前請求的 Host: 頭部的內容。
$_SERVER[‘HTTP_REFERER’] #鏈接到當前頁面的前一頁面的 URL 地址。
$_SERVER[‘HTTP_USER_AGENT’] #當前請求的 User_Agent: 頭部的內容。
$_SERVER[‘REMOTE_ADDR’] #正在瀏覽當前頁面用戶的 IP 地址。
$_SERVER[‘REMOTE_HOST’] #正在瀏覽當前頁面用戶的主機名。
$_SERVER[‘REMOTE_PORT’] #用戶連接到服務器時所使用的端口。
$_SERVER[‘SCRIPT_FILENAME’] #當前執行腳本的絕對路徑名。
$_SERVER[‘SERVER_ADMIN’] #管理員信息
$_SERVER[‘SERVER_PORT’] #服務器所使用的端口
$_SERVER[‘SERVER_SIGNATURE’] #包含服務器版本和虛擬主機名的字符串。
$_SERVER[‘PATH_TRANSLATED’] #當前腳本所在文件系統(不是文檔根目錄)的基本路徑。
$_SERVER[‘SCRIPT_NAME’] #包含當前腳本的路徑。這在頁面需要指向自己時非常有用。
$_SERVER[‘REQUEST_URI’] #訪問此頁面所需的 URI。例如,「/index.html」。
$_SERVER[‘PHP_AUTH_USER’] #當 PHP 運行在 Apache 模塊方式下,並且正在使用 HTTP 認證功能,這個變量便是用戶輸入的用戶名。
$_SERVER[‘PHP_AUTH_PW’] #當 PHP 運行在 Apache 模塊方式下,並且正在使用 HTTP 認證功能,這個變量便是用戶輸入的密碼。
$_SERVER[‘AUTH_TYPE’] #當 PHP 運行在 Apache 模塊方式下,並且正在使用 HTTP 認證功能,這個變量便是認證的類型。

HTTP 狀態碼清單

Posted: 2017 年 09 月 05 日 in Tech, Web

HTTP 狀態碼大致分成 5 類 (粗體表示),完整的狀態碼概述如下:

  • 1xx – 參考資訊 (Informational)
    這些狀態碼代表主機先暫時回應用戶端一個狀態,所以在接收一般的回應之前,用戶端應準備接收一個或多個 1xx 的回應。我以前在寫 ASP 的時候比較有看到 IIS 使用到這些狀態碼回應,在 Apache 的環境我還未曾遇到過。

    • 100 – 繼續。
    • 101 – 切換通訊協定。
  • 2xx – 成功 (OK)
    這類的狀態碼表示伺服器成功接收到用戶端要求、理解用戶端要求、以及接受用戶端要求。

    • 200 – 確定。 用戶端要求成功。
    • 201 – 已建立。
    • 202 – 已接受。
    • 203 – 非授權資訊。
    • 204 – 無內容。
    • 205 – 重設內容。
    • 206 – 部分內容。
    • 207 – 多重狀態 (WebDAV) — 這好像只有在 IIS 中才有,HTTP/1.1 並沒有定義這個狀態。這狀態會出現在可以包含多個不同回應代碼 (視子要求數量而定) 的 XML 訊息之前。
  • 3xx – 重新導向 (Redirection)
    用戶端瀏覽器必須採取更多動作才能完成要求。例如:瀏覽器可能必須重新發出 HTTP Request 要求伺服器上的不同頁面。

    • 301 – 要求的網頁已經永久改變網址。此狀態要求用戶端未來在連結此網址時應該導向至指定的 URI。
    • 302 – 物件已移動,並告知移動過去的網址。針對表單架構驗證,這通常表示為「物件已移動」。 要求的資源暫時存於不同的 URI 底下。 由於重新導向可能偶而改變,用戶端應繼續使用要求 URI 來執行未來的要求。 除非以 Cache-Control 或 Expires 標頭欄位表示,此回應才能夠快取。
      ASP.NET 預設的 Response.Redirect 方法,就是以 302 Found 做回應。
    • 303 – 通知 Client 連到另一個網址去查看上傳表單的結果(POST 變成 GET),當使用程式作網頁轉向時,會回應此訊息。
      在 ASP.NET 中要輸出 HTTP 303 轉向的程式碼如下:

      Response.StatusCode = 303;
      Response.RedirectLocation = "/PageB.aspx";
    • 304 – 未修改。用戶端要求該網頁時,其內容並沒有變更,應該回傳 304 告知網頁未修改。此時用戶端僅需要取得本地快取(Local Cache)的副本即可。
    • 305 – 要求的網頁必須透過 Server 指定的 proxy 才能觀看 ( 透過 Location 標頭 )
    • 306 – (未使用) 此代碼僅用來為了向前相容而已。
    • 307 – 暫時重新導向。要求的網頁只是「暫時」改變網址而已。
  • 4xx – 用戶端錯誤 (Client Error)
    這代表錯誤發生,且這錯誤的發生的原因跟「用戶端」有關。例如:用戶端可能連結到不存在的頁面、用戶端的權限不足、或可能未提供有效的驗證資訊(輸入的帳號、密碼錯誤)。下次看到 4xx 的回應千萬不要傻傻的一直查程式哪裡寫錯誤了(不過也有可能是程式造成的)。

    • 400 – 錯誤的要求。
    • 401 – 拒絕存取。 IIS 定義數個不同的 401 錯誤,以表示更詳細的錯誤原因。 這些特定的錯誤碼會顯示在瀏覽器中,但不會顯示在 IIS 記錄檔中:
      • 401.1 – 登入失敗。
      • 401.2 – 因為伺服器設定導致登入失敗。
      • 401.3 – 因為資源上的 ACL 而沒有授權。
      • 401.4 – 篩選授權失敗。
      • 401.5 – ISAPI/CGI 應用程式授權失敗。
      • 401.7 – Web 伺服器上的 URL 授權原則拒絕存取。 這是 IIS 6.0 專用的錯誤碼。
    • 403 – 禁止使用。 IIS 定義數個不同的 403 錯誤,以表示更詳細的錯誤原因:
      • 403.1 – 禁止執行存取。
      • 403.2 – 禁止讀取存取。
      • 403.3 – 禁止寫入存取。
      • 403.4 – 需要 SSL。
      • 403.5 – 需要 SSL 128。
      • 403.6 – IP 位址遭拒。
      • 403.7 – 需要用戶端憑證。
      • 403.8 – 網站存取遭拒。
      • 403.9 – 使用者過多。
      • 403.10 – 設定無效。
      • 403.11 – 密碼變更。
      • 403.12 – 對應程式拒絕存取。
      • 403.13 – 用戶端憑證已撤銷。
      • 403.14 – 目錄清單遭拒。
      • 403.15 – 超過用戶端存取授權數量。
      • 403.16 – 用戶端憑證不受信任或無效。
      • 403.17 – 用戶端憑證已經過期或尚未生效。
      • 403.18 – 無法在目前的應用程式集區中執行要求的 URL。 這是 IIS 6.0 專用的代碼。
      • 403.19 – 無法在這個應用程式集區中執行用戶端的 CGI。 這是 IIS 6.0 專用的代碼。
      • 403.20 – Passport 登入失敗。 這是 IIS 6.0 專用的錯誤碼。
    • 404 – 找不到。
      • 404.0 – (無) – 找不到檔案或目錄。
      • 404.1 – 無法在要求的連接埠上存取網站。
      • 404.2 – 網頁服務延伸鎖定原則阻止這個要求。
      • 404.3 – MIME 對應原則阻止這個要求。
    • 405 – 用來存取這個頁面的 HTTP 動詞不受允許 (方法不受允許)。
    • 406 – 用戶端瀏覽器不接受要求頁面的 MIME 類型。
    • 407 – 需要 Proxy 驗證。
    • 412 – 指定條件失敗。
    • 413 – 要求的實體太大。
    • 414 – 要求 URI 太長。
    • 415 – 不支援的媒體類型。
    • 416 – 無法滿足要求的範圍。
    • 417 – 執行失敗。
    • 423 – 鎖定錯誤。
  • 5xx – 伺服器錯誤 (Server Error)
    這代表錯誤發生,且這錯誤發生的原因跟「伺服器」有關。伺服器因為發生錯誤或例外狀況(Exception)而無法完成要求(Request)時,就會回應 5xx 的錯誤,且這肯定跟伺服器有關。

    • 500 – 內部伺服器錯誤。
      • 500.12 – 應用程式正忙於在 Web 伺服器上重新啟動。
      • 500.13 – Web 伺服器過於忙碌。
      • 500.15 – 不允許直接要求 Global.asa。
      • 500.16 – UNC 授權認證不正確。 這是 IIS 6.0 專用的錯誤碼。
      • 500.18 – 無法開啟 URL 授權存放區。 這是 IIS 6.0 專用的錯誤碼。
      • 500.19 – 此檔案的資料在 Metabase 中設定不當。
      • 500.100 – 內部的 ASP 錯誤。
    • 501 – 標頭值指定未實作的設定。
    • 502 – Web 伺服器在作為閘道或 Proxy 時收到無效的回應。
      • 502.1 – CGI 應用程式逾時。
      • 502.2 – CGI 應用程式中發生錯誤。
    • 503 – 服務無法使用。 這是 IIS 6.0 專用的錯誤碼。
    • 504 – 閘道逾時。
    • 505 – 不支援的 HTTP 版本。

mssql 獨佔鎖定

Posted: 2014 年 05 月 13 日 in SQL

MSSQL 新建資料庫時,出現"無法取得資料庫 ‘model’ 獨佔鎖定, 某些列出的檔案名稱無法建立" 的問題時 ,

解決方案如下

MSSQL Management Studio 裡,新增查詢

———– keyin ————————————

select spid from master.dbo.sysprocesses
where dbid=db_id(‘model’)

——————————————————

查詢出  (例)可能是 62

然後 keyin

kill 62

 

之後就正常了

Form 小技巧

Posted: 2014 年 04 月 24 日 in php

1.陣列接收

<form

……

<input type="checkbox" name="address[ ]" value="桃園" /> 桃園
<input type="checkbox" name="address[ ]" value="台中" />台中 
<input type="checkbox" name="address[ ]" value="高雄" />高雄 
<input type="checkbox" name="address[ ] " value="台南" />台南

…….

 

接收的話,也是 $_POST[‘address’]
只不過 $_POST[‘address’] 是一個陣列
所以可以用
foreach($_POST[‘address’] as $val){
echo $val;
}
就可以找出所有值。

or

假如選了「台中」、「高雄」
$address=implode(“,",$_POST[‘address’]);
$address的值就是「台中,高雄」

 

2.serialize() 很好用  可以多用

$.ajax({
url: “test1.php",
data: $(‘#applyForm’).serialize(),
type:"POST",
dataType:’json’,

success: function(msg){
alert(“return="+msg);
},

error:function(xhr, ajaxOptions, thrownError){
alert(xhr.status);
alert(thrownError);
}
});

PHP 檔案管理

Posted: 2014 年 03 月 12 日 in php

檔案處理

  PHP也可進行一般檔案的處理,例如文字檔的開啟、讀取、寫人、關閉等等,甚至還可以進行檔案的複製、搬移、刪除,以及目錄的處理功能,唯在處理這些檔案之前,如果要透過Web的方式來處理,得先注意檔案在系統中的權限問題,像是Linux系統,一般檔案的權限可分為擁有者、群組、其他等三種不同的使用者權限,同時又區分「讀、寫、執行」三種屬性權限,所以,在使用時得先留意在那個系統(Linux或Windows)執行,以及上述權限問題等,才能順利操作PHP管理檔案。 以下就以一個文字檔為例,進行所謂的:

  • 開啟檔案 ─ fopen( )函數
  • 顯示檔案 ─ fpassthru ( )函數
  • 檔案內容讀取 ─ fread( ) 、fgets( )函數
  • 寫入檔案 ─ fwrite( ) 、fputs( ) 函數
  • 關閉檔案 ─ fclose ( ) 函數
  • 複製檔案 ─ copy ( ) 函數
  • 刪除檔案 ─ unlink( ) 函數

在操作這些檔案處理函數時,php.ini中的設定會影響這些函式的動作:

參數名稱
預設值
說明
參數可變更性
allow_url_fopen
1
是否允許利用網頁方式開啟檔案
php.ini
user_agent
設定PHP傳送時使用者代理
php.ini
default_socket_timeout
60秒
在使用連線功能時的逾時時間設定(即自動斷線時間)
php.ini
auto_detect_line_endings
Off
自動檢查「行」的結束(換行)
php.ini

 

fopen 開啟檔案
語法
fopen ( string filename, string mode [, int use_include_path [, resource zcontext]])

fopen ( string 檔案名稱, string 開啟模式 [, int use_include_path [, resource zcontext]])

說明
  1. filename可以是檔案名稱或絕對路徑的檔案
  2. 開啟模式如下表說明:

    開啟
    模式

    說明
    'r'
    開啟成唯讀檔
    'r+'
    開啟成可讀寫的檔案
    'w'
    開啟只有寫入的檔案,並將檔案長度設為零;如果檔案不存在,則建立。
    'w+'
    開啟可讀寫,如果檔案存在,則會清除所有內容,長度為零; 如果檔案不存在,則建立。
    'a'
    開啟只有寫入的檔案,資料由檔案尾部加入;如果檔案不存在,則建立。
    'a+'
    開啟可讀寫的檔案,資料由檔案尾部加入;如果檔案不存在,則建立。
    'x'
    建立並開啟只有寫入的檔案,資料由檔案開頭寫入;如果檔案存在,fopen( )函數將回應「false」,並發生錯誤;如果檔案不存在,則建立。這個參數自PHP 4.3.2 以後版本開始支援。.
    'x+'
    建立並開啟可讀寫的檔案,資料由檔案開頭寫入;如果檔案存在,fopen( )函數將回應「false」,並發生錯誤;如果檔案不存在,則建立。這個參數自PHP 4.3.2 以後版本開始支援。.
  3. include_path 是指定檔案可搜尋的路徑位置。
  4. 如果操作成功的話,會回傳一個「handle」值,失敗則傳回「 false 」

 

傳回值
resource
範例
01:
02:
03:
04:
05:
<?php
  if ( !($fp = fopen("file_ex.txt", "r")) ) {
    echo "無法開啟檔案";
  } 
?>
第02行:開啟檔案,「!」表示相反的意思;如果成功,則結果會回傳給$fp。

 

 
fpassthru 顯示檔案
語法
fpassthru ( resource handle)
說明
當fopen( )函數開啟檔案成功的話,使用fpassthru( )函數,會檔案內容全部輸出到網頁上。
傳回值
int
範例
01:
02:
03:
04:
05:
06:
07:
<?php
  if ( !($fp = fopen("file_ex.txt", "r")) ) {
    echo "無法開啟檔案";
  } else {
    fpassthru ($fp) ;
  }  
?>

ch8-1-2.php

執行程式

第02行:開啟檔案,「!」表示相反的意思;如果成功,則結果會回傳給$fp。

 

fread 讀取檔案
語法
fread ( resource handle, int length)
說明
  1. 由開啟的檔案中讀取一定長度的字串。
  2. 可配合 while 將整個檔案讀取出來。
傳回值
string
範例
01:
02:
03:
04:
05:
06:
07:
<?php
  if ( !($fp = fopen("file_ex.txt", "r")) ) {
    echo "無法開啟檔案";
  } else {
    while ( $buffer = fread($fp, 40) ) {
       echo "$buffer <BR>";
    }
  }  
?>

ch8-1-3.php

執行程式

第05行:每次讀取40個字元,一直到讀取完畢為止。
fwrite 寫入檔案
語法
fwrite ( resource handle, string string [, int length])
說明
將指定的字串寫入檔案中,如果有長度設定,則表示要寫入字串的字元數。
傳回值
int
範例
01:
02:
03:
04:
05:
06:
07:
08:

09:
<?php
  $add_str = "台中市教育資訊網路心";
  if ( !($fp = fopen("file_ex.txt", "a")) ) {
    echo "無法開啟檔案";
  } else {
      fwrite ($fp, $add_str); 
      fpassthru ($fp);
  }  
?>

ch8-1-4.php

執行程式

第03行:開啟檔案為可讀寫模式
第06行:寫入預設字串
第07行:顯示結果
fclose 關閉檔案
語法
fclose ( resource handle)
說明
關閉開啟的檔案;
傳回值
bool
copy 複製檔案
語法
copy ( string source, string dest)
說明
複製檔案,成功回傳TRUE失敗回傳FALSE;須注意檔案或目錄的權限
傳回值
bool
範例
01:
02:
03:
04:
05:
<?php
  if ( !copy("file_ex.txt", "file_ex.bak")) ) {
    echo "無法複製檔案";
  }  
?>
unlink 刪除檔案
語法
unlink ( string filename)
說明
刪除檔案,成功回傳TRUE失敗回傳FALSE;須注意檔案或目錄的權限
傳回值
bool
範例
01:
02:
03:
04:
05:
<?php
  if ( !unlink("file_ex.txt")) ) {
    echo "無法複製檔案";
  }  
?>
PHP處理檔案函數 (目前共有75個)
函數名稱
功能簡介
basename Returns filename component of path
chgrp Changes file group
chmod Changes file mode
chown Changes file owner
clearstatcache Clears file status cache
copy Copies file
delete See unlink() or unset()
dirname Returns directory name component of path
disk_free_space Returns available space in directory
disk_total_space Returns the total size of a directory
diskfreespace Alias of disk_free_space()
fclose Closes an open file pointer
feof Tests for end-of-file on a file pointer
fflush Flushes the output to a file
fgetc Gets character from file pointer
fgetcsv Gets line from file pointer and parse for CSV fields
fgets Gets line from file pointer
fgetss Gets line from file pointer and strip HTML tags
file_exists Checks whether a file or directory exists
file_get_contents Reads entire file into a string
file_put_contents Write a string to a file
file Reads entire file into an array
fileatime Gets last access time of file
filectime Gets inode change time of file
filegroup Gets file group
fileinode Gets file inode
filemtime Gets file modification time
fileowner Gets file owner
fileperms Gets file permissions
filesize Gets file size
filetype Gets file type
flock Portable advisory file locking
fnmatch Match filename against a pattern
fopen Opens file or URL
fpassthru Output all remaining data on a file pointer
fputs Alias of fwrite()
fread Binary safe file read
fscanf Parses input from a file according to a format
fseek Seeks on a file pointer
fstat Gets information about a file using an open file pointer
ftell Tells file pointer read/write position
ftruncate Truncates a file to a given length
fwrite Binary safe file write
glob Find pathnames matching a pattern
is_dir Tells whether the filename is a directory
is_executable Tells whether the filename is executable
is_file Tells whether the filename is a regular file
is_link Tells whether the filename is a symbolic link
is_readable Tells whether the filename is readable
is_uploaded_file Tells whether the file was uploaded via HTTP POST
is_writable Tells whether the filename is writable
is_writeable Alias of is_writable()
link Create a hard link
linkinfo Gets information about a link
lstat Gives information about a file or symbolic link
mkdir Makes directory
move_uploaded_file Moves an uploaded file to a new location
parse_ini_file Parse a configuration file
pathinfo Returns information about a file path
pclose Closes process file pointer
popen Opens process file pointer
readfile Outputs a file
readlink Returns the target of a symbolic link
realpath Returns canonicalized absolute pathname
rename Renames a file
rewind Rewind the position of a file pointer
rmdir Removes directory
set_file_buffer Alias of stream_set_write_buffer()
stat Gives information about a file
symlink Creates a symbolic link
tempnam Create file with unique file name
tmpfile Creates a temporary file
touch Sets access and modification time of file
umask Changes the current umask
unlink Deletes a file

php Apache MSSQL 設定

Posted: 2013 年 04 月 24 日 in php

1. 下載 AppServ (Apache 2.0 Handler, 內含PHP Version 5.2.6、MySQL 5.0.51a、Apache 2.2.8  ), 安裝並執行

2. 雖然 php 有內建 mssql 的支援函式, 但這個功能並沒有預設開啟, 因此必須修改 C:\Windows\php.ini 將" ;extension=php_mssql.dll" 前面的 (  ;  ) 去掉

3. 將 AppServ 下的兩個 dll 檔拷貝到 windows\system32 下: [ AppServ\php5\ntwdblib.dll、AppServ\php5\ext\php_mssql.dll ]

4. 由於 php 所附的 dll 可能是舊版的, 只能支援到 MS SQL 2000 所以必須重新下載 ntwdblib.dll( http://webzila.com/dll/1/ntwdblib.zip ),解壓縮之後並貼到 windows\system32 中覆蓋舊有的檔案

5. 重新啟動 appserv 中的 appache

6. 如果是 MS SQL 2005 以上的版本, 預設的 TCP/IP 和 Named 連線功能是關 閉的, 必須到 MS SQL 上將這兩個功能打開

a. 打開 SQL Server Enterprise Manager 編輯該 SQL Server 的參數 (或是到控制台下的 Administrative Tools 打開 SQL 的管理程式也可以)

b. 點選 “網路設定", 將 “具名管道" 與 TCP/IP 加入後確定即可

7. 測試連線

8.php預設的session不能直接使用,必須至php.ini中,將「output_buffering = Off」,改為「output_buffering = 4096」,不設的話,在php檔為UTF-8編碼下可能會出現以下的訊息 「 cannot send session cache limiter-headers already sent (output start at …………) 」

<html>
<head>
<title>MS SQL Connection Test</title>
</head>
<body>
<?php
    $dhcp_dbh = mssql_connect("<your ip>", "<mssql_user>", "<sql_password>") 
                or die("Can't Connect to SQL Server");
    print "connection = ".$dhcp_dbh;
?>
</body>
</html>

====== PART 2 ===============

PHP + MSSQL – Apache 設定

   Apache 及 php.ini
1. 更改 php.ini
mssql.secure_connection = On

extension=php_mssql.dll (移除 ; )2. SQL Server – 伺服器驗證 : SQL Server 及 Windows 驗證模式3. 將 \php5\ext\php_mssql.dll copy 至下列 folder.
C:\Windows\System32\4. 找尋 ntwdblib.dll (版本 2000.80.194.0 或以上), copy 至下列 folder.
C:\Windows\System32\
\php5\
\Apache\bin\5. Restart Apache 服務註 : 設定錯誤出現之 error message.
Warning: mssql_connect() [function.mssql-connect]: Unable to connect to serve
 php 程式碼
<table border="1″ cellpadding="0″ cellspacing="0″><?php
$server = ‘(Host Name),(Port No.)’;$con=mssql_connect($server,'(SQL Server User Account Login Name)’,'(SQL Server User Account Password)’);$msdb=mssql_select_db(‘Soccer’,$con);$query = mssql_query(‘SELECT * FROM dbo.Team’);if (!mssql_num_rows($query)) {
echo ‘No records found’;
}else{
while ($row = mssql_fetch_array($query, MSSQL_NUM)) {
echo “<tr>" ;
echo “<td>" ;
echo $row[0] . “</td><td>" ;
echo $row[1] . “</td><td>" ;
echo $row[2] . “</td></tr>" ;
}
}mssql_free_result($query);?></table>

MSSQL 效能篇

Posted: 2012 年 08 月 28 日 in SQL

1、資料庫設計與規劃

• Primary Key 欄位的長度儘量小,能用 small integer 就不要用 integer。例如員工資料表,若能用員工編號當主鍵,就不要用身分證字號。

• 一般欄位亦同。若該資料表要存放的資料不會超過 3 萬筆,用 small integer 即可,不必用 integer。

• 文字資料欄位若長度固定,如:身分證字號,就不要用 varchar 或 nvarchar,應該用 char 或 nchar。

• 文字資料欄位若長度不固定,如:地址,則應該用 varchar 或 nvarchar。除了可節省儲存空間外,存取磁碟時也會較有效率。

• 設計欄位時,若其值可有可無,最好也給一個預設值,並設成「不允許 NULL」(一般欄位預設為「允許 NULL」)。因為 SQL Server 在存放和查詢有 NULL 的資料表時,會花費額外的運算動作 [2]。

• 若一個資料表的欄位過多,應垂直切割成兩個以上的資料表,並用同名的 Primary Key 一對多連結起來,如:Northwind 的 Orders、Order Details 資料表。以避免在存取資料時,以叢集索引掃描時會載入過多的資料,或修改資料時造成互相鎖定或鎖定過久。

——————————

2、適當地建立索引

• 記得自行幫 Foreign Key 欄位建立索引,即使是很少被 JOIN 的資料表亦然。

• 替常被查詢或排序的欄位建立索引,如:常被當作 WHERE 子句條件的欄位。

• 用來建立索引的欄位,長度不宜過長,不要用超過 20 個位元組的欄位,如:地址。

• 不要替內容重複性高的欄位建立索引,如:性別;反之,若重複性低的欄位則適合建立索引,如:姓名。

• 不要替使用率低的欄位建立索引。

• 不宜替過多欄位建立索引,否則反而會影響到新增、修改、刪除的效能,尤其是以線上交易 (OLTP) 為主的網站資料庫。

• 若資料表存放的資料很少,就不必刻意建立索引。否則可能資料庫沿著索引樹狀結構去搜尋索引中的資料,反而比掃描整個資料表還慢。

• 若查詢時符合條件的資料很多,則透過「非叢集索引」搜尋的效能,可能反而不如整個資料表逐筆掃描。

• 建立「叢集索引」的欄位選擇至為重要,會影響到整個索引結構的效能。要用來建立「叢集索引」的欄位,務必選擇「整數」型別 (鍵值會較小)、唯一、不可為 NULL。

——————————

3、適當地使用索引

• 有些書籍會提到,使用 LIKE、% 做模糊查詢時,即使您已替某個欄位建立索引 (如下方例子的 CustomerID),但以常數字元開頭才會使用到索引,若以萬用字元 (%) 開頭則不會使用索引,如下所示:

USE Northwind;
GO
SELECT * FROM Orders WHERE CustomerID LIKE ‘D%’; –使用索引
SELECT * FROM Orders WHERE CustomerID LIKE ‘%D’; –不使用索引

執行完成後按 Ctrl+L,可檢閱如下圖的「執行計畫」。

圖 1 可看出「查詢最佳化程式」有使用到索引做搜尋

圖 2 在此的叢集索引掃描,並未直接使用索引,效能上幾乎只等於掃描整個資料表

但經版工反覆測試,這種語法是否會使用到索引,抑或會逐筆掃描,並非絕對的。仍要看所下的查詢關鍵字,以及欄位內儲存的資料內容而定。但對於儲存資料筆數龐大的資料表,最好還是少用 LIKE 做模糊查詢。

• 以下的運算子會造成「負向查詢」,常會讓「查詢最佳化程式」無法有效地使用索引,最好能用其他運算子和語法改寫 (經版工測試,並非有負向運算子,就絕對無法使用索引):
NOT 、 != 、 <> 、 !> 、 !< 、 NOT EXISTS 、 NOT IN 、 NOT LIKE

• 避免讓 WHERE 子句中的欄位,去做字串串接或數字運算,否則可能導致「查詢最佳化程式」無法直接使用索引,而改採叢集索引掃描 (經版工測試並非絕對)。

• 資料表中的資料,會依照「叢集索引」欄位的順序存放,因此當您下 BETWEEN、GROUP BY、ORDER BY 時若有包含「叢集索引」欄位,由於資料已在資料表中排序好,因此可提升查詢速度。

• 若使用「複合索引」,要注意索引順序上的第一個欄位,才適合當作過濾條件。

——————————

4、避免在 WHERE 子句中對欄位使用函數

對欄位使用函數,也等於對欄位做運算或串接的動作,一樣可能會讓「查詢最佳化程式」無法有效地使用索引。但真正對效能影響最重大的,是當您的資料表內若有 10 萬筆資料,則在查詢時就需要呼叫函數 10 萬次,這點才是真正的效能殺手。程式員應注意,在系統開發初期可能感覺不出差異,但當系統上線且資料持續累積後,這些語法細節所造成的效能問題就會逐步浮現。

SELECT * FROM Orders WHERE DATEPART(yyyy, OrderDate) = 1996 AND DATEPART(mm, OrderDate)=7
可改成
SELECT * FROM Orders WHERE OrderDate BETWEEN ‘19960701’ AND ‘19960731’

SELECT * FROM Orders WHERE SUBSTRING(CustomerID, 1, 1) = ‘D’
可改成
SELECT * FROM Orders WHERE CustomerID LIKE ‘D%’

注意當您在下 UPDATE、DELETE 陳述式時,若有採用 WHERE 子句,也應符合上述原則。

——————————

5、AND 與 OR 的使用

在 AND 運算中,「只要有一個」條件有用到索引 (如下方的 CustomerID),即可大幅提升查詢速度,如下圖 3 所示:

SELECT * FROM Orders WHERE CustomerID=’VINET’ AND Freight=32.3800 –使用索引,會出現下圖 3 的畫面

SELECT * FROM Orders WHERE Freight=32.3800 –不使用索引,會出現上圖 2 的畫面

圖 3

但在 OR 運算中,則要「所有的」條件都有可用的索引,才能使用索引來提升查詢速度。因此 OR 運算子的使用必須特別小心。

若您將上方 AND 的範例,邏輯運算子改成 OR 的話,如下所示:

SELECT * FROM Orders WHERE CustomerID=’VINET’ OR Freight=32.3800

由於無法有效地使用索引,也會出現圖 2 的畫面。

在使用 OR 運算子時,只要有一個條件 (欄位) 沒有可用的索引,則其他所有的條件 (欄位) 都有索引也沒用,只能如圖 2 般,把整個資料表或整個叢集索引都掃描過,以逐筆比對是否有符合條件的資料。

據網路上文件的說法 [1],上述的 OR 運算陳述式,我們還可用 UNION 聯集適當地改善,如下:

SELECT * FROM Orders WHERE CustomerID=’VINET’
UNION
SELECT * FROM Orders WHERE Freight=32.3800

此時您再按 Ctrl+L 檢閱「執行計畫」,會發現上半段的查詢會使用索引,但下半段仍用叢集索引掃描,對效能不無小補。

——————————

6、適當地使用子查詢

相較於「子查詢 (Subquery)」,若能用 JOIN 完成的查詢,一般會比較建議使用後者。原因除了 JOIN 的語法較容易理解外,在多數的情況下,JOIN 的效能也會比子查詢較佳;但這並非絕對,也有的情況可能剛好相反。

我們知道子查詢可分為「獨立子查詢」和「關聯子查詢」兩種,前者指子查詢的內容可單獨執行,後者則無法單獨執行,亦即外層查詢的「每一次」查詢動作都需要引用內層查詢的資料,或內層查詢的「每一次」查詢動作都需要參考外層查詢的資料。

以下我們看一個比較極端的例子 [2]。若我們希望所有查詢出來的資料,都能另外給一個自動編號,版工我在之前的文章「用 SQL Server 2005 新增的 ROW_NUMBER 函數撰寫 GridView 分頁」中有介紹過,可用 SQL Server 2005 中新增的 ROW_NUMBER 函數輕易地達成,且 ROW_NUMBER 函數還能再加上「分群 (PARTITION BY)」等功能,而且執行效能極佳。

圖 4 將 Orders 資料表的 830 筆資料都撈出來,並在右側給一組自動編號

現在我們要如上圖 4 般,將 Northwind 中 Orders 資料表的 830 筆資料都撈出來,並自動給一組編號,若用 ROW_NUMBER 函數的寫法如下所示,而且效能極佳,只要 2 ms (毫秒),亦即千分之二秒。

SET STATISTICS TIME ON
SELECT OrderID, ROW_NUMBER() OVER(ORDER BY OrderID) AS 編號
FROM dbo.Orders

但如果是在舊版的 SQL Server 2000 中,我們可能得用以下的「子查詢」寫法:

SET STATISTICS TIME ON
SELECT OrderID,
(SELECT COUNT(*) FROM dbo.Orders AS 內圈
WHERE 內圈.OrderID <= 外圈.OrderID) AS 編號
FROM dbo.Orders AS 外圈
ORDER BY 編號

但這種舊寫法,會像先前所提到的,外層查詢的「每一次」查詢動作都需要引用內層查詢的資料。以上方例子而言,外層查詢的每一筆資料,都要等內層查詢「掃描整個資料表」並作比對和計數,因此 830 筆資料每一筆都要重複掃描整個資料表 830 次,所耗用的時間也因此爆增至 170 ms。

若您用相同的寫法,去查詢 AdventureWorks 資料庫中,有 31,465 筆資料的 Sales.SalesOrderHeader 資料表,用 ROW_NUMBER 函數要 677 ms,還不到 1 秒鐘;但用子查詢的話,居然要高達 225,735 ms,將近快 4 分鐘的時間。

雖然這是較極端的範例,但由此可知子查詢的撰寫,在使用上不可不慎,尤其是「關聯子查詢」。程式員在程式開發初期、資料量還很少時感受不到此種 SQL 語法的重大陷阱;但等到系統上線幾個月或一兩年後,可能就會有反應遲緩的現象。

——————————

7、其他查詢技巧

• DISTINCT、ORDER BY 語法,會讓資料庫做額外的計算。此外聯集的使用,若沒有要剔除重複資料的需求,使用 UNION ALL 會比 UNION 更佳,因為後者會加入類似 DISTINCT 的演算法。

• 在 SQL Server 2005 版本中,存取資料庫物件時,最好明確指定該物件的「結構描述 (Schema)」,也就是使用兩節式名稱。否則若呼叫者的預設 Schema 不是 dbo,則 SQL Server 在執行時,會先尋找該使用者預設 Schema 所搭配的物件,找不到的話才會轉而使用預設的 dbo,會多耗費尋找的時間。例如若要執行一個叫做 dbo.mySP1 的 Stored Procedure,應使用以下的兩節式名稱:

EXEC dbo.mySP1

——————————

8、儘可能用 Stored Procedure 取代前端應用程式直接存取資料表

Stored Procedure 除了經過事先編譯、效能較好以外,亦可節省 SQL 陳述式傳遞的頻寬,也方便商業邏輯的重複使用。再搭配自訂函數和 View 的使用,將來若要修改資料表結構、重新切割或反正規化時亦較方便。

——————————

9、儘可能在資料來源層,就先過濾資料

使用 SELECT 語法時,儘量避免傳回所有的資料至前端而不設定 WHERE 等過濾條件。雖然 ASP.NET 中 SqlDataSource、ObjectDataSource 控制項的 FilterExpression 可再做篩選,GridView 控制項的 SortExpression 可再做排序,但會多消耗掉資料庫的系統資源、Web server 的記憶體和網路頻寬。最好還是在資料庫和資料來源層,就先用 SQL 條件式篩選出所要的資料。