<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
MySQL在伺服器端提供唯讀的、單向的遊標,而且只能在儲存過程或者更底層的使用者端API中使用。
因為MySQL遊標中指向的物件都是儲存在臨時表中而不是實際查詢到的資料,所以MySQL遊標總是唯讀的。它可以逐行指向查詢結果,然後讓程式做進一步的處理。在一個儲存過程中,可以有多個遊標,也可以在迴圈中“巢狀”地使用遊標。
MySQL的遊標設計也為粗心的人“準備”了陷阱。因為是使用臨時表實現的,所以它在效率上給開發人員一個錯覺。需要記住的最重要的一點是:當你開啟一個遊標的時候需要執行整個查詢。
考慮下面的儲存過程:
CREATE PROCEDURE bad_cursor() BEGIN DECLARE film_id INT; DECLARE f CURSOR FOR SELECT film_id FROM sakila.film; OPEN f; FETCH f INTO film_id; CLOSE f; END
從這個例子中可以看到,不用處理完所有的資料就可以立刻關閉遊標。使用Oracle或者SQL Server的使用者不會認為這個儲存過程有什麼問題,但是在MySQL中,這會帶來很多的不必要的額外操作。使用SHOW STATUS來診斷這個儲存過程,可以看到它需要做1000個索引頁的讀取,做1000個寫入。這是因為在表sakila.film中有1000條記錄,而所有這些讀和寫都發生在第五行的開啟遊標動作。
這個案例告訴我們,如果在關閉遊標的時候你只是掃描一個大結果集的一小部分,那麼儲存過程可能不僅沒有減少開銷,相反帶來了大量的額外開銷。這時,你需要考慮使用LIMIT來限制返回的結果集。
遊標也會讓MySQL執行一些額外的I/O操作,而這些操作的效率可能非常低。因為臨時記憶體表不支援BLOB和TEXT型別,如果遊標返回的結果包含這樣的列的話,MySQL就必須建立臨時磁碟表來存放,這樣效能可能會很糟。即使沒有這樣的列,當臨時表大於tmp_table_size的時候,MyQL也還是會在磁碟上建立臨時表。
MySQL不支援使用者端的遊標,不過使用者端API可以通過快取全部查詢結果的方式模擬使用者端的遊標。這和直接將結果放在一個記憶體陣列中來維護並沒有什麼不同。
從MySQL 4.1版本開始,就支援伺服器端的繫結變數(prepared statement),這大大提高了使用者端和伺服器端資料傳輸的效率。你若使用一個支援新協定的使用者端,如MySQL CAPI,就可以使用繫結變數功能了。另外,Java和.NET的也都可以使用各自的使用者端Connector/J和Connector/NET來使用繫結變數。
最後,還有一個SQL介面用於支援繫結變數,後面我們將討論這個(這裡容易引起困擾)。
當建立一個繫結變數SQL時,使用者端向伺服器傳送了一個SQL語句的原型。伺服器端收到這個SQL語句框架後,解析並儲存這個SQL語句的部分執行計劃,返回給使用者端一個SQL語句處理控制程式碼。以後每次執行這類查詢,使用者端都指定使用這個控制程式碼。
繫結變數的SQL,使用問號標記可以接收引數的位置,當真正需要執行具體查詢的時候,則使用具體值代替這些問號。例如,下面是一個繫結變數的SQL語句:
INSERT INTO tbl(col1, col2, col3) VALUES (?, ?, ?);
可以通過向伺服器端傳送各個問號的取值和這個SQL的控制程式碼來執行一個具體的查詢。反覆使用這樣的方式執行具體的查詢,這正是繫結變數的優勢所在。具體如何傳送取值引數和SQL控制程式碼,則和各個使用者端的程式語言有關。使用Java和.NET的MySQL聯結器就是一種辦法。很多使用MySQL C語言連結庫的使用者端可以提供類似的介面,需要根據使用的程式語言的檔案來了解如何使用繫結變數。
因為如下的原因,MySQL在使用繫結變數的時候可以更高效地執行大量的重複語句:
1.在伺服器端只需要解析一次SQL語句。
2.在伺服器端某些優化器的工作只需要執行一次,因為它會快取一部分的執行計劃。
4.僅僅是引數——而不是整個查詢語句——需要傳送到伺服器端,所以網路開銷會更小。
5.MySQL在儲存引數的時候,直接將其存放到快取中,不再需要在記憶體中多次複製。
繫結變數相對也更安全。無須在應用程式中處理跳脫,一則更簡單了,二則也大大減少了SQL隱碼攻擊和攻擊的風險。(任何時候都不要信任使用者輸入,即使是使用繫結變數的時候。)
可以只在使用繫結變數的時候才使用二進位制傳輸協定。如果使用普通的mysql_query()介面則不會使用二進位制傳輸協定。還有一些使用者端讓你使用繫結變數,先傳送帶引數的繫結SQL,然後傳送變數值,但是實際上,這些使用者端只是模擬了繫結變數的介面,最後還是會直接用具體值代替引數後,再使用mysql_query()傳送整個查詢語句。
對使用繫結變數的SQL,MySQL能夠快取其部分執行計劃,如果某些執行計劃需要根據傳入的引數來計算時,MySQL就無法快取這部分的執行計劃。根據優化器什麼時候工作,可以將優化分為三類。
在本書編寫的時候,下面的三點是適用的。
1.在準備階段
2.在第一次執行的時候
3.在每次SQL語句執行時
1)過濾分割區。
2)如果可能的話,儘量移除COUNT()、MIN()和MAX()。
3)移除常數表示式。
4)檢測常數表。
5)做必要的等值傳播。
6)分析和優化ref、range和索引優化等存取資料的方法。
7)優化關聯順序。
MySQL支援了SQL介面的繫結變數。不使用二進位制傳輸協定也可以直接以SQL的方式使用繫結變數。下面案例展示瞭如何使用SQL介面的繫結變數:
當伺服器收到這些SQL語句後,先會像一般使用者端的連結庫一樣將其翻譯成對應的操作。
這意味著你無須使用二進位制協定也可以使用繫結變數。
正如你看到的,比起直接編寫的SQL語句,這裡的語法看起來有一些怪怪的。
那麼,這種寫法實現的繫結變數到底有什麼優勢呢?
最主要的用途就是在儲存過程中使用。在MySQL 5.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 LEAVE 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')
另一種實現儲存過程中迴圈的辦法是:
REPEAT FETCH 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語句非常非常長,並且需要多次執行的時候。
關於繫結變數的一些限制和注意事項如下:
1.繫結變數是對談級別的,所以連線之間不能共用繫結變數控制程式碼。同樣地,一旦連線斷開,則原來的控制程式碼也不能再使用了。(連線池和持久化連線可以在一定程度上緩解這個問題。)
2.在MySQL 5.1版本之前,繫結變數的SQL是不能使用查詢快取的。
3.並不是所有的時候使用繫結變數都能獲得更好的效能。如果只是執行一次SQL,那麼使用繫結變數方式無疑比直接執行多了一次額外的準備階段消耗,而且還需要一次額外的網路開銷。(要正確地使用繫結變數,還需要在使用完成後,釋放相關的資源。)
4.當前版本下,還不能在儲存函數中使用繫結變數(但是儲存過程中可以使用)。
5.如果總是忘記釋放繫結變數資源,則在伺服器端很容易發生資源“洩漏”。繫結變數 SQL總數的限制是一個全域性限制,所以某一個地方的錯誤可能會對所有其他的執行緒都產生影響。
6.有些操作,如BEGIN,無法在繫結變數中完成。
不過使用繫結變數最大的障礙可能是:
它是如何實現以及原理是怎樣的,這兩點很容易讓人困惑。有時,很難解釋如下三種系結變數型別之間的區別是什麼:
1.使用者端模擬的繫結變數
2.伺服器端的繫結變數
3.SQL介面的繫結變數
參考:《高效能MySQL》
以上為個人經驗,希望能給大家一個參考,也希望大家多多支援it145.com。
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45