成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

MySQL中Sp運行Check表版本更新流程解析

數據庫 MySQL
在MySQL的sp操作中涉及表操作的sql語句一定會執行check_and_update_table_version這個函數,每次會根據這個函數的結果來確定要不要重新parse該sql語句,如果沒有版本改變就直接進行execute操作,如果有改變就重新parse,先prepare再execute,這樣可以保證每次執行sp的SQL語句的時候表結構一定是最新的。

一、MySQL的sp運行sql語句兩個步驟介紹

MySQL的sp運行SQL語句需要執行2個步驟:prepare和execute。第一次執行的時候先執行prepare,進行相關語句parse、itemize、fix_fields等操作,然后才開始進行execute操作。等第二次再執行該sp的時候就直接運行execute而不需要再次進行重復的prepare操作,這樣可以節省sp運行時候重復prepare的開銷。但是,對于表操作就有一個問題產生,那就是如果執行第二遍的時候表的結構發生改變了,那么不進行reprepare而直接execute是會發生錯誤的。因此,本文章的目的在于尋找sp多次運行時候如何確認表版本更新并進行正確的操作。

先看下面的例子:
CREATE TABLE t1 (a INT, b VARCHAR(10));
INSERT INTO t1 VALUES (1,'11');
INSERT INTO t1 VALUES (2,'21');
MySQL> select * from t1;
+------+------+
| a | b |
+------+------+
| 1 | 11 |
| 2 | 21 |
+------+------+
2 rows in set (0.01 sec)
DELIMITER $$
CREATE PROCEDURE p1()
BEGIN
update t1 set b='aa' where a=1;
END $$
DELIMITER ;
MySQL> call p1; #這里第一次操作,因此會先執行update這句SQL的prepare再進行execute。
Query OK, 1 row affected (0.05 sec)

MySQL> select * from t1;
+------+------+
| a | b |
+------+------+
| 1 | aa |
| 2 | 21 |
+------+------+
2 rows in set (0.01 sec)
MySQL> call p1; #這里第二次操作,直接執行update這句SQL的execute。
Query OK, 0 rows affected (13.78 sec)

#接著我們執行表結構的更新。
MySQL> alter table t1 add i int;
Query OK, 0 rows affected (0.41 sec)
Records: 0 Duplicates: 0 Warnings: 0

#然后再次執行sp,就會發現這次執行了這句SQL的prepare再進行execute。
MySQL> call p1;
Query OK, 0 rows affected (34.24 sec)

二、代碼跟蹤

現在跟蹤一下這個sp看看上面在哪里check表版本并且能正確執行reprepare的。

#首先看一下這個sp涉及的instr。
MySQL> show procedure code p1;
+-----+---------------------------------------+
| Pos | Instruction |
+-----+---------------------------------------+
| 0 | stmt "update t1 set b='aa' where a=1" |
+-----+---------------------------------------+
1 row in set (0.01 sec)
可以看到這個sp只涉及了sp_instr_stmt::execute的運行,因此跟蹤一下代碼找到sp_lex_instr::validate_lex_and_execute_core,可以發現這個函數里面有一個無限while循環,如果發現is_invalid()的話就重新執行parse動作,如果!is_invalid()就直接執行exec_core,這個跟上面的運行步驟就對的上了。但是表結構變更后在哪里被判定為rc=true的呢,那就從reset_lex_and_exec_core這個函數繼續跟蹤下去。
bool sp_lex_instr::validate_lex_and_execute_core(THD *thd, uint *nextp,
bool open_tables) {
while (true) {
if (is_invalid() || (m_lex->has_udf() && !m_first_execution)) {
LEX *lex = parse_expr(thd, thd->sp_runtime_ctx->sp);
}
bool rc = reset_lex_and_exec_core(thd, nextp, open_tables);
if (!rc) return false;
thd->clear_error();
invalidate();
}
}
#跟蹤代碼發現有一個check_and_update_table_version函數是用來check表版本是否一致的
#打印堆棧看一下代碼調用過程:
Thread 51 "mysqld" hit Breakpoint 6, check_and_update_table_version (thd=0x7fff70001060, tables=0x7fff702c4e20,
table_share=0x7fff70297640) at /mysql/sql/sql_base.cc:3722
3722 if (!tables->is_table_ref_id_equal(table_share)) {
(gdb) bt
#0 check_and_update_table_version (thd=0x7fff70001060, tables=0x7fff702c4e20, table_share=0x7fff70297640)
at /mysql/sql/sql_base.cc:3722
#1 0x0000000003340f71 in open_and_process_table (thd=0x7fff70001060, lex=0x7fff702c2650, tables=0x7fff702c4e20,
counter=0x7fff702c26a8, prelocking_strategy=0x7fffec2e7478, has_prelocking_list=false, ot_ctx=0x7fffec2e7368)
at /MySQL/sql/sql_base.cc:5223
#2 0x000000000333f788 in open_tables (thd=0x7fff70001060, start=0x7fffec2e7488, counter=0x7fff702c26a8, flags=0,
prelocking_strategy=0x7fffec2e7478) at /mysql/sql/sql_base.cc:5968
#3 0x0000000003343c96 in open_tables_for_query (thd=0x7fff70001060, tables=0x7fff702c4e20, flags=0)
at /MySQL/sql/sql_base.cc:6958
#4 0x0000000003514334 in Sql_cmd_dml::execute (this=0x7fff702c6138, thd=0x7fff70001060)
at /MySQL/sql/sql_select.cc:543
#5 0x0000000003475097 in mysql_execute_command (thd=0x7fff70001060, first_level=false)
at /MySQL/sql/sql_parse.cc:3832
#6 0x00000000033075c6 in sp_instr_stmt::exec_core (this=0x7fff70249a80, thd=0x7fff70001060, nextp=0x7fffec2eac38)
at /MySQL/sql/sp_instr.cc:1008
#7 0x00000000033052ed in sp_lex_instr::reset_lex_and_exec_core (this=0x7fff70249a80, thd=0x7fff70001060,
nextp=0x7fffec2eac38, open_tables=false) at /mysql/sql/sp_instr.cc:457
#8 0x00000000033060a4 in sp_lex_instr::validate_lex_and_execute_core (this=0x7fff70249a80, thd=0x7fff70001060,
nextp=0x7fffec2eac38, open_tables=false) at /mysql/sql/sp_instr.cc:741
#9 0x0000000003306748 in sp_instr_stmt::execute (this=0x7fff70249a80, thd=0x7fff70001060, nextp=0x7fffec2eac38)
at /MySQL/sql/sp_instr.cc:925
#10 0x00000000032f4d74 in sp_head::execute (this=0x7fff7018e7a0, thd=0x7fff70001060, merge_da_on_success=true)
at /MySQL/sql/sp_head.cc:2272
#11 0x00000000032f80e1 in sp_head::execute_procedure (this=0x7fff7018e7a0, thd=0x7fff70001060, args=0x0)
at /MySQL/sql/sp_head.cc:2977
#可以發現open_tables函數調用了這個函數,這個函數調用了ask_to_reprepare,
#在sp運行中這個ask_to_reprepare返回的是true。因此這里就解開了之前的問題,
#為何表版本更新了會return true然后重新進行parse操作。
static bool check_and_update_table_version(THD *thd, TABLE_LIST *tables,
TABLE_SHARE *table_share) {
if (!tables->is_table_ref_id_equal(table_share)) {
/*
Version of the table share is different from the
previous execution of the prepared statement, and it is
unacceptable for this SQLCOM.
*/
if (ask_to_reprepare(thd)) return true;
/* Always maintain the latest version and type */
tables->set_table_ref_id(table_share);
}
return false;
}

