MySQL 5.1對服務器一方的預製語句提供支持。若是您使用合適的客戶端編程界面,則這種支持能夠發揮在MySQL 4.1中實施的高效客戶端/服務器二進制協議的優點。候選界面包括MySQL C API客戶端庫(用於C程序)、MySQL Connector/J(用於Java程序)和MySQL Connector/NET。例如,C API能夠提供一套能組成預製語句API的函數調用。其它語言界面能夠對使用了二進制協議(經過在C客戶端庫中連接)的預製語句提供支持。對預製語句,還有一個SQL界面能夠利用。與在整個預製語句API中使用二進制協議相比,本界面效率沒有那麼高,可是它不要求編程,由於在SQL層級,能夠直接利用本界面:php
· 當您沒法利用編程界面時,您可使用本界面。html
· 有些程序容許您發送SQL語句到將被執行的服務器中,好比mysql客戶端程序。您能夠從這些程序中使用本界面。mysql
· 即便客戶端正在使用舊版本的客戶端庫,您也可使用本界面。惟一的要求是,您可以鏈接到一個支持預製語句SQL語法的服務器上。sql
預製語句的SQL語法在如下狀況下使用:數據庫
· 在編代碼前,您想要測試預製語句在您的應用程序中運行得如何。或者也許一個應用程序在執行預製語句時有問題,您想要肯定問題是什麼。編程
· 您想要建立一個測試案例,該案例描述了您使用預製語句時出現的問題,以便您編制程序錯誤報告。緩存
· 您須要使用預製語句,可是您沒法使用支持預製語句的編程API。服務器
預製語句的SQL語法基於三個SQL語句:併發
1
2
3
4
5
|
PREPARE
stmt_name
FROM
preparable_stmt;
EXECUTE
stmt_name [USING @var_name [, @var_name] ...];
{
DEALLOCATE
|
DROP
}
PREPARE
stmt_name;
|
PREPARE語句用於預備一個語句,並賦予它名稱stmt_name,藉此在之後引用該語句。語句名稱對案例不敏感。preparable_stmt能夠是一個文字字符串,也能夠是一個包含了語句文本的用戶變量。該文本必須展示一個單一的SQL語句,而不是多個語句。使用本語句,‘?'字符能夠被用於製做參數,以指示當您執行查詢時,數據值在哪裏與查詢結合在一塊兒。‘?'字符不該加引號,即便您想要把它們與字符串值結合在一塊兒,也不要加引號。參數製做符只能被用於數據值應該出現的地方,不用於SQL關鍵詞和標識符等。oracle
若是帶有此名稱的預製語句已經存在,則在新的語言被預備之前,它會被隱含地解除分配。這意味着,若是新語句包含一個錯誤而且不能被預備,則會返回一個錯誤,而且不存在帶有給定名稱語句。
預製語句的範圍是客戶端會話。在此會話內,語句被建立。其它客戶端看不到它。
在預備了一個語句後,您可以使用一個EXECUTE語句(該語句引用了預製語句名稱)來執行它。若是預製語句包含任何參數製造符,則您必須提供一個列舉了用戶變量(其中包含要與參數結合的值)的USING子句。參數值只能有用戶變量提供,USING子句必須準確地指明用戶變量。用戶變量的數目與語句中的參數製造符的數量同樣多。
您能夠屢次執行一個給定的預製語句,在每次執行前,把不一樣的變量傳遞給它,或把變量設置爲不一樣的值。
要對一個預製語句解除分配,需使用DEALLOCATE PREPARE語句。嘗試在解除分配後執行一個預製語句會致使錯誤。
若是您終止了一個客戶端會話,同時沒有對之前已預製的語句解除分配,則服務器會自動解除分配。
如下SQL語句能夠被用在預製語句中:CREATE TABLE, DELETE, DO, INSERT, REPLACE, SELECT, SET, UPDATE和多數的SHOW語句。目前不支持其它語句。
如下例子顯示了預備一個語句的兩種方法。該語句用於在給定了兩個邊的長度時,計算三角形的斜邊。
第一個例子顯示如何經過使用文字字符串來建立一個預製語句,以提供語句的文本:
1
2
3
4
5
6
7
8
9
10
|
mysql>
PREPARE
stmt1
FROM
'SELECT SQRT(POW(?,2) + POW(?,2)) AS hypotenuse'
;
mysql>
SET
@a = 3;
mysql>
SET
@b = 4;
mysql>
EXECUTE
stmt1 USING @a, @b;
+
------------+
| hypotenuse |
+
------------+
| 5 |
+
------------+
mysql>
DEALLOCATE
PREPARE
stmt1;
|
第二個例子是類似的,不一樣的是提供了語句的文本,做爲一個用戶變量:
1
2
3
4
5
6
7
8
9
10
11
|
mysql>
SET
@s =
'SELECT SQRT(POW(?,2) + POW(?,2)) AS hypotenuse'
;
mysql>
PREPARE
stmt2
FROM
@s;
mysql>
SET
@a = 6;
mysql>
SET
@b = 8;
mysql>
EXECUTE
stmt2 USING @a, @b;
+
------------+
| hypotenuse |
+
------------+
| 10 |
+
------------+
mysql>
DEALLOCATE
PREPARE
stmt2;
|
對於已預備的語句,您可使用位置保持符。如下語句將從tb1表中返回一行:
1
2
3
4
5
|
mysql>
SET
@a=1;
mysql>
PREPARE
STMT
FROM
"SELECT * FROM tbl LIMIT ?"
;
mysql>
EXECUTE
STMT USING @a;
|
如下語句將從tb1表中返回第二到第六行:
1
2
3
4
5
|
mysql>
SET
@skip=1;
SET
@numrows=5;
mysql>
PREPARE
STMT
FROM
"SELECT * FROM tbl LIMIT ?, ?"
;
mysql>
EXECUTE
STMT USING @skip, @numrows;
|
預製語句的SQL語法不能被用於帶嵌套的風格中。也就是說,被傳遞給PREPARE的語句自己不能是一個PREPARE, EXECUTE或DEALLOCATE PREPARE語句。
預製語句的SQL語法與使用預製語句API調用不一樣。例如,您不能使用mysql_stmt_prepare() C API函數來預備一個PREPARE, EXECUTE或DEALLOCATE PREPARE語句。
預製語句的SQL語法能夠在已存儲的過程當中使用,可是不能在已存儲的函數或觸發程序中使用。
以上就是本文的所有內容,但願對你們的學習有所幫助。
在oracle數據庫中,有一個變量綁定的用法,不少人都比較熟悉,能夠調高數據庫效率,應對高併發等,好吧,這其中並不包括我,當同事問我MySQL中有沒有相似的寫法時,我是很茫然的,因而就上網查,找到了以下一種寫法
代碼以下:
用這種形式寫的查詢,能夠隨意替換參數,給出代碼的人稱之爲預處理,我想這個應該就是MySQL中的變量綁定吧……可是,在查資料的過程當中我卻聽到了兩種聲音,一種是,MySQL中有相似Oracle變量綁定的寫法,但沒有其實際做用,也就是隻能方便編寫,不能提升效率,這種說法在幾個09年的帖子中看到:
http://www.itpub.net/thread-1210292-1-1.html
http://cuda.itpub.net/redirect.php?fid=73&tid=1210572&goto=nextnewset
另外一種說法是MySQL中的變量綁定是能確實提升效率的,這個是但願有的,那到底有木有,仍是本身去試驗下吧。
試驗是在本機進行的,數據量比較小,具體數字並不具備實際意義,可是,能用來講明一些問題,數據庫版本是mysql-5.1.57-win32免安裝版。
本着對數據庫不是很熟悉的態度^_^,試驗過程當中走了很多彎路,此文以結論爲主,就不列出實驗的設計過程,文筆很差,文章寫得有點枯燥,寫出來是但願有人來拍磚,由於我得出的結論是:預處理在有沒有cache的狀況下的執行效率都不及直接執行…… 我對本身的實驗結果不肯接受。。若是說預處理只爲了規範下Query,使cache命中率提升的話我的以爲大材小用了,但願有比較瞭解的人能指出事實到底是什麼樣子的——NewSilen
實驗準備
第一個文件NormalQuery.sql
第二個sql文件 StmtQuery.sql
作幾點小說明:
1. Set profiling=1; 執行此語句以後,能夠從information_schema.profiling這張表中讀出語句執行的詳細信息,其實包含很多內容,包括我須要的時間信息,這是張臨時表,每新開一個會話都要從新設置profiling屬性才能從這張表中讀取數據
2. Select * From MyTable where DictID = 100601000004;
這行代碼貌似和咱們的實驗沒什麼關係,原本我也是這麼認爲的,之因此加這句,是我在以前的摸索中發現,執行過程當中有個步驟是open table,若是是第一次打開某張表,那時間是至關長的,因此在執行後面的語句前,我先執行了這行代碼打開試驗用的表
3. MySQL默認在information_schema.profiling表中保存的查詢歷史是15條,能夠修改profiling_history_size屬性來進行調整,我但願他大一些讓我能一次取出足夠的數據,不過最大值只有100,儘管我調整爲150,最後可以查到的也只有100條,不過也夠了
4. SQL代碼我沒有全列出來,由於查詢語句差很少,上面代碼中用省略號表示了,最後的結果是兩個csv文件,我的習慣,你也能夠把結果存到數據庫進行分析
實驗步驟
重啓數據庫,執行文件NormalQuery.sql,執行文件StmtQuery.sql,獲得兩個結果文件
再重啓數據庫,執行StmtQuery.sql,執行文件NormalQuery.sql,獲得另外兩個結果文件
實驗結果
詳細結果在最後提供了附件下載,有興趣的朋友能夠看下
結果分析
每個SQL文件中執行了一百個查詢語句,沒有重複的查詢語句,不存在查詢cache,統計執行SQL的平均時間得出以下結果
從結果中能夠看出,不管是先執行仍是後執行,NormalQuery中的語句都比使用預處理語句的要快一些=.=!
那再來看看每一句查詢具體的狀況,Normal和Stmt的query各執行了兩百次,每一步的詳細信息以下:
從這裏面能夠看出,第一個,normalquery比stmtquery少一個步驟,第二個,雖然stmt在很多步驟上是優於normal的,但在executing一步上輸掉太多,最後結果上也是落敗
最後,再給出一個查詢緩存的實驗結果,具體步驟就不列了
在查詢緩存的時候,Normal完勝……
寫在最後
大概狀況就是這樣,我回憶了一下,網上說預處理能夠提升效率的,基本都是用編程的方式去執行查詢,不知道這個有沒有關係,基礎有限,但願園子裏的大牛能看到,幫忙解惑實驗結果附件