最新文章專題視頻專題問(wèn)答1問(wèn)答10問(wèn)答100問(wèn)答1000問(wèn)答2000關(guān)鍵字專題1關(guān)鍵字專題50關(guān)鍵字專題500關(guān)鍵字專題1500TAG最新視頻文章推薦1 推薦3 推薦5 推薦7 推薦9 推薦11 推薦13 推薦15 推薦17 推薦19 推薦21 推薦23 推薦25 推薦27 推薦29 推薦31 推薦33 推薦35 推薦37視頻文章20視頻文章30視頻文章40視頻文章50視頻文章60 視頻文章70視頻文章80視頻文章90視頻文章100視頻文章120視頻文章140 視頻2關(guān)鍵字專題關(guān)鍵字專題tag2tag3文章專題文章專題2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章專題3
問(wèn)答文章1 問(wèn)答文章501 問(wèn)答文章1001 問(wèn)答文章1501 問(wèn)答文章2001 問(wèn)答文章2501 問(wèn)答文章3001 問(wèn)答文章3501 問(wèn)答文章4001 問(wèn)答文章4501 問(wèn)答文章5001 問(wèn)答文章5501 問(wèn)答文章6001 問(wèn)答文章6501 問(wèn)答文章7001 問(wèn)答文章7501 問(wèn)答文章8001 問(wèn)答文章8501 問(wèn)答文章9001 問(wèn)答文章9501
當(dāng)前位置: 首頁(yè) - 科技 - 知識(shí)百科 - 正文

探索MySQL源代碼之SQL歷險(xiǎn)記

來(lái)源:懂視網(wǎng) 責(zé)編:小采 時(shí)間:2020-11-09 14:37:26
文檔

探索MySQL源代碼之SQL歷險(xiǎn)記

