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

Cobar源碼分析之AST

運(yùn)維 數(shù)據(jù)庫(kù)運(yùn)維
本文從SQL AST的來(lái)源、結(jié)構(gòu)、遍歷原理、應(yīng)用等方面進(jìn)行介紹,相信看完文章會(huì)對(duì)SQL AST有了初步的了解,如果想進(jìn)一步了解可以參考Cobar項(xiàng)目中的單元測(cè)試進(jìn)行實(shí)際的演示感受。

[[409505]]

本文轉(zhuǎn)載自微信公眾號(hào)「捉蟲大師」,作者捉蟲大師。轉(zhuǎn)載本文請(qǐng)聯(lián)系捉蟲大師公眾號(hào)。

背景

Cobar

Cobar是阿里開源的數(shù)據(jù)庫(kù)中間件,關(guān)于它的介紹這里不再贅述,可以參考之前的文章《Cobar SQL審計(jì)的設(shè)計(jì)與實(shí)現(xiàn)》

SQL

SQL是一種領(lǐng)域語(yǔ)言(編程語(yǔ)言),常用于關(guān)系型數(shù)據(jù)庫(kù),方便管理結(jié)構(gòu)化數(shù)據(jù)。數(shù)據(jù)庫(kù)執(zhí)行SQL時(shí)先對(duì)SQL進(jìn)行詞法分析、語(yǔ)法分析、語(yǔ)義分析生成抽象語(yǔ)法樹(Abstract Syntax Tree,簡(jiǎn)稱AST),再被優(yōu)化器處理生成執(zhí)行計(jì)劃,由執(zhí)行引擎執(zhí)行。

SQL Parser

將SQL解析為AST的解析器叫SQL Parser,開發(fā)這個(gè)解析器通常有兩種方式:

  • 通過工具自動(dòng)生成
    • 優(yōu)點(diǎn):簡(jiǎn)單易于實(shí)現(xiàn)
    • 缺點(diǎn):性能不佳,二次開發(fā)困難
  • 手工編寫
    • 優(yōu)點(diǎn):性能好,代碼清晰易于擴(kuò)展
    • 缺點(diǎn):對(duì)開發(fā)人員要求高,需要了解編譯原理

Cobar中也實(shí)現(xiàn)了SQL Parser,它在Cobar中的位置可以從它的架構(gòu)圖中看到: 

SQL Parser之后是SQL Router,可以推斷出SQL Parser解析出AST的目的是為了分庫(kù)分表的路由功能。

Cobar的SQL Parser也經(jīng)歷了三個(gè)版本的迭代,本質(zhì)是性能考慮:

第一版:基于JavaCC生成SQL parser,性能較差,優(yōu)化不方便

第二版:仿照ANTLR生成的parser結(jié)構(gòu)手寫,中間對(duì)象過多

第三版:基于LL(2)識(shí)別器手寫

本文不對(duì)SQL Parser做過多的介紹,這篇文章我也仔細(xì)閱讀了幾遍,附上總結(jié)的腦圖:

https://github.com/lkxiaolou/reading/tree/main/xmind

Cobar AST

Cobar中的SQL Parser將SQL解析為AST,為了直觀感受,先舉個(gè)例子:

  1. select id,type from goods as g where type in (select type from type_config where status = 0) 

經(jīng)過Cobar SQL Parser后,生成了如下AST對(duì)象:

這個(gè)AST的根節(jié)點(diǎn)就是select語(yǔ)句,然后每個(gè)屬性都是葉子節(jié)點(diǎn),葉子節(jié)點(diǎn)的屬性再分出葉子節(jié)點(diǎn)。可能有點(diǎn)繞,需要從代碼層面感受。

