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

數(shù)據(jù)庫(kù)管理提速:SQL解析的探索與應(yīng)用

運(yùn)維 數(shù)據(jù)庫(kù)運(yùn)維 MySQL
SQL解析是一項(xiàng)復(fù)雜的技術(shù),一般都是由數(shù)據(jù)庫(kù)廠商來(lái)掌握,當(dāng)然也有公司專門提供SQL解析的API。SQL解析與優(yōu)化是屬于編譯器范疇,和C語(yǔ)言等其他語(yǔ)言的解析沒有本質(zhì)的區(qū)別。其中分為詞法分析、語(yǔ)法和語(yǔ)義分析、優(yōu)化、執(zhí)行代碼生成。

作者介紹

數(shù)據(jù)庫(kù)作為核心的基礎(chǔ)組件,是需要重點(diǎn)保護(hù)的對(duì)象。任何一個(gè)線上的不慎操作,都有可能給數(shù)據(jù)庫(kù)帶來(lái)嚴(yán)重的故障,從而給業(yè)務(wù)造成巨大的損失。

為了避免這種損失,一般會(huì)在管理上下功夫,比如為研發(fā)人員制定數(shù)據(jù)庫(kù)開發(fā)規(guī)范;新上線的SQL,需要DBA進(jìn)行審核;維護(hù)操作需要經(jīng)過領(lǐng)導(dǎo)審批等等。而且如果希望能夠有效地管理這些措施,需要有效的數(shù)據(jù)庫(kù)培訓(xùn),還需要DBA細(xì)心的進(jìn)行SQL審核。很多中小型創(chuàng)業(yè)公司可以通過設(shè)定規(guī)范、進(jìn)行培訓(xùn)、完善審核流程來(lái)管理數(shù)據(jù)庫(kù)。

隨著美團(tuán)點(diǎn)評(píng)的業(yè)務(wù)不斷發(fā)展和壯大,上述措施的實(shí)施成本越來(lái)越高。如何更多的依賴技術(shù)手段,來(lái)提高效率,越來(lái)越受到重視。業(yè)界已有不少基于MySQL源碼開發(fā)的SQL審核、優(yōu)化建議等工具,極大的減輕了DBA的SQL審核負(fù)擔(dān)。那么我們能否繼續(xù)擴(kuò)展MySQL的源碼,來(lái)輔助DBA和研發(fā)人員來(lái)進(jìn)一步提高效率呢?比如,更全面的SQL優(yōu)化功能;多維度的慢查詢分析;輔助故障分析等。要實(shí)現(xiàn)上述功能,其中最核心的技術(shù)之一就是SQL解析。

現(xiàn)狀與場(chǎng)景