探索MySQL源代碼之SQL歷險(xiǎn)記:本文從一個(gè)select語(yǔ)句的執(zhí)行過(guò)程出發(fā),遍歷MySQL的多個(gè)幾子系統(tǒng)。 先放圖一張, 按圖索驥開(kāi)始我們的歷險(xiǎn). 當(dāng)客戶端連接上MySQL服務(wù)端之后,發(fā)出請(qǐng)求之前,服務(wù)端的線程是阻塞在do_command(sql/parse.cc)里的my_net_read函數(shù)中(就是socket里的r
推薦度:
導(dǎo)讀探索MySQL源代碼之SQL歷險(xiǎn)記:本文從一個(gè)select語(yǔ)句的執(zhí)行過(guò)程出發(fā),遍歷MySQL的多個(gè)幾子系統(tǒng)。 先放圖一張, 按圖索驥開(kāi)始我們的歷險(xiǎn). 當(dāng)客戶端連接上MySQL服務(wù)端之后,發(fā)出請(qǐng)求之前,服務(wù)端的線程是阻塞在do_command(sql/parse.cc)里的my_net_read函數(shù)中(就是socket里的r

本文從一個(gè)select語(yǔ)句的執(zhí)行過(guò)程出發(fā),遍歷MySQL的多個(gè)幾子系統(tǒng)。 先放圖一張, 按圖索驥開(kāi)始我們的歷險(xiǎn). 當(dāng)客戶端連接上MySQL服務(wù)端之后,發(fā)出請(qǐng)求之前,服務(wù)端的線程是阻塞在do_command(sql/parse.cc)里的my_net_read函數(shù)中(就是socket里的read). 當(dāng)客戶端鍵

本文從一個(gè)select語(yǔ)句的執(zhí)行過(guò)程出發(fā),遍歷MySQL的多個(gè)幾子系統(tǒng)。

先放圖一張, 按圖索驥開(kāi)始我們的歷險(xiǎn).

當(dāng)客戶端連接上MySQL服務(wù)端之后,發(fā)出請(qǐng)求之前,服務(wù)端的線程是阻塞在do_command(sql/parse.cc)里的my_net_read函數(shù)中(就是socket里的read).

當(dāng)客戶端鍵入sql語(yǔ)句(本文例子select * from zzz)發(fā)送到服務(wù)端之后, my_net_read返回, 并從tcpbuffer中讀取數(shù)據(jù)寫(xiě)入到packet這個(gè)字符串.

  1. packet_length= my_net_read(net);

packet的第一個(gè)字節(jié)是個(gè)標(biāo)志位, 決定數(shù)據(jù)包是查詢還是命令,成功,或者出錯(cuò)。

接下來(lái)就進(jìn)入dispatch_command(sql/sql/parse.cc)這個(gè)函數(shù), 數(shù)據(jù)類型不再需要.

  1. return_value= dispatch_command(command, thd, packet+1, (uint) (packet_length-1));

進(jìn)入dispatch_command, 我們可見(jiàn)

  1. statistic_increment(thd->status_var.questions, &LOCK_status);

這個(gè)就是show status questions的值累加.

接下的mysql_parse(sql/sql_parse.cc), 該函數(shù)是sql語(yǔ)句解析的總路口.

進(jìn)入該函數(shù)后首先碰到的是query_cache_send_result_to_client,故名思義這個(gè)函數(shù)是在QCache里查詢是否有相同的語(yǔ)句, 有則立即從QCache返回結(jié)果, 于是整個(gè)sql就結(jié)束了.

QCache里不存在的sql則繼續(xù)前進(jìn)來(lái)到parse_sql(sql/sql_parse.cc),這個(gè)函數(shù)主要就是調(diào)用了MYSQLparse. 而MYSQLparse其實(shí)就是bison/yacc里的yyparse(^_^),

  1. #define yyparse MYSQLparse

是的開(kāi)始解析sql了. 關(guān)于詞法分析和語(yǔ)法匹配簡(jiǎn)單說(shuō)幾下.

對(duì)于一條像select * from zzz的語(yǔ)句首先進(jìn)入詞法分析,找到2個(gè)token(select, from), 然后根據(jù)token進(jìn)行語(yǔ)法匹配, 規(guī)則在sql/yacc.yy里, 我把幾個(gè)匹配到的pattern和action貼出來(lái).

  1. select:
  2. select_init
  3. {
  4. LEX *lex= Lex;
  5. lex->sql_command= SQLCOM_SELECT;
  6. }
  7. ;
  8. /* Need select_init2 for subselects. */
  9. select_init:
  10. SELECT_SYM select_init2
  11. | '(' select_paren ')' union_opt
  12. ;
  13. select_paren:
  14. SELECT_SYM select_part2
  15. {
  16. LEX *lex= Lex;
  17. SELECT_LEX * sel= lex->current_select;
  18. .....
  19. select_from:
  20. FROM join_table_list where_clause group_clause having_clause
  21. opt_order_clause opt_limit_clause procedure_clause
  22. {
  23. Select->context.table_list=
  24. Select->context.first_name_resolution_table=
  25. (TABLE_LIST *) Select->table_list.first;
  26. }
  27. ....
  28. select_item_list:
  29. select_item_list ',' select_item
  30. | select_item
  31. | '*'
  32. {
  33. THD *thd= YYTHD;
  34. Item *item= new (thd->mem_root)
  35. Item_field(&thd->lex->current_select->context,
  36. NULL, NULL, "*");
  37. if (item == NULL)
  38. MYSQL_YYABORT;
  39. if (add_item_to_list(thd, item))
  40. MYSQL_YYABORT;
  41. (thd->lex->current_select->with_wild)++;
  42. }
  43. ;
  44. select_item:
  45. remember_name select_item2 remember_end select_alias
  46. {
  47. THD *thd= YYTHD;
  48. DBUG_ASSERT($1 < $3);
  49. if (add_item_to_list(thd, $2))
  50. MYSQL_YYABORT;
  51. if ($4.str)
  52. ...

可以看到action里最關(guān)鍵的就是add_item_to_list 和table_list的賦值.

解析后對(duì)于需要查詢的表(zzz)和字段(*)這些信息都寫(xiě)入到thd->lex這個(gè)結(jié)構(gòu)體里了.

例如其中thd->lex->query_tables就是表(zzz)的狀況, thd->lex->current_select->with_wild 是表示該語(yǔ)句是否使用了*等等.

  1. (gdb) p *thd->lex->query_tables
  2. $7 = {next_local = 0x0, next_global = 0x0, prev_global = 0x855a458, db = 0x85a16b8 "test", alias = 0x85a16e0 "zzz",
  3. table_name = 0x85a16c0 "zzz", schema_table_name = 0x0, option = 0x0, on_expr = 0x0, prep_on_expr = 0x0, cond_equal = 0x0,

sql解析完了, 優(yōu)化呢? 別急接著往下看.

接著進(jìn)入mysql_execute_command函數(shù),這個(gè)函數(shù)是所有sql命令的總?cè)肟?

由于是這個(gè)sql是一個(gè)select, 于是execute_sqlcom_select就是我們下個(gè)要執(zhí)行的函數(shù),又然后進(jìn)入了mysql_select(^_^怒了如此復(fù)雜).

mysql_select 就是優(yōu)化器的模塊, 這個(gè)模塊代碼比較復(fù)雜. 我們可以清楚看到創(chuàng)建優(yōu)化器,優(yōu)化,執(zhí)行的3個(gè)步驟, 優(yōu)化細(xì)節(jié)不表.

  1. if (!(join= new JOIN(thd, fields, select_options, result)))
  2. ...
  3. if ((err= join->optimize()))
  4. ...
  5. join->exec();

結(jié)束了優(yōu)化,我們要具體執(zhí)行join->exec(),該函數(shù)實(shí)際進(jìn)入的是JOIN::exec()(sql_select.cc)。

exec()首先向客戶端發(fā)送字段title的函數(shù)send_fields, 沒(méi)數(shù)據(jù)但字段也是要的。

然后再進(jìn)入do_select(),根據(jù)表的存儲(chǔ)引擎跳入到引擎具體的實(shí)現(xiàn)(zzz是myisam表)。

這里mi_scan就是myisam引擎掃描文件的函數(shù),再看到

  1. (gdb) p info->filename
  2. ./test/zzz

這不就是zzz表對(duì)應(yīng)的物理文件嗎。

通過(guò)一系列的mi函數(shù)訪問(wèn)磁盤(pán)拿到數(shù)據(jù)之后,會(huì)通過(guò)send_data發(fā)送數(shù)據(jù)給client,并從dispatch_command返回.最后在net_end_statement結(jié)束整個(gè)sql。

一個(gè)簡(jiǎn)單的select語(yǔ)句背后的執(zhí)行過(guò)程是非常復(fù)雜的,上面的步驟都只是點(diǎn)到就止。

ps: 在sql_yacc.yy可見(jiàn)MySQL對(duì)于Oracle中常用的dual表的嘲諷。

聲明:本網(wǎng)頁(yè)內(nèi)容旨在傳播知識(shí),若有侵權(quán)等問(wèn)題請(qǐng)及時(shí)與本網(wǎng)聯(lián)系,我們將在第一時(shí)間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com

文檔

探索MySQL源代碼之SQL歷險(xiǎn)記

探索MySQL源代碼之SQL歷險(xiǎn)記:本文從一個(gè)select語(yǔ)句的執(zhí)行過(guò)程出發(fā),遍歷MySQL的多個(gè)幾子系統(tǒng)。 先放圖一張, 按圖索驥開(kāi)始我們的歷險(xiǎn). 當(dāng)客戶端連接上MySQL服務(wù)端之后,發(fā)出請(qǐng)求之前,服務(wù)端的線程是阻塞在do_command(sql/parse.cc)里的my_net_read函數(shù)中(就是socket里的r
推薦度:
標(biāo)簽: 一個(gè) 代碼 sql
  • 熱門(mén)焦點(diǎn)

最新推薦

猜你喜歡

熱門(mén)推薦

專題
Top