共計 3333 個字符,預計需要花費 9 分鐘才能閱讀完成。
自動寫代碼機器人,免費開通
丸趣 TV 小編給大家分享一下 MySQL 數據庫中預處理 prepared statement 性能測試的示例,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!
1、預處理干了什么
當我們提交一條數據庫語句時,語句到達數據庫服務那邊,數據庫服務需要解析這條 sql 語句,比如說語法檢查,查詢條件先后優化,然后才執行。對于預處理,簡單來說就是把客戶端與數據庫服務原本一次交互的分成兩次。首先,提交數據庫語句,讓數據庫服務先解析這條語句。其次,提交參數,調用語句并執行。這樣對于多次重復執行的語句來說,可以提交并解析一次數據庫語句就可以了,然后不斷的調用剛剛解析過得語句并執行。這樣就省去了多次解析同一條語句的時間。從而達到提高效率的目的。
預處理語句支持占位符(place holder), 通過綁定占位符的方式提交參數。一個非常重要的一點是,能與占位符綁定的只能是值,而不能是 sql 語句的一些關鍵詞。例如語句:“select * from student where student.id = ?”。如果放入占位符(?)中的是“1 or 1=1”,那么“1 or 1=1”就會被當成一個值,即用 “ 符號包括起來,最終這條非法的語句就出錯了。從而達到放 sql 注入的漏洞(sql injestion)。
預處理機制主要的三步驟:
1、將語句進行預處理
2、執行語句
3、析構掉預處理語句。
2、關于 `performance_schema`.`prepared_statements_instances` 表的介紹
運行 sql 腳本:show global variable like‘%prepare%’。可以看到一個叫‘performance_schema_max_prepared_statement_instances’的系統變量。其值為 0 表示不啟用預處理語句性能數據記錄表 `performance_schema`.`prepared_statements_instances`;- 1 表示記錄的數量動態處理;其他正整數值則表示 performance_schema_max_prepared_statement_instances 記錄的最大條數。
表 `performance_schema`.`prepared_statements_instances` 又是什么呢?它是用來記錄預處理語句的一些基本信息和性能數據。比如預處理語句的 ID,預處理語句的名字,預處理語句的具體語句內容,預處理語句被執行的次數,每次執行耗時,每條預處理語句所屬的線程 id 等。當我們創建一條預處理語句時,就會插入一條數據到這張表里。預處理語句是基于連接的,連接斷開,則預處理語句自動刪除。但 `performance_schema`.`prepared_statements_instances` 表是全局的,它與數據庫連接沒關系。有了這些數據,我們就可以知道,1、代碼中執行的語句是否真的做了預處理,2、通過了解預處理語句的執行情況來決定業務中是否需要把一個語句進行預處理。
3、qt prepare 函數說明
根據我自己本身的項目需求,這次測試的客戶端代碼使用的是 Qt。這里記錄一個關鍵的函數:QSqlQuery 類的 prepare 函數。調用 prepare 函數即是向數據庫提交一個創建預處理語句的命令。意味著調用期間,是會與數據庫服務進行一次交互的。需要注意的是,當同一個 QSqlQuery 類對象調用第二次 prepare 時,會將第一次調用 prepare 創建的預處理語句刪除掉,然后再創建一條預處理語句,即便是這兩條預處理語句是一模一樣的。在調用 QSqlQuery 的 exec 函數時,也會將 QSqlQuery 先前創建的預處理語句刪除掉。所以在查詢結束,關閉掉連接,或者查詢又執行了其他語句,從而導致 `performance_schema`.`prepared_statements_instances` 表沒有相關預處理語句的記錄,就會誤認為預處理語句創建失敗。其實 Qt 的這種做法,也省去了要我們人為的刪除預處理語句。
4、實驗猜想
常規執行的語句和預處理后執行的語句不同點在于,在多次執行的情況下,預處理語句只需解析一次 sql 語句,而之后多花時間在傳輸參數和綁定參數上。預處理語句在返回結果時,使用的是二進制傳輸協議,而普通語句使用的是文本格式的傳輸協議。因此我們做出以下猜想并驗證。
1、如果執行的是簡單語句,那么普通執行和預處理執行性能上差別不大。預處理語句在重復執行復雜的語句情況下才展現出優勢。
2、在查詢結果集是大數據量的情況下,預處理語句會展現出性能優勢。
5、實驗數據記錄
序號是否預處理語句是否遠程數據庫返回數據量每次實驗語句執行總次數三次實驗平均總耗時 / 單位毫秒 1 是 select * from task where task.taskId in (?) 是 10001000698222 否 select * from task where task.taskId in (arr) 是 10001000667783 是 select * from task where task.taskId = ? 是 1100012604 否 select * from task where task.taskId = id 是 110009515 是 select * from task a LEFT JOIN task_file b ON a.taskId = b.task_id where a.taskName like %s% and b.file_id 100000 and b.file_id 200000 and a.taskId =?是 2100021306 否 select * from task a LEFT JOIN task_file b ON a.taskId = b.task_id where a.taskName like %s% and b.file_id 100000 and b.file_id 200000 and a.taskId = 32327 是 2100014807 是 select * from task where task.taskId in (?) 否 10001000570518 否 select * from task where task.taskId in (arr) 否 10001000562359 是 select * from task where task.taskId = ? 否 1100021710 否 select * from task where task.taskId = id 否 1100020411 是 select * from task a LEFT JOIN task_file b ON a.taskId = b.task_id where a.taskName like %s% and b.file_id 100000 and b.file_id 200000 and a.taskId =?否 2100036612 否 select * from task a LEFT JOIN task_file b ON a.taskId = b.task_id where a.taskName like %s% and b.file_id 100000 and b.file_id 200000 and a.taskId = 32327 否 21000380
6、結論
實驗的數據結果和我預期的相差有點兒大,但經過反復檢查測試代碼和測試過程,確認測試本身應該沒有問題。尊重實驗數據,我們得出以下結論:
1、通過實驗 5 和實驗 6 對比,實驗 11 和實驗 12 對比,可得猜想 1 是錯誤的。結論應該是:MySQL 預處理和常規查詢在簡單語句和復雜語句下,都沒有顯著性的性能差別。
2、通過實驗 1 和實驗 2 對比,實驗 7 和實驗 8 對比,可得猜想 2 是錯誤的。結論應該是:MySQL 預處理和常規查詢的結果在數據傳輸上沒有顯著性的性能差距。
3、此外,對比遠程數據庫和本地數據庫實驗數據。可得結論:MySQL 數據庫在本地會給數據操作帶來顯著性的性能提高。
以上是“MySQL 數據庫中預處理 prepared statement 性能測試的示例”這篇文章的所有內容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內容對大家有所幫助,如果還想學習更多知識,歡迎關注丸趣 TV 行業資訊頻道!
向 AI 問一下細節