SQL解析是一項(xiàng)復(fù)雜的技術(shù),一般都是由數(shù)據(jù)庫(kù)廠商來(lái)掌握,當(dāng)然也有公司專門提供SQL解析的API(參考鏈接:http://sqlparser.com/)。

由于這幾年MySQL數(shù)據(jù)庫(kù)中間件的興起,需要支持讀寫分離、分庫(kù)分表等功能,就必須從SQL中抽出表名、庫(kù)名以及相關(guān)字段的值。因此像Java語(yǔ)言編寫的Druid,C語(yǔ)言編寫的MaxScale,Go語(yǔ)言編寫的Kingshard等,都會(huì)對(duì)SQL進(jìn)行部分解析。而真正把SQL解析技術(shù)用于數(shù)據(jù)庫(kù)維護(hù)的產(chǎn)品較少,主要有如下幾個(gè):

  • 美團(tuán)點(diǎn)評(píng)開源的SQLAdvisor。它基于MySQL原生態(tài)詞法解析,結(jié)合分析SQL中的where條件、聚合條件、多表Join關(guān)系給出索引優(yōu)化建議。

    參考鏈接:https://github.com/Meituan-Dianping/SQLAdvisor

  • 去哪兒開源的Inception。側(cè)重于根據(jù)內(nèi)置的規(guī)則,對(duì)SQL進(jìn)行審核。

    參考鏈接:http://mysql-inception.github.io/inception-document

  • 阿里的Cloud DBA。根據(jù)官方文檔介紹,其也是提供SQL優(yōu)化建議和改寫。

    參考鏈接:https://yq.aliyun.com/articles/218442

上述產(chǎn)品都有非常合適的應(yīng)用場(chǎng)景,在業(yè)界也被廣泛使用。但是SQL解析的應(yīng)用場(chǎng)景遠(yuǎn)遠(yuǎn)沒有被充分發(fā)掘,比如:

  • 基于表粒度的慢查詢報(bào)表。比如,一個(gè)Schema中包含了屬于不同業(yè)務(wù)線的數(shù)據(jù)表,那么從業(yè)務(wù)線的角度來(lái)說,其希望提供表粒度的慢查詢報(bào)表。

  • 生成SQL特征。將SQL語(yǔ)句中的值替換成問號(hào),方便SQL歸類。雖然可以使用正則表達(dá)式實(shí)現(xiàn)相同的功能,但是其Bug較多,可以參考pt-query-digest。比如pt-query-digest中,會(huì)把遇到的數(shù)字都替換成“?”,導(dǎo)致無(wú)法區(qū)別不同數(shù)字后綴的表。

  • 高危操作確認(rèn)與規(guī)避。比如,DBA不小心Drop數(shù)據(jù)表,而此類操作,目前還無(wú)有效的工具進(jìn)行回滾,尤其是大表,其后果將是災(zāi)難性的。

  • SQL合法性判斷。為了安全、審計(jì)、控制等方面的原因,美團(tuán)點(diǎn)評(píng)不會(huì)讓研發(fā)人員直接操作數(shù)據(jù)庫(kù),而是提供RDS服務(wù)。尤其是對(duì)于數(shù)據(jù)變更,需要研發(fā)人員的上級(jí)主管進(jìn)行業(yè)務(wù)上的審批。如果研發(fā)人員,寫了一條語(yǔ)法錯(cuò)誤的SQL,而RDS無(wú)法判斷該SQL是否合法,就會(huì)造成不必要的溝通成本。

因此為了讓所有有需要的業(yè)務(wù)都能方便地使用SQL解析功能,我們認(rèn)為應(yīng)該具有如下特性:

  • 直接暴露SQL解析接口,使用盡量簡(jiǎn)單。比如:輸入SQL,則輸出表名、特征和優(yōu)化建議。

  • 接口的使用不依賴于特定的語(yǔ)言,否則維護(hù)和使用的代價(jià)太高。比如:以HTTP等方式提供服務(wù)。

千里之行,始于足下,下面我先介紹下SQL的解析原理。

原理

SQL解析與優(yōu)化是屬于編譯器范疇,和C語(yǔ)言等其他語(yǔ)言的解析沒有本質(zhì)的區(qū)別。其中分為詞法分析、語(yǔ)法和語(yǔ)義分析、優(yōu)化、執(zhí)行代碼生成。對(duì)應(yīng)到MySQL的部分,如下圖:

數(shù)據(jù)庫(kù)管理提速:SQL解析的探索與應(yīng)用

SQL解析原理

1、詞法分析

SQL解析由詞法分析和語(yǔ)法/語(yǔ)義分析兩個(gè)部分組成。詞法分析主要是把輸入轉(zhuǎn)化成一個(gè)個(gè)Token。其中Token中包含Keyword(也稱symbol)和非Keyword。例如:SQL語(yǔ)句select username from userinfo,在分析之后,會(huì)得到4個(gè)Token,其中有2個(gè)Keyword,分別為select和from:

數(shù)據(jù)庫(kù)管理提速:SQL解析的探索與應(yīng)用

通常情況下,詞法分析可以使用Flex來(lái)生成。

參考鏈接:https://www.gnu.org/software/flex

但是MySQL并未使用該工具,而是手寫了詞法分析部分(據(jù)說是為了效率和靈活性,可參考:https://yq.aliyun.com/articles/71979)。具體代碼在sql/lex.h和sql/sql_lex.cc文件中。

MySQL中的Keyword定義在sql/lex.h中,如下為部分Keyword:

 

  1. "&&", SYM(AND_AND_SYM)},  
  2. "<", SYM(LT)},  
  3. "<=", SYM(LE)},  
  4. "<>", SYM(NE)},  
  5. "!=", SYM(NE)},  
  6. "=", SYM(EQ)},  
  7. ">", SYM(GT_SYM)},  
  8. ">=", SYM(GE)},  
  9. "<<", SYM(SHIFT_LEFT)},  
  10. ">>", SYM(SHIFT_RIGHT)},  
  11. "<=>", SYM(EQUAL_SYM)},  
  12. "ACCESSIBLE", SYM(ACCESSIBLE_SYM)},  
  13. "ACTION", SYM(ACTION)},  
  14. "ADD", SYM(ADD)},  
  15. "AFTER", SYM(AFTER_SYM)},  
  16. "AGAINST", SYM(AGAINST)},  
  17. "AGGREGATE", SYM(AGGREGATE_SYM)},  
  18. "ALL", SYM(ALL)}, 

 

