一、什么是 SQL
sql (Structured Query Language: 結(jié)構(gòu)化查詢語(yǔ)言) 是高級(jí)的費(fèi)過程化編程語(yǔ)言,允許用戶在高層數(shù)據(jù)結(jié)構(gòu)上工作,是一種數(shù)據(jù)查詢和程序設(shè)計(jì)語(yǔ)言,也是 (ANSI) 的一項(xiàng)標(biāo)準(zhǔn)的計(jì)算機(jī)語(yǔ)言. but... 目前仍然存在著許多不同版本的 sql 語(yǔ)言,為了與 ANSI 標(biāo)準(zhǔn)相兼容,它們必須以相似的方式共同地來(lái)支持一些主要的命令 (比如 SELECT、UPDATE、DELETE、INSERT、WHERE 等等).
在標(biāo)準(zhǔn) SQL 中,SQL 語(yǔ)句包含四種類型
DML(Data Manipulation Language):數(shù)據(jù)操作語(yǔ)言,用來(lái)定義數(shù)據(jù)庫(kù)記錄(數(shù)據(jù))。
DCL(Data Control Language):數(shù)據(jù)控制語(yǔ)言,用來(lái)定義訪問權(quán)限和安全級(jí)別。
DQL(Data Query Language):數(shù)據(jù)查詢語(yǔ)言,用來(lái)查詢記錄(數(shù)據(jù))。
DDL(Data Definition Language):數(shù)據(jù)定義語(yǔ)言,用來(lái)定義數(shù)據(jù)庫(kù)對(duì)象(庫(kù),表,列等)
二、如何執(zhí)行 SQL
2.1 MySQL
以 mysql 為例,sql 執(zhí)行流程大致分為以下節(jié)點(diǎn) (mysql server 層代碼,不包含引擎層事務(wù) /log 等操作):
mysqlLex: mysql 自身的詞法分析程序,C++ 語(yǔ)言開發(fā),基于輸入的語(yǔ)句進(jìn)行分詞,并解析除每個(gè)分詞的意義。分詞的本質(zhì)便是正則表達(dá)式的匹配過程。源碼在 sql/sql_lex.cc
Bision: 根據(jù) mysql 定義的語(yǔ)法規(guī)則,進(jìn)行語(yǔ)法解析,語(yǔ)法解析就是生成語(yǔ)法樹的過程。核心是如何涉及合適的存儲(chǔ)結(jié)構(gòu)以及相關(guān)算法,去存儲(chǔ)和遍歷所有的信息
語(yǔ)法解析中,生成語(yǔ)法樹:
mysql 分析器: SQL 解析,針對(duì)關(guān)鍵詞 / 非關(guān)鍵詞進(jìn)行提取、解析,并生成解析語(yǔ)法樹。如果分析到語(yǔ)法錯(cuò)誤,會(huì)拋出異常: ERROR: You have an error in your SQL syntax. 同時(shí)該階段也會(huì)做一些校驗(yàn),如不存在字段會(huì)拋出異常: unknow column in field list.
引申點(diǎn):
a. 語(yǔ)法樹生成規(guī)則
b. mysql 的優(yōu)化規(guī)則
2.2 hive sql
Hive 是基于 Hadoop 構(gòu)建的一套數(shù)據(jù)倉(cāng)庫(kù)分析系統(tǒng),它提供了豐富的 SQL 查詢方式來(lái)分析存儲(chǔ)在 Hadoop 分布式文件系統(tǒng)中的數(shù)據(jù),可以將結(jié)構(gòu)化的數(shù)據(jù)文件映射為一張數(shù)據(jù)庫(kù)表,并提供完整的 SQL 查詢功能,可以將 SQL 語(yǔ)句轉(zhuǎn)換為 MapReduce 任務(wù)進(jìn)行運(yùn)行,通過自己的 SQL 去查詢分析需要的內(nèi)容,這套 SQL 簡(jiǎn)稱 Hive SQL,使不熟悉 mapreduce 的用戶很方便的利用 SQL 語(yǔ)言查詢,匯總,分析數(shù)據(jù)
hive 架構(gòu)圖:
Driver:
輸入了 sql 字符串,對(duì) sql 字符串進(jìn)行解析,轉(zhuǎn)化程抽象語(yǔ)法樹,再轉(zhuǎn)化成邏輯計(jì)劃,然后使用優(yōu)化工具對(duì)邏輯計(jì)劃進(jìn)行優(yōu)化,最終生成物理計(jì)劃(序列化反序列化,UDF 函數(shù)),交給 Execution 執(zhí)行引擎,提交到 MapReduce 上執(zhí)行(輸入和輸出可以是本地的也可以是 HDFS/Hbase)見下圖的 hive 架構(gòu)
hiveSql 的執(zhí)行流程如下:
sql 寫出來(lái)以后只是一些字符串的拼接,所以要經(jīng)過一系列的解析處理,才能最終變成集群上的執(zhí)行的作業(yè)
(1)Parser:將 sql 解析為 AST(抽象語(yǔ)法樹),會(huì)進(jìn)行語(yǔ)法校驗(yàn),AST 本質(zhì)還是字符串
(2)Analyzer:語(yǔ)法解析,生成 QB(query block)
(3)Logicl Plan:邏輯執(zhí)行計(jì)劃解析,生成一堆 Opertator Tree
(4)Logical optimizer: 進(jìn)行邏輯執(zhí)行計(jì)劃優(yōu)化,生成一堆優(yōu)化后的 Opertator Tree
(5)Phsical plan:物理執(zhí)行計(jì)劃解析,生成 tasktree
(6)Phsical Optimizer:進(jìn)行物理執(zhí)行計(jì)劃優(yōu)化,生成優(yōu)化后的 tasktree,該任務(wù)即是集群上的執(zhí)行的作業(yè)
結(jié)論:經(jīng)過以上的六步,普通的字符串 sql 被解析映射成了集群上的執(zhí)行任務(wù),最重要的兩步是 邏輯執(zhí)行計(jì)劃優(yōu)化和物理執(zhí)行計(jì)劃優(yōu)化(圖中紅線圈畫)
Antlr: Antrl 是一種語(yǔ)言識(shí)別的工具,基于 JAVA 開發(fā),可以用來(lái)構(gòu)造領(lǐng)域語(yǔ)言。它提供了一個(gè)框架,可以通過包含 java, C++, 或 C# 動(dòng)作 (action) 的語(yǔ)法描述來(lái)構(gòu)造語(yǔ)言識(shí)別器,編譯器和解釋器.Antlr 完成了 hive 詞法分析、語(yǔ)法分析、語(yǔ)義分析、中間代碼生成的過程.
AST 語(yǔ)法樹舉例:
引申學(xué)習(xí):
a. 從 hivesql 的執(zhí)行機(jī)制可以看出,hive 并不適合用于聯(lián)機(jī)事務(wù)處理,無(wú)法提供實(shí)時(shí)查詢功能;最適合應(yīng)用在基于大量不可變數(shù)據(jù)的批處理作業(yè)
b. Antlr 的解析流程
c. hive 的優(yōu)化規(guī)則
2.3 flink sql
Flink SQL 是 Flink 中最高級(jí)的抽象,可以劃分為 SQL --> Table API --> DataStream/DataSetAPI --> Stateful Stream Processing
Flink SQL 包含 DML 數(shù)據(jù)操作語(yǔ)言、 DDL 數(shù)據(jù)語(yǔ)言, DQL 數(shù)據(jù)查詢語(yǔ)言,不包含 DCL 語(yǔ)言。
(1)首先,F(xiàn)linkSQL 底層使用的是 Apache Calcite 引擎來(lái)處理 SQL 語(yǔ)句,Calcite 會(huì)使用 javaCC 做 SQL 解析,javaCC 根據(jù) Calcite 中定義的 Parser.jj 文件,生成一系列的 java 代碼,生成的 java 代碼會(huì)把 SQL 轉(zhuǎn)換成 AST 抽象語(yǔ)法樹(即 SQLNode 類型)。
(2)生成的 SqlNode 抽象語(yǔ)法樹,他是一個(gè)未經(jīng)驗(yàn)證的抽象語(yǔ)法樹,這時(shí) SQL Validator 會(huì)獲取 Flink Catalog 中的元數(shù)據(jù)信息來(lái)驗(yàn)證 sql 語(yǔ)法,元數(shù)據(jù)信息檢查包括表名,字段名,函數(shù)名,數(shù)據(jù)類型等檢查。然后生成一個(gè)校驗(yàn)后的 SqlNode。
(3)到達(dá)這步后,只是將 SQL 解析到 java 數(shù)據(jù)結(jié)構(gòu)的固定節(jié)點(diǎn)上,并沒有給出相關(guān)節(jié)點(diǎn)之間的關(guān)聯(lián)關(guān)系以及每個(gè)節(jié)點(diǎn)的類型信息。
所以,還需要將 SqlNode 轉(zhuǎn)換為邏輯計(jì)劃,也就是 LogicalPlan,在轉(zhuǎn)換過程中,會(huì)使用 SqlToOperationConverter 類,來(lái)將 SqlNode 轉(zhuǎn)換為 Operation,Operation 會(huì)根據(jù) SQL 語(yǔ)法來(lái)執(zhí)行創(chuàng)建表或者刪除表等操作,同時(shí) FlinkPlannerImpl.rel () 方法會(huì)將 SQLNode 轉(zhuǎn)換成 RelNode 樹,并返回 RelRoot。
(4)第 4 步將執(zhí)行 Optimize 操作,按照預(yù)定義的優(yōu)化規(guī)則 RelOptRule 優(yōu)化邏輯計(jì)劃。
Calcite 中的優(yōu)化器 RelOptPlanner 有兩種,一是基于規(guī)則優(yōu)化(RBO)的 HepPlanner,二是基于代價(jià)優(yōu)化(CBO)的 VolcanoPlanner。然后得到優(yōu)化后的 RelNode, 再基于 Flink 里面的 rules 將優(yōu)化后的邏輯計(jì)劃轉(zhuǎn)換成物理計(jì)劃。
(5)第 5 步 執(zhí)行 execute 操作,會(huì)通過代碼生成 transformation,然后遞歸遍歷各節(jié)點(diǎn),將 DataStreamRelNode 轉(zhuǎn)換成 DataStream,在這期間,會(huì)依次遞歸調(diào)用 DataStreamUnion、DataStreamCalc、DataStreamScan 類中重寫的 translateToPlan 方法。遞歸調(diào)用各節(jié)點(diǎn)的 translateToPlan,實(shí)際是利用 CodeGen 元編成 Flink 的各種算子,相當(dāng)于直接利用 Flink 的 DataSet 或者 DataStream 開發(fā)程序。
(6)最后進(jìn)一步編譯成可執(zhí)行的 JobGraph 提交運(yùn)行。
Flink SQL 使用 Apache Calcite 作為解析器和優(yōu)化器
Calcite : 一種動(dòng)態(tài)數(shù)據(jù)管理框架,它具備很多典型數(shù)據(jù)庫(kù)管理系統(tǒng)的功能 如 SQL 解析、 SQL 校驗(yàn)、 SQL 查詢優(yōu)化、 SQL 生成以及數(shù)據(jù)連接查詢等,但是又省略了一些關(guān)鍵的功能,如 Calcite 并不存儲(chǔ)相關(guān)的元數(shù)據(jù)和基本數(shù)據(jù),不完全包含相關(guān)處理數(shù)據(jù)的算法等。
引申學(xué)習(xí):
a. flink sql 優(yōu)化規(guī)則
三、常見 SQL 解析引擎
持續(xù)補(bǔ)充 ing...
四、總結(jié)
在實(shí)際工作過程中會(huì)涉及到相關(guān)的 sql 優(yōu)化,比如將非研發(fā)的業(yè)務(wù)老師寫的復(fù)雜嵌套 sql 后臺(tái)自動(dòng)改為非嵌套執(zhí)行,提高查詢性能。支持 redisSQL, 以標(biāo)準(zhǔn) SQL 格式解析成后臺(tái)可執(zhí)行的 redis 命令。目前采用的開源 jsqlparser 框架來(lái)實(shí)現(xiàn)語(yǔ)法樹的解析,好處是操作簡(jiǎn)單,只對(duì) sql 語(yǔ)句進(jìn)行拆分,解析成 java 類的層次結(jié)構(gòu),支持 visitor 模式,與數(shù)據(jù)庫(kù)無(wú)關(guān)。缺點(diǎn)是只支持常見的 SQL 語(yǔ)法集,如若要擴(kuò)展語(yǔ)法需改其源碼,對(duì)代碼的侵入性與維護(hù)性造成影響。想要做好 sql 解析優(yōu)化相關(guān)的工作,還是要深入了解 sql 的執(zhí)行原理,了解各個(gè) sql 引擎的特點(diǎn)與優(yōu)劣。站在架構(gòu)的角度來(lái)思考來(lái)思考問題.
工欲善其事,必先利其器.
作者:京東科技 李丹楓
來(lái)源:京東云開發(fā)者社區(qū) 轉(zhuǎn)載請(qǐng)注明來(lái)源