Mysql 預處理 PREPARE以及預處理的好處

Mysql 預處理 PREPARE以及預處理的好處

 

Mysql手冊 預處理記載:

預製語句的SQL語法在以下情況下使用:
 
· 在編代碼前,您想要測試預製語句在您的應用程序中運行得如何。或者也許一個應用程序在執行預製語句時有問題,您想要確定問題是什麼。
 
· 您想要創建一個測試案例,該案例描述了您使用預製語句時出現的問題,以便您編制程序錯誤報告。
 
· 您需要使用預製語句,但是您無法使用支持預製語句的編程API。
 
預製語句的SQL語法基於三個SQL語句:
 
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關鍵詞和標識符等。
 
如果帶有此名稱的預製語句已經存在,則在新的語言被預備以前,它會被隱含地解除分配。這意味着,如果新語句包含一個錯誤並且不能被預備,則會返回一個錯誤,並且不存在帶有給定名稱語句。
 
預製語句的範圍是客戶端會話。在此會話內,語句被創建。其它客戶端看不到它。
 
在預備了一個語句後,您可使用一個EXECUTE語句(該語句引用了預製語句名稱)來執行它。如果預製語句包含任何參數製造符,則您必須提供一個列舉了用戶變量(其中包含要與參數結合的值)的USING子句。參數值只能有用戶變量提供,USING子句必須準確地指明用戶變量。用戶變量的數目與語句中的參數製造符的數量一樣多。
 
您可以多次執行一個給定的預製語句,在每次執行前,把不同的變量傳遞給它,或把變量設置爲不同的值。
 
要對一個預製語句解除分配,需使用DEALLOCATE PREPARE語句。嘗試在解除分配後執行一個預製語句會導致錯誤。
 
如果您終止了一個客戶端會話,同時沒有對以前已預製的語句解除分配,則服務器會自動解除分配。
 

以下SQL語句可以被用在預製語句中:CREATE TABLE, DELETE, DO, INSERT, REPLACE, SELECT, SET, UPDATE和多數的SHOW語句。目前不支持其它語句。

以下例子顯示了預備一個語句的兩種方法。該語句用於在給定了兩個邊的長度時,計算三角形的斜邊。
第一個例子顯示如何通過使用文字字符串來創建一個預製語句,以提供語句的文本:
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;
第二個例子是相似的,不同的是提供了語句的文本,作爲一個用戶變量:

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;
預製語句的SQL語法不能被用於帶嵌套的風格中。也就是說,被傳遞給PREPARE的語句本身不能是一個PREPARE, EXECUTE或DEALLOCATE PREPARE語句。
 
預製語句的SQL語法與使用預製語句API調用不同。例如,您不能使用mysql_stmt_prepare() C API函數來預備一個PREPARE, EXECUTE或DEALLOCATE PREPARE語句。
 
預製語句的SQL語法可以在已存儲的過程中使用,但是不能在已存儲的函數或觸發程序中使用。

 

Prepare SQL產生的原因

1. 首先從mysql服務器執行sql的過程開始講起,SQL執行過程包括以下階段 詞法分析->語法分析->語義分析->執行計劃優化->執行。詞法分析->語法分析這兩個階段我們稱之爲硬解析。詞法分析識別sql中每個詞,語法分析解析SQL語句是否符合sql語法,並得到一棵語法樹(Lex)。對於只是參數不同,其他均相同的sql,它們執行時間不同但硬解析的時間是相同的。而同一SQL隨着查詢數據的變化,多次查詢執行時間可能不同,但硬解析的時間是不變的。對於sql執行時間較短,sql硬解析的時間佔總執行時間的比率越高。
2. Prepare的出現就是爲了優化硬解析的問題。Prepare在服務器端的執行過程如下
  1) Prepare 接收客戶端帶”?”的sql, 硬解析得到語法樹(stmt->Lex), 緩存在線程所在的preparestatement cache中。此cache是一個HASH MAP. Key爲stmt->id. 然後返回客戶端stmt->id等信息。
  2) Execute 接收客戶端stmt->id和參數等信息。注意這裏客戶端不需要再發sql過來。服務器根據stmt->id在preparestatement cache中查找得到硬解析後的stmt, 並設置參數,就可以繼續後面的優化和執行了。

 

Prepared Statements優點

1.安全

Prepared Statements通過sql邏輯與數據的分離來增加安全,sql邏輯與數據的分離能防止普通類型的sql注入攻擊(SQL injection attack)。

2.性能

Prepared Statements只語法分析一次,你初始話Prepared Statements時,mysql將檢查語法並準備語句的運行,當你執行query 多次時,這樣就不會在有額外的負擔了,如果,當運行query 很多次的時候(如:insert)這種預處理有很大的性能提高
他使用binary protocol協議,這樣更能提高效率。
 

例子:

執行兩條sql查詢:
select * from a where id>1
select * from a where id>10
按執行順序:詞法分析->語法分析->語義分析->執行計劃優化->執行 。執行兩遍。如果使用Prepare,節約硬解析時間。那麼同樣執行上面的sql。

prepare first_ prepare from 'select * from a where id>(?)'; 
其中?可以傳入不同參數。
1. 按執行順序:第一次:詞法分析->語法分析->語義分析->執行計劃優化->執行 。
2. 第二次:語義分析->執行計劃優化->執行 。節約了一次硬解析時間。
 
> Prepare在execute階段可以節省硬解析的時間。如果sql只執行一次,且以prepare的方式執行,那麼sql執行需兩次與服務器交互(Prepare和execute), 而以普通(非prepare)方式,只需要一次交互。這樣使用prepare帶來額外的網絡開銷,可能得不償失。我們再來看同一sql執行多次的情況,比如以prepare方式執行10次,那麼只需要一次硬解析。這時候 額外的網絡開銷就顯得微乎其微了。因此prepare適用於頻繁執行的SQL。
 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章