詞法分析的核心代碼在sql/sql_lex.c文件中的MySQLLex→lex_one_Token,有興趣的同學(xué)可以下載源碼研究。

2、語(yǔ)法分析

語(yǔ)法分析就是生成語(yǔ)法樹的過程。這是整個(gè)解析過程中最精華、最復(fù)雜的部分,不過這部分MySQL使用了Bison來(lái)完成。即使如此,如何設(shè)計(jì)合適的數(shù)據(jù)結(jié)構(gòu)以及相關(guān)算法,去存儲(chǔ)和遍歷所有的信息,也是值得在這里研究的。

語(yǔ)法分析樹

SQL語(yǔ)句:

 

  1. select username, ismale from userinfo where age > 20 and level > 5 and 1 = 1 

會(huì)生成如下語(yǔ)法樹:

數(shù)據(jù)庫(kù)管理提速:SQL解析的探索與應(yīng)用

語(yǔ)法樹

對(duì)于未接觸過編譯器實(shí)現(xiàn)的同學(xué),肯定會(huì)好奇如何才能生成這樣的語(yǔ)法樹,不過其背后的原理都是編譯器的范疇,大家可以參考維基百科的一篇文章,以及該鏈接中的參考書籍。本人也是在學(xué)習(xí)MySQL源碼過程中,閱讀了部分內(nèi)容。

參考鏈接:https://en.wikipedia.org/wiki/LR_parser

由于編譯器涉及的內(nèi)容過多,本人經(jīng)歷和時(shí)間有限,不做過多探究。從工程的角度來(lái)說,學(xué)會(huì)如何使用Bison去構(gòu)建語(yǔ)法樹,來(lái)解決實(shí)際問題,對(duì)我們的工作也許有更大幫助。下面我就以Bison為基礎(chǔ),探討該過程。

MySQL語(yǔ)法分析樹生成過程

全部的源碼在sql/sql_yacc.yy中,在MySQL5.6中有17K行左右代碼。這里列出涉及到SQL:

 

  1. select username, ismale from userinfo where age > 20 and level > 5 and 1 = 1 

解析過程的部分代碼摘錄出來(lái)。其實(shí)有了Bison之后,SQL解析的難度也沒有想象的那么大。特別是這里給出了解析的脈絡(luò)之后。

