從mysql 4.1版本開始,就支援伺服器端的繫結變數(prepared statement),這大大提高了客戶端和伺服器端資料傳輸的效率。你若使用乙個支援新協議的客戶端,如mysql c api,就可以使用繫結變數功能了。另外,j**a和.net的也都可以使用各自的客戶端connector/j和connector/net來使用繫結變數。最後,還有乙個sql介面用於支援繫結變數,後面我們將討論這個(這裡容易引起困擾)。
當建立乙個繫結變數sql時,客戶端向伺服器傳送了乙個sql語句的原型。伺服器端收到這個sql語句框架後,解析並儲存這個sql語句的部分執行計畫,返回給客戶端乙個sql語句處理控制代碼。以後每次執行這類查詢,客戶端都指定使用這個控制代碼。
繫結變數的sql,使用問號標記可以接收引數的位置,當真正需要執行具體查詢的時候,則使用具體值代替這些問號。例如,下面是乙個繫結變數的sql語句:
insert into tbl(col1, col2, col3) values (?, ?, ?);
可以通過向伺服器端傳送各個問號的取值和這個sql的控制代碼來執行乙個具體的查詢。反覆使用這樣的方式執行具體的查詢,這正是繫結變數的優勢所在。具體如何傳送取值引數和sql控制代碼,則和各個客戶端的程式語言有關。使用j**a和.net的mysql聯結器就是一種辦法。很多使用mysql c語言鏈結庫的客戶端可以提供類似的介面,需要根據使用的程式語言的文件來了解如何使用繫結變數。
因為如下的原因,mysql在使用繫結變數的時候可以更高效地執行大量的重複語句:
繫結變數相對也更安全。無須在應用程式中處理轉義,一則更簡單了,二則也大大減少 了sql注入和攻擊的風險。(任何時候都不要信任使用者輸入,即使是使用繫結變數的時候。)
可以只在使用繫結變數的時候才使用二進位制傳輸協議。如果使用普通的mysql_query()介面則不會使用二進位制傳輸協議。還有一些客戶端讓你使用繫結變數,先傳送帶引數的繫結sql,然後傳送變數值,但是實際上,這些客戶端只是模擬了繫結變數的介面,最後還是會直接用具體值代替引數後,再使用mysql_query()傳送整個查詢語句。
對使用繫結變數的sql, mysql能夠快取其部分執行計畫,如果某些執行計畫需要根據傳入的引數來計算時,mysql就無法快取這部分的執行計畫。根據優化器什麼時候工作,可以將優化分為三類。mysql5.6版本之前,下面的三點是適用的。
在準備階段
伺服器解析sql語句,移除不可能的條件,並且重寫子查詢。
在第一次執行的時候
如果可能的話,伺服器先簡化巢狀迴圈的關聯,並將外關聯轉化成內關聯。
在每次sql語句執行時
伺服器做如下事情:
理論上,有些優化只需要做一次,但實際上,上面的操作還是都會被執行。
在4.1和更新的版本中,mysql支援了sql介面的繫結變數。不使用二進位制傳輸協議也可以直接以sql的方式使用繫結變數。下面案例展示了如何使用sql介面的繫結變數:
mysql> set @sql := 'select actor_id, first_name, last_name
-> from sakila.actor where first_name = ?'
;mysql>prepare stmt_fetch_actor from @sql;
mysql> set @actor_name := '
penelope';
mysql>execute stmt_fetch_actor using @actor_name;
+----------+------------+-----------+
| actor_id | first_name | last_name |
+----------+------------+-----------+
| 1 | penelope | guiness |
| 54 | penelope | pinkett |
| 104 | penelope | cronyn |
| 120 | penelope | monroe |
+----------+------------+-----------+mysql> deallocate prepare stmt_fetch_actor;
當伺服器收到這些sql語句後,先會像一般客戶端的鏈結庫一樣將其翻譯成對應的操作。這意味著你無須使用二進位制協議也可以使用繫結變數。
正如你看到的,比起直接編寫的sql語句,這裡的語法看起來有一些怪怪的。那麼,這種寫法實現的繫結變數到底有什麼優勢呢?
最主要的用途就是在儲存過程中使用。在mysql5.0版本中,就可以在儲存過程中使用繫結變數,其語法和前面介紹的sql介面的繫結變數類似。這意味,可以在儲存過程中構建並執行「動態」的sql語句,這裡的「動態」是指可以通過靈活地拼接字串等引數構建sql語句。例如,下面的示例儲存過程中可以針對某個資料庫執行optimize table的操作:
drop procedure if exists optimize_tables;delimiter //create procedure optimize_tables(db_name varchar(64))
begin
declare t varchar(64);
declare done int default 0;
declare c cursor for
select table_name from information_schema.tables
where table_schema = db_name and table_type = '
base table';
declare continue handler for sqlstate
'02000
' set done = 1;
open c;
tables_loop: loop
fetch c into t;
if done then
le**e tables_loop;
end if;
set @stmt_text := concat("
optimize table
", db_name, "."
, t);
prepare stmt from @stmt_text;
execute stmt;
deallocate prepare stmt;
end loop;
close c;
end//delimiter ;
可以這樣呼叫這個儲存過程:
mysql> call optimize_tables('sakila
');
另一種實現儲存過程中迴圈的辦法是:
repeatfetch c into t;
if not done then
set @stmt_text := concat("
optimize table
", db_name, "."
, t);
prepare stmt from @stmt_text;
execute stmt;
deallocate prepare stmt;
end if;
until done end repeat;
這兩種迴圈結構最重要的區別在於:repeat會為每個迴圈檢查兩次迴圈條件。在這個例子中,因為迴圈條件檢查的是乙個整數判斷,並不會有什麼效能問題,如果迴圈的判斷條件非常複雜的話,則需要注意這兩者的區別。
像這樣使用sql介面的繫結變數拼接表名和庫名是很常見的,這樣的好處是無須使用任何引數就能完成sql語句。而庫名和表名都是關鍵字,在二進位制協議的繫結變數中是不能將這兩部分引數化的。另乙個經常需要動態設定的就是limit子句,因為二進位制協議中也無法將這個值引數化。
另外,編寫儲存過程時,sql介面的繫結變數通常可以很大程度地幫助我們除錯繫結變數,如果不是在儲存過程中,sql介面的繫結變數就不是那麼有用了。因為sql介面的繫結變數,它既沒有使用二進位制傳輸協議,也沒有能夠節省頻寬,相反還總是需要增加至少一次額外網路傳輸才能完成一次查詢。所有只有在某些特殊的場景下sql介面的繫結變數才有用,比如當sql語句非常非常長,並且需要多次執行的時候。
關於繫結變數的一些限制和注意事項如下:
不過使用繫結變數最大的障礙可能是:它是如何實現以及原理是怎樣的,這兩點很容易讓人困惑。有時,很難解釋如下三種繫結變數型別之間的區別是什麼:
客戶端模擬的繫結變數
客戶端的驅動程式接收乙個帶引數的sql,再將指定的值帶入其中,最後將完整的查詢傳送到伺服器端。
伺服器端的繫結變數
客戶端使用特殊的二進位制協議將帶引數的字串傳送到伺服器端,然後使用二進位制協議將具體的引數值傳送給伺服器端並執行。
sql介面的繫結變數
客戶端先傳送乙個帶引數的字串到伺服器端,這類似於使用prepare的sql語句,然後傳送設定引數的sql,最後使用execute來執行sql。所有這些都使用普通的文字傳輸協議。
Oracle 資料庫的繫結變數特性及應用
繫結變數 binding variable 共享池 shared buffer pool sga system global area 在開發乙個資料庫系統前,有誰對oracle 系統了解很多,尤其是它的特性,好象很少吧 對初學者來講,這更是不可能的事情 僅僅簡單掌握了sql的寫法,就開始了資料庫的...
pl sql 繫結變數
在oracle 中,對於乙個提交的sql語句,存在兩種可選的解析過程,一種叫做硬解析,一種叫做軟解析.乙個硬解析需要經解析,制定執行路徑,優化訪問計畫等許多的步驟.硬解析不僅僅耗費大量的cpu,更重要的是會佔據重要的們閂 latch 資源,嚴重的影響系統的規模的擴大 即限制了系統的並發行 而且引起的...
繫結變數窺測
事物都存在兩面性,繫結變數對大多數oltp處理是適用的,但是也有例外。比如在where條件中的字段是 傾斜字段 的時候。傾斜字段 指該列中的絕大多數的值都是相同的,比如一張人口調查表,其中 民族 這列,90 以上都是漢族。那麼如果乙個sql語句要查詢30歲的漢族人口有多少,那 民族 這列必然要被放在...