MySQL中普通sql與預編譯sql 區別
MySQL中的預編譯提到的不多,oracle上一次編譯多次執行,是有很大的效能提升的,這裡看下mysql為什麼沒有那麼大的提升,以及跟普通sql相比有哪些區別。
執行緒在初始化建立的時候,會使用init_sql_alloc分配main_mem_root部分,main_mem_root也是mem_root, 在sql執行時候使用。
執行普通的sql,在轉發sql後,回進行記憶體的分配,分配到mem_root中,會先在free列表中查詢是否有足夠的空間,沒有就分配,有就返回分配的地址。呼叫堆疊如下:
mysqld!alloc_root (/Users/xiaoyu.bai/Downloads/mysql-5.7.29/mysys/my_alloc.c:274) mysqld!Query_arena::alloc(unsigned long) (/Users/xiaoyu.bai/Downloads/mysql-5.7.29/sql/sql_class.h:783) mysqld!alloc_query(THD*, char const*, unsigned long) (/Users/xiaoyu.bai/Downloads/mysql-5.7.29/sql/sql_parse.cc:2158) mysqld!dispatch_command(THD*, COM_DATA const*, enum_server_command) (/Users/xiaoyu.bai/Downloads/mysql-5.7.29/sql/sql_parse.cc:1467) mysqld!do_command(THD*) (/Users/xiaoyu.bai/Downloads/mysql-5.7.29/sql/sql_parse.cc:1032) mysqld!::handle_connection(void *) (/Users/xiaoyu.bai/Downloads/mysql-5.7.29/sql/conn_handler/connection_handler_per_thread.cc:313) mysqld!::pfs_spawn_thread(void *) (/Users/xiaoyu.bai/Downloads/mysql-5.7.29/storage/perfschema/pfs.cc:2197) libsystem_pthread.dylib!_pthread_start (未知源:0) libsystem_pthread.dylib!thread_start (未知源:0)
在普通sql執行完成後,會呼叫free_root 進行mem_root記憶體的釋放
mysqld!free_root (/Users/xiaoyu.bai/Downloads/mysql-5.7.29/mysys/my_alloc.c:487) mysqld!dispatch_command(THD*, COM_DATA const*, enum_server_command) (/Users/xiaoyu.bai/Downloads/mysql-5.7.29/sql/sql_parse.cc:1947) mysqld!do_command(THD*) (/Users/xiaoyu.bai/Downloads/mysql-5.7.29/sql/sql_parse.cc:1032) mysqld!::handle_connection(void *) (/Users/xiaoyu.bai/Downloads/mysql-5.7.29/sql/conn_handler/connection_handler_per_thread.cc:313) mysqld!::pfs_spawn_thread(void *) (/Users/xiaoyu.bai/Downloads/mysql-5.7.29/storage/perfschema/pfs.cc:2197) libsystem_pthread.dylib!_pthread_start (未知源:0) libsystem_pthread.dylib!thread_start (未知源:0)
預編譯sql執行
1 SET @s = 'SELECT * from products where code=?'; 2 PREPARE stmt2 FROM @s; 3 SET @a = 200; 4 EXECUTE stmt2 USING @a;
執行1的時候是跟普通sql一樣的使用mem_root,釋放mem_root
在執行第二步的時候也會線上程上使用記憶體,進行語法解析,驗證語句,執行緒中儲存了stmt_map物件,這個字典用來存放預編譯的語句
mysqld!alloc_query(THD*, char const*, unsigned long) (/Users/xiaoyu.bai/Downloads/mysql-5.7.29/sql/sql_parse.cc:2158) mysqld!Prepared_statement::prepare(char const*, unsigned long) (/Users/xiaoyu.bai/Downloads/mysql-5.7.29/sql/sql_prepare.cc:3247) mysqld!mysql_sql_stmt_prepare(THD*) (/Users/xiaoyu.bai/Downloads/mysql-5.7.29/sql/sql_prepare.cc:2323) mysqld!mysql_execute_command(THD*, bool) (/Users/xiaoyu.bai/Downloads/mysql-5.7.29/sql/sql_parse.cc:2837) mysqld!mysql_parse(THD*, Parser_state*) (/Users/xiaoyu.bai/Downloads/mysql-5.7.29/sql/sql_parse.cc:5584) mysqld!dispatch_command(THD*, COM_DATA const*, enum_server_command) (/Users/xiaoyu.bai/Downloads/mysql-5.7.29/sql/sql_parse.cc:1491) mysqld!do_command(THD*) (/Users/xiaoyu.bai/Downloads/mysql-5.7.29/sql/sql_parse.cc:1032) mysqld!::handle_connection(void *) (/Users/xiaoyu.bai/Downloads/mysql-5.7.29/sql/conn_handler/connection_handler_per_thread.cc:313) mysqld!::pfs_spawn_thread(void *) (/Users/xiaoyu.bai/Downloads/mysql-5.7.29/storage/perfschema/pfs.cc:2197) libsystem_pthread.dylib!_pthread_start (未知源:0) libsystem_pthread.dylib!thread_start (未知源:0)
在這裡呼叫lex_start進行了一次解析。
所以如果預編譯語句有很多的話,這個map會比較大,引數max_prepared_stmt_count是限制的全域性的數量
if (thd->stmt_map.insert(thd, stmt))
執行第四步的時候,是真正的執行,堆疊
mysqld!mysql_sql_stmt_execute(THD*) (/Users/xiaoyu.bai/Downloads/mysql-5.7.29/sql/sql_prepare.cc:2640) mysqld!mysql_execute_command(THD*, bool) (/Users/xiaoyu.bai/Downloads/mysql-5.7.29/sql/sql_parse.cc:2842) mysqld!mysql_parse(THD*, Parser_state*) (/Users/xiaoyu.bai/Downloads/mysql-5.7.29/sql/sql_parse.cc:5584) mysqld!dispatch_command(THD*, COM_DATA const*, enum_server_command) (/Users/xiaoyu.bai/Downloads/mysql-5.7.29/sql/sql_parse.cc:1491) mysqld!do_command(THD*) (/Users/xiaoyu.bai/Downloads/mysql-5.7.29/sql/sql_parse.cc:1032) mysqld!::handle_connection(void *) (/Users/xiaoyu.bai/Downloads/mysql-5.7.29/sql/conn_handler/connection_handler_per_thread.cc:313) mysqld!::pfs_spawn_thread(void *) (/Users/xiaoyu.bai/Downloads/mysql-5.7.29/storage/perfschema/pfs.cc:2197) libsystem_pthread.dylib!_pthread_start (未知源:0) libsystem_pthread.dylib!thread_start (未知源:0)
執行完後,也會呼叫 free_root進行釋放。
所以預編譯跟普通sql執行,多了儲存預編譯語句的map物件,預編譯多了一次賦值的解析與執行。
問題1: 一次編譯,多次執行,編譯的結果放到哪裡了?
mysql的跟oracle不太一樣,mysql的是每次輸入引數,會給sql設定下對應的值,然後走一遍普通的mysql_execute_command的流程。stmt_map針對效能提升這沒有什麼用途,就是用來儲存語句的。
所以這裡來看,mysql 使用預編譯語句對效能的影響不如oracle那麼大,只是在防止注入的安全上有用。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/25719946/viewspace-2947595/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- MYSQL和SQL的區別MySql
- SQL JOIN 中 on 與 where 有何區別SQL
- 預編譯SQL為什麼能夠防止SQL隱碼攻擊編譯SQL
- SQL中where和on的區別SQL
- sql server中的一個坑-len與datalength區別SQLServer
- [精選] SQL中的IN與NOT IN、EXISTS與NOT EXISTS的區別及效能分析SQL
- sql中UNION和UNION ALL的區別SQL
- Oracle9i中v$sql、v$sqlarea、v$sqltext、v$sql_plan的聯絡與區別OracleSQL
- 【SQL】Oracle SQL join on語句and和where使用區別SQLOracle
- SQL Server中count(*)和Count(1)的區別SQLServer
- MySQL5.7中的sql_mode預設值MySql
- 在Pandas中 SQL操作:SQLAlchemy和PyMySQL的區別MySql
- SQL中 where 子句和having子句中的區別SQL
- sql:left join和join區別SQL
- sql語句中#{}和${}的區別SQL
- GraphJin:GraphQL自動編譯轉為SQL編譯SQL
- 精讀《手寫SQL編譯器-回溯》SQL編譯
- 對線面試官:SQL中的IN與NOT IN、EXISTS與NOT EXISTS的區別及效能分析面試SQL
- SQL語句case when外用sum與count的區別SQL
- [Mysql]SQLMySql
- SQL Server新老版本CE區別SQLServer
- SQL語句中exists和in的區別SQL
- SQL語句中not in 和not exist的區別SQL
- v$sql,v$sqlarea,v$sqltext區別SQL
- launchbadge/sqlx: Rust SQL工具包讓SQL在編譯時驗證檢查SQLRust編譯
- mysql中SQL的概念介紹MySql
- sql devloper 用法的和SQL 編寫SQLdev
- sql學習(mysql)(1)資料型別MySql資料型別
- CAD的ShowDialog與普通ShowDialog的區別
- 工控機與普通電腦的區別
- mysql 常用sqlMySql
- MySQL SQL模式MySql模式
- MySQL 資料庫與 SQL 優化MySql資料庫優化
- Hive SQL的底層編譯過程詳解HiveSQL編譯
- 精讀《手寫 SQL 編譯器 – 詞法分析》SQL編譯詞法分析
- 精讀《手寫 SQL 編譯器 - 詞法分析》SQL編譯詞法分析
- 精讀《手寫 SQL 編譯器 - 語法樹》SQL編譯
- 精讀《手寫 SQL 編譯器 - 文法介紹》SQL編譯