AST的Node定義如下,這里只有個(gè)accept方法,是為了遍歷這棵樹,暫時(shí)不管,后面會(huì)說到:

  1. public interface ASTNode { 
  2.     void accept(SQLASTVisitor visitor); 

實(shí)現(xiàn)這個(gè)ASTNode主要有這幾個(gè):

  • SQLStatement:SQL語(yǔ)句,比如select、update、insert等語(yǔ)句,體現(xiàn)在上圖的DMLSelectStatement
  • Expression:表達(dá)式,比如and、or、比較等語(yǔ)句,體現(xiàn)在InExpression、ComparisionEqualsExpression、LiteralNumber、Identifier
  • TableReference:table相關(guān)語(yǔ)句,體現(xiàn)在TableReferences、TableRefFactor

以ComparisionEqualsExpression的實(shí)現(xiàn)為例

其中1是比較的左右表達(dá)式,2是判斷符,這里是“=”,3是計(jì)算該表達(dá)式。

evaluationInternal如何實(shí)現(xiàn)?其實(shí)表達(dá)式被結(jié)構(gòu)化和窮舉之后這個(gè)問題變得簡(jiǎn)單,比如這里只需要取左右的數(shù)值,進(jìn)行是否相等的比較即可。

AST操作

有了如上對(duì)AST的了解,接下來(lái)看對(duì)AST的操作,最基本的是遍歷,利用ASTNode的accept,需要實(shí)現(xiàn)SQLASTVisitor接口,這個(gè)SQLASTVisitor定義如下:

其實(shí)是利用了java的多態(tài),對(duì)每種ASTNode都定義了visit方法,遍歷時(shí)不同對(duì)象對(duì)應(yīng)到不同方法上。

比如MySQLOutputASTVisitor可以遍歷AST,將AST還原為SQL輸出,只需要這樣:

  1. SQLStatement stmt = SQLParserDelegate.parse(sql); 
  2. StringBuilder s = new StringBuilder(); 
  3. stmt.accept(new MySQLOutputASTVisitor(s)); 
  4. System.out.println(s.toString()); 

這樣執(zhí)行會(huì)輸出

SELECT id, type FROM goods AS G WHERE type IN (SELECT type FROM type_config WHERE status = 0)

SQLParserDelegate.parse(sql)解析出來(lái)為DMLSelectStatement對(duì)象,它的visit方法實(shí)現(xiàn)如下:

  1. @Override 
  2. public void accept(SQLASTVisitor visitor) { 
  3.     visitor.visit(this); 

再看MySQLOutputASTVisitor的visit(DMLSelectStatement node)實(shí)現(xiàn):代碼比較長(zhǎng),這里就不貼了,總體思路是遇到葉子節(jié)點(diǎn)就直接按格式存入StringBuilder中,否則繼續(xù)調(diào)用相應(yīng)節(jié)點(diǎn)的accept繼續(xù)遍歷,是一種深度遍歷的思想。

我們可以參考MySQLOutputASTVisitor編寫符合自己需求的遍歷器。

AST的應(yīng)用

分庫(kù)分表

Cobar中利用AST可以獲取table名、列名、比較的值進(jìn)行分庫(kù)分表,這也是Cobar最重要的功能。

SQL特征生成

除此之外,我了解的AST還可以對(duì)原始SQL生成SQL特征,比如原始SQL是這樣:

select id, name, age from user as u where age >= 20

或者是

select id, name, age from user as u where age >= 30

都可以被歸一化為

select id, name, age from user as u where age >= ?

在進(jìn)行SQL慢查詢或其他的統(tǒng)計(jì)、針對(duì)SQL進(jìn)行限流時(shí)非常有用。

危險(xiǎn)SQL攔截

線上寫了一條沒有where條件的update或delete,這時(shí)可以利用AST進(jìn)行表達(dá)式計(jì)算,對(duì)沒有where條件和where條件恒為true的SQL進(jìn)行攔截。

最后 

本文從SQL AST的來(lái)源、結(jié)構(gòu)、遍歷原理、應(yīng)用等方面進(jìn)行介紹,相信看完文章會(huì)對(duì)SQL AST有了初步的了解,如果想進(jìn)一步了解可以參考Cobar項(xiàng)目中的單元測(cè)試進(jìn)行實(shí)際的演示感受。

 

責(zé)任編輯:武曉燕 來(lái)源: 捉蟲大師
相關(guān)推薦

2011-05-26 10:05:48

MongoDB

2021-03-23 09:17:58

SpringMVCHttpServletJavaEE

2024-06-13 07:55:19

2023-02-26 08:42:10

源碼demouseEffect

2012-09-20 10:07:29

Nginx源碼分析Web服務(wù)器

2011-05-26 16:18:51

Mongodb

2020-07-28 08:54:39

內(nèi)核通信Netlink

2017-01-12 14:52:03

JVMFinalRefere源碼

2009-07-08 13:22:30

JDK源碼分析Set

2022-08-27 08:02:09

SQL函數(shù)語(yǔ)法

2022-01-06 07:06:52

KubernetesResourceAPI

2022-05-30 07:36:54

vmstoragevmselect

2012-09-06 10:07:26

jQuery

2021-09-05 07:35:58

lifecycleAndroid組件原理

2019-09-09 06:30:06

Springboot程序員開發(fā)

2023-03-17 07:53:20

K8sAPIServerKubernetes

2024-05-21 08:40:21

分庫(kù)分表源碼

2017-01-11 14:02:32

JVM源碼內(nèi)存

2021-02-19 06:56:33

架構(gòu)協(xié)程應(yīng)用

2022-07-19 20:04:31

NAPI模塊鴻蒙
點(diǎn)贊
收藏

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