三、知識應用

如果想開發一種動態表類型,需要每次執行sp都重新parse這個表,那就可以借用這個ask_to_reprepare函數來保證多次執行sp的時候都會進行重新reprepare。

四、總結

在MySQL的sp操作中涉及表操作的sql語句一定會執行check_and_update_table_version這個函數,每次會根據這個函數的結果來確定要不要重新parse該sql語句,如果沒有版本改變就直接進行execute操作,如果有改變就重新parse,先prepare再execute,這樣可以保證每次執行sp的SQL語句的時候表結構一定是最新的。

責任編輯:武曉燕 來源: GreatSQL社區
相關推薦

2024-05-08 08:56:09

GreatSQL內存宏定義

2010-05-20 09:42:48

安裝IIS

2015-10-20 09:25:41

數據庫mysql

2023-07-05 08:21:24

MySQL函數sp

2010-11-23 11:36:15

MySQL創建關聯表

2020-09-09 09:48:28

C++語言Rust

2010-09-03 10:21:35

SQL刪除

2010-11-23 15:50:44

MySQL中文建表

2011-06-28 09:48:14

Office 2010

2021-04-19 07:57:23

Spring 源碼GetBean

2010-06-28 16:12:43

ARP協議

2011-04-12 14:48:38

MySQL數據庫

2010-05-12 18:02:11

MySQL數據庫

2021-11-04 17:50:01

云原生安全

2010-05-21 14:56:53

MySQL聯表查詢優化

2010-03-23 08:40:33

Windows 7 S系統發布

2012-07-17 08:44:26

MySQL

2018-09-21 16:13:01

數據庫MySQLSQL

2010-08-04 13:23:29

Flex事件

2024-03-28 18:17:49

PMSAndroid
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 国产伦精品一区二区三区高清 | 欧美在线视频二区 | 欧美一区二区三区在线观看视频 | 动漫www.被爆羞羞av44 | m豆传媒在线链接观看 | 亚洲视频欧美视频 | 伊人精品一区二区三区 | 午夜视频网站 | se婷婷| 亚洲人在线观看视频 | 亚洲不卡在线观看 | 91av在线免费观看 | ririsao久久精品一区 | 视频精品一区二区三区 | 狠狠躁躁夜夜躁波多野结依 | 伊人在线 | 午夜影视 | 日韩av第一页 | 97色综合 | 91精品国产91久久久 | 中文字幕乱码一区二区三区 | 女同久久另类99精品国产 | 中文字幕一区二区三区乱码图片 | 亚洲情综合五月天 | 九九99九九精彩46 | 日韩福利电影 | 欧美精品久久久久 | 国产91在线 | 中日 | 亚洲国产一区二区视频 | 91亚洲精品国偷拍自产在线观看 | 国产一区二区三区久久久久久久久 | 欧美一级小视频 | 91 久久| 在线免费毛片 | 国产成人高清 | 精品视频免费 | 亚洲高清三级 | 国产日韩视频 | 欧美色人| 亚洲精品观看 | 日韩国产欧美在线观看 |