代碼示下:

 

  1. select /*select語(yǔ)句入口*/:  
  2. select_init  
  3.  
  4. LEX *lex= Lex;  
  5. lex->sql_command= SQLCOM_SELECT;  
  6.  
  7.  
  8. select_init:  
  9. SELECT_SYM /*select 關(guān)鍵字*/ select_init2  
  10. '(' select_paren ')' union_opt  
  11.  
  12. select_init2:  
  13. select_part2  
  14. SELECT_LEX * sel= lex->current_select;  
  15. if (lex->current_select->set_braces(0))  
  16.  
  17. my_parse_error(ER(ER_SYNTAX_ERROR));  
  18. MYSQL_YYABORT; 
  19.  
  20. if (sel->linkage == UNION_TYPE &&  
  21. sel->master_unit->first_select->braces)  
  22. union_clause  
  23.  
  24. select_part2:  
  25. SELECT_LEX *sel= lex->current_select;  
  26. if (sel->linkage != UNION_TYPE)  
  27. mysql_init_select(lex);  
  28. lex->current_select->parsing_place= SELECT_LIST;  
  29.  
  30. select_options select_item_list /*解析列名*/  
  31.  
  32. Select->parsing_place= NO_MATTER;  
  33.  
  34. select_into select_lock_type  
  35.  
  36. select_into:  
  37. opt_order_clause opt_limit_clause {}  
  38. into  
  39. | select_from /*from 字句*/  
  40. into select_from  
  41. | select_from into  
  42.  
  43. select_from:  
  44. FROM join_table_list /*解析表名*/ where_clause /*where字句*/ group_clause having_clause  
  45. opt_order_clause opt_limit_clause procedure_analyse_clause  
  46.  
  47. Select->context.table_list=  
  48. Select->context.first_name_resolution_table=  
  49. Select->table_list.first 
  50.  
  51. FROM DUAL_SYM where_clause opt_limit_clause  
  52. /* oracle compatibility: oracle always requires FROM clause,  
  53. and DUAL is system table without fields.  
  54. Is "SELECT 1 FROM DUAL" any better than "SELECT 1" ?  
  55. Hmmm :) */  
  56. where_clause:  
  57. /* empty */ { Select->where= 0; }  
  58. WHERE  
  59.  
  60. Select->parsing_place= IN_WHERE;  
  61.  
  62. expr /*各種表達(dá)式*/  
  63.  
  64. SELECT_LEX *selectSelect 
  65. select->where= $3;  
  66. select->parsing_place= NO_MATTER;  
  67. if ($3)  
  68. $3->top_level_item;  
  69. /* all possible expressions */  
  70. expr:  
  71. | expr and expr %prec AND_SYM  
  72.  
  73. /* See comments in rule expr: expr or expr */  
  74. Item_cond_and *item1;  
  75. Item_cond_and *item3;  
  76. if (is_cond_and($1))  
  77.  
  78. item1= (Item_cond_and*) $1;  
  79. if (is_cond_and($3))  
  80. item3= (Item_cond_and*) $3;  
  81. /*  
  82. (X1 AND X2) AND (Y1 AND Y2) ==> AND (X1, X2, Y1, Y2)  
  83. */  
  84. item3->add_at_head(item1->argument_list);  
  85. $$ = $3;  
  86.  
  87. else  
  88. (X1 AND X2) AND Y ==> AND (X1, X2, Y)  
  89. */  
  90. item1->add($3);  
  91. $$ = $1;  
  92. else if (is_cond_and($3))  
  93. AND (Y1 AND Y2) ==> AND (X, Y1, Y2)  
  94. */  item3->add_at_head($1); 
  95. /* X AND Y */  
  96. $$ = new (YYTHD->mem_root) Item_cond_and($1, $3);  
  97. if ($$ == ) 

上下拉動(dòng)可完整查看

在大家瀏覽上述代碼的過程,會(huì)發(fā)現(xiàn)Bison中嵌入了C++的代碼。通過C++代碼,把解析到的信息存儲(chǔ)到相關(guān)對(duì)象中。例如表信息會(huì)存儲(chǔ)到TABLE_LIST中,order_list存儲(chǔ)order by子句里的信息,where字句存儲(chǔ)在Item中。有了這些信息,再輔助以相應(yīng)的算法就可以對(duì)SQL進(jìn)行更進(jìn)一步的處理了。

核心數(shù)據(jù)結(jié)構(gòu)及其關(guān)系

在SQL解析中,最核心的結(jié)構(gòu)是SELECT_LEX,其定義在sql/sql_lex.h中。下面僅列出與上述例子相關(guān)的部分。

數(shù)據(jù)庫(kù)管理提速:SQL解析的探索與應(yīng)用

SQL解析樹結(jié)構(gòu)

上面圖示中,列名username、ismale存儲(chǔ)在item_list中,表名存儲(chǔ)在table_list中,條件存儲(chǔ)在where中。其中以where條件中的Item層次結(jié)構(gòu)最深,表達(dá)也較為復(fù)雜,如下圖所示:

數(shù)據(jù)庫(kù)管理提速:SQL解析的探索與應(yīng)用

where條件

SQL解析的應(yīng)用

為了更深入的了解SQL解析器,這里給出2個(gè)應(yīng)用SQL解析的例子:

1、無(wú)用條件去除

“無(wú)用條件去除”屬于優(yōu)化器的邏輯優(yōu)化范疇,僅僅根據(jù)SQL本身以及表結(jié)構(gòu)即可完成,其優(yōu)化的情況較多,代碼在sql/sql_optimizer.cc文件中的remove_eq_conds函數(shù)。為了避免過于繁瑣的描述,以及大段代碼的粘貼,這里通過圖片來(lái)分析以下四種情況:

  • 1=1 and (m > 3 and n > 4)

  • 1=2 and (m > 3 and n > 4)

  • 1=1 or (m > 3 and n > 4)

  • 1=2 or (m > 3 and n > 4)

無(wú)用條件去除a:

數(shù)據(jù)庫(kù)管理提速:SQL解析的探索與應(yīng)用

 

 

無(wú)用條件去除b

 

 

數(shù)據(jù)庫(kù)管理提速:SQL解析的探索與應(yīng)用

無(wú)用條件去除c

數(shù)據(jù)庫(kù)管理提速:SQL解析的探索與應(yīng)用

無(wú)用條件去除d

數(shù)據(jù)庫(kù)管理提速:SQL解析的探索與應(yīng)用

如果對(duì)其代碼實(shí)現(xiàn)有興趣的同學(xué),需要對(duì)MySQL中的一個(gè)重要數(shù)據(jù)結(jié)構(gòu)Item類有所了解。因?yàn)槠浔容^復(fù)雜,所以MySQL官方文檔專門介紹了Item類。

參考鏈接:https://dev.mysql.com/doc/internals/en/item-class.html

阿里的MySQL小組也有類似的文章。如需更詳細(xì)的了解,就需要去查看源碼中sql/item_*等文件。

2、SQL特征生成

為了確保數(shù)據(jù)庫(kù)這一系統(tǒng)基礎(chǔ)組件穩(wěn)定、高效運(yùn)行,業(yè)界有很多輔助系統(tǒng)。比如慢查詢系統(tǒng)、中間件系統(tǒng)。這些系統(tǒng)采集、收到SQL之后,需要對(duì)SQL進(jìn)行歸類,以便統(tǒng)計(jì)信息或者應(yīng)用相關(guān)策略。歸類時(shí),通常需要獲取SQL特征。比如SQL:

 

  1. select username, ismale from userinfo where age > 20 and level > 5; 

SQL特征為:

 

  1. select username, ismale from userinfo where age > ? and level > ? 

業(yè)界著名的慢查詢分析工具pt-query-digest,通過正則表達(dá)式實(shí)現(xiàn)這個(gè)功能,但是這類處理辦法Bug較多。接下來(lái)就介紹如何使用SQL解析,完成SQL特征的生成。

SQL特征生成分兩部分組成:

  • 生成Token數(shù)組;

  • 根據(jù)Token數(shù)組,生成SQL特征。

首先回顧在詞法解析章節(jié),我們介紹了SQL中的關(guān)鍵字,并且每個(gè)關(guān)鍵字都有一個(gè)16位的整數(shù)對(duì)應(yīng),而非關(guān)鍵字統(tǒng)一用ident表示,其也對(duì)應(yīng)了一個(gè)16位整數(shù)。如下表:

數(shù)據(jù)庫(kù)管理提速:SQL解析的探索與應(yīng)用

將一個(gè)SQL轉(zhuǎn)換成特征的過程:

數(shù)據(jù)庫(kù)管理提速:SQL解析的探索與應(yīng)用

在SQL解析過程中,可以很方便的完成Token數(shù)組的生成。而一旦完成Token數(shù)組的生成,就可以很簡(jiǎn)單的完成SQL特征的生成。SQL特征被廣泛用于各個(gè)系統(tǒng)中,比如pt-query-digest需要根據(jù)特征對(duì)SQL歸類,然而其基于正則表達(dá)式的實(shí)現(xiàn)有諸多Bug。下面列舉幾個(gè)已知的Bug:

數(shù)據(jù)庫(kù)管理提速:SQL解析的探索與應(yīng)用

學(xué)習(xí)建議

最近,在對(duì)SQL解析器和優(yōu)化器探索的過程中,從一開始的茫然無(wú)措到有章可循,也總結(jié)了一些心得體會(huì),在這里跟大家分享一下:

  • 首先,閱讀相關(guān)書籍,書籍能給我們一個(gè)系統(tǒng)的認(rèn)識(shí)解析器和優(yōu)化器的角度。但是該類針對(duì)MySQL的書籍市面上很少,目前中文作品可以看下《數(shù)據(jù)庫(kù)查詢優(yōu)化器的藝術(shù):原理解析與SQL性能優(yōu)化》;

  • 其次,要閱讀源碼,但是***以某個(gè)版本為基礎(chǔ),比如MySQL5.6.23,因?yàn)镾QL解析、優(yōu)化部分的代碼在不斷變化,尤其是在跨越大的版本時(shí),改動(dòng)力度大;

  • 再次,多使用GDB調(diào)試,驗(yàn)證自己的猜測(cè),檢驗(yàn)閱讀質(zhì)量;

  • ***,需要寫相關(guān)代碼驗(yàn)證,只有寫出來(lái)了才能算真正的掌握。 

責(zé)任編輯:龐桂玉 來(lái)源: DBAplus社群
相關(guān)推薦

2022-04-19 09:53:06

云數(shù)據(jù)庫(kù)云計(jì)算數(shù)據(jù)庫(kù)

2018-02-27 15:48:31

數(shù)據(jù)庫(kù)SQL鎖死

2010-06-30 14:54:42

SQL Server

2011-08-22 09:55:30

SQL Server 排序

2009-03-05 14:43:39

元數(shù)據(jù)管理SQL Server

2010-07-05 15:23:08

SQL Server數(shù)

2010-04-29 09:35:31

Oracle數(shù)據(jù)庫(kù)

2022-06-30 10:56:18

字節(jié)云數(shù)據(jù)庫(kù)存儲(chǔ)

2017-06-12 18:24:25

數(shù)據(jù)庫(kù)壓縮技術(shù)

2010-06-30 08:13:18

SQL Server數(shù)

2010-07-21 14:11:36

SQL Server

2011-05-12 11:01:07

MySQL數(shù)據(jù)庫(kù)緩存

2024-07-10 08:00:00

數(shù)據(jù)庫(kù)流式數(shù)據(jù)庫(kù)

2010-07-08 11:23:41

SQL Server還

2011-03-11 16:42:51

Oracle數(shù)據(jù)庫(kù)視圖

2010-06-17 10:02:12

SQL Server數(shù)

2011-08-18 10:36:24

SQL ServerISNULL函數(shù)

2011-08-19 14:53:02

SQL ServerDataRelatio

2010-07-16 15:53:19

SQL Server數(shù)

2010-07-21 14:17:36

SQL Server數(shù)
點(diǎn)贊
收藏

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