自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

MySQL中Sp運(yùn)行Check表版本更新流程解析

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

一、MySQL的sp運(yùn)行sql語句兩個(gè)步驟介紹

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

先看下面的例子:
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; #這里第一次操作,因此會(huì)先執(zhí)行update這句SQL的prepare再進(jìn)行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; #這里第二次操作,直接執(zhí)行update這句SQL的execute。
Query OK, 0 rows affected (13.78 sec)

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

#然后再次執(zhí)行sp,就會(huì)發(fā)現(xiàn)這次執(zhí)行了這句SQL的prepare再進(jìn)行execute。
MySQL> call p1;
Query OK, 0 rows affected (34.24 sec)

二、代碼跟蹤

現(xiàn)在跟蹤一下這個(gè)sp看看上面在哪里check表版本并且能正確執(zhí)行reprepare的。

#首先看一下這個(gè)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)
可以看到這個(gè)sp只涉及了sp_instr_stmt::execute的運(yùn)行,因此跟蹤一下代碼找到sp_lex_instr::validate_lex_and_execute_core,可以發(fā)現(xiàn)這個(gè)函數(shù)里面有一個(gè)無限while循環(huán),如果發(fā)現(xiàn)is_invalid()的話就重新執(zhí)行parse動(dòng)作,如果!is_invalid()就直接執(zhí)行exec_core,這個(gè)跟上面的運(yùn)行步驟就對(duì)的上了。但是表結(jié)構(gòu)變更后在哪里被判定為rc=true的呢,那就從reset_lex_and_exec_core這個(gè)函數(shù)繼續(xù)跟蹤下去。
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();
}
}
#跟蹤代碼發(fā)現(xiàn)有一個(gè)check_and_update_table_version函數(shù)是用來check表版本是否一致的
#打印堆??匆幌麓a調(diào)用過程:
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
#可以發(fā)現(xiàn)open_tables函數(shù)調(diào)用了這個(gè)函數(shù),這個(gè)函數(shù)調(diào)用了ask_to_reprepare,
#在sp運(yùn)行中這個(gè)ask_to_reprepare返回的是true。因此這里就解開了之前的問題,
#為何表版本更新了會(huì)return true然后重新進(jìn)行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;
}

三、知識(shí)應(yīng)用

如果想開發(fā)一種動(dòng)態(tài)表類型,需要每次執(zhí)行sp都重新parse這個(gè)表,那就可以借用這個(gè)ask_to_reprepare函數(shù)來保證多次執(zhí)行sp的時(shí)候都會(huì)進(jìn)行重新reprepare。

四、總結(jié)

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

責(zé)任編輯:武曉燕 來源: GreatSQL社區(qū)
相關(guān)推薦

2024-05-08 08:56:09

GreatSQL內(nèi)存宏定義

2010-05-20 09:42:48

安裝IIS

2010-11-23 11:36:15

MySQL創(chuàng)建關(guān)聯(lián)表

2015-10-20 09:25:41

數(shù)據(jù)庫mysql

2023-07-05 08:21:24

MySQL函數(shù)sp

2020-09-09 09:48:28

C++語言Rust

2010-11-23 15:50:44

MySQL中文建表

2010-09-03 10:21:35

SQL刪除

2010-05-21 14:56:53

MySQL聯(lián)表查詢優(yōu)化

2011-04-12 14:48:38

MySQL數(shù)據(jù)庫

2011-06-28 09:48:14

Office 2010

2010-05-12 18:02:11

MySQL數(shù)據(jù)庫

2010-06-28 16:12:43

ARP協(xié)議

2021-04-19 07:57:23

Spring 源碼GetBean

2018-09-21 16:13:01

數(shù)據(jù)庫MySQLSQL

2021-11-04 17:50:01

云原生安全

2012-07-17 08:44:26

MySQL

2010-03-23 08:40:33

Windows 7 S系統(tǒng)發(fā)布

2010-05-21 18:07:56

MySQL 表種類

2010-08-04 13:23:29

Flex事件
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)