GaussDB技術(shù)解讀系列之SQL Audit:面向應(yīng)用開發(fā)的SQL審核工具
本文作者??華為云數(shù)據(jù)庫(kù)和應(yīng)用遷移專家? 李志學(xué)
前言
我們先從一個(gè)SQL語句說起(以某傳統(tǒng)單機(jī)數(shù)據(jù)庫(kù)為例)。

也許這就是我們業(yè)務(wù)代碼中潛藏的一個(gè)SQL語句,對(duì)于一個(gè)普通開發(fā)者來說,這個(gè)語句編寫工整,邏輯清晰,沒有什么問題,可以直接推到代碼倉(cāng)中交付上線。但是一個(gè)有經(jīng)驗(yàn)的開發(fā)者或數(shù)據(jù)庫(kù)管理員可能會(huì)發(fā)現(xiàn)這個(gè)SQL存在諸多的優(yōu)化點(diǎn):
兩張表的id字段是否有索引?
like語句不符合最左匹配原則,能否改寫?
test_1表where條件中的create_time判斷不符合單邊原則,無法走索引,可以改寫;
union會(huì)對(duì)結(jié)果集去除,效率較低,能否換成union all?
test_2表的id字段被函數(shù)引用,也可能用不上索引,可以優(yōu)化;
test_2表是否存在id和name聯(lián)合索引,能否加hint,指定特定索引提高查詢性能?
貌似經(jīng)過上述的分析后,這個(gè)SQL可以煥然一新,在該數(shù)據(jù)庫(kù)上飛一樣地跑起來,但這就完了嗎?其實(shí)并沒有,在單機(jī)數(shù)據(jù)庫(kù)上也許已經(jīng)優(yōu)化到了極致,可當(dāng)我們的數(shù)據(jù)庫(kù)是一個(gè)分布式數(shù)據(jù)庫(kù)呢?它可能又會(huì)帶來新的性能問題,我們要考慮where條件中的id是否是分布鍵,concat函數(shù)是否會(huì)影響算子的下推…...這一系列的問題都會(huì)產(chǎn)生。
這實(shí)際就是我們所面臨的現(xiàn)狀,開發(fā)者的技術(shù)能力良莠不齊,DBA對(duì)數(shù)據(jù)庫(kù)知識(shí)的局限性導(dǎo)致爛SQL無處不在,而且隨著數(shù)據(jù)庫(kù)的不斷變更或演進(jìn),一些好的SQL也可能逐步變成需要優(yōu)化的爛SQL, 我們要時(shí)刻不斷地找尋它們的蹤跡。
SQL Audit審核工具介紹
華為內(nèi)部有很多業(yè)務(wù)部門,對(duì)傳統(tǒng)單機(jī)數(shù)據(jù)庫(kù)、MySQL、PostgreSQL等各種數(shù)據(jù)庫(kù)都有深度的使用,也一直備受爛SQL的困擾,隨著GaussDB在內(nèi)部業(yè)務(wù)系統(tǒng)的規(guī)模應(yīng)用,現(xiàn)存SQL在GaussDB中能否高質(zhì)量運(yùn)行也面臨挑戰(zhàn),于是我們開發(fā)了SQL Audit工具,根據(jù)公司內(nèi)部各業(yè)務(wù)部門多年積累的SQL開發(fā)規(guī)范和GaussDB數(shù)據(jù)庫(kù)的優(yōu)秀實(shí)踐,整理出SQL審核規(guī)則上百條,對(duì)命名規(guī)范、表結(jié)構(gòu)/索引設(shè)計(jì)、SQL性能優(yōu)化、分布鍵及算子下推等常見影響SQL質(zhì)量的問題都可以做深入的分析和審核,同時(shí)我們又開發(fā)了一些插件,直接集成到開發(fā)的流水線中,自動(dòng)從代碼倉(cāng)獲取SQL語句,做到一鍵審核。
SQL審核的核心流程可以分為以下三個(gè)階段:

SQL獲?。杭次覀兡軓哪男┣阔@取到需要審核的SQL, 獲取能力決定了我們能否對(duì)開發(fā)中的代碼做更全面的審核;
SQL語法解析:是針對(duì)具體的每一條SQL做語法樹的生成和分析;
SQL規(guī)則審核:是拆解SQL語句的每一部分,和相關(guān)審核規(guī)則項(xiàng)逐一做匹配,找出待優(yōu)化或風(fēng)險(xiǎn)點(diǎn),最終形成審核報(bào)告。
SQL獲取
客戶通過SQL訪問數(shù)據(jù)庫(kù)的渠道多種多樣,客戶端工具、命令行、SQL腳本、應(yīng)用代碼…...代碼開發(fā)又可以采用JDBC、ODBC、底層API調(diào)用等各種方式,SQL語句既可以直接在代碼中拼接,也可以通過配置文件(如:Mybatis),還可以通過ORM框架(如:Hibernate )訪問數(shù)據(jù)庫(kù),所以如果想要獲取到客戶的全部SQL是一件非常困難的事情。
SQL Audit對(duì)當(dāng)前大部分SQL使用場(chǎng)景進(jìn)行了支持,而且還在持續(xù)擴(kuò)大SQL能獲取的范圍,力求能夠全面地將客戶使用的所有SQL全部審核到,下圖是當(dāng)前SQL Audit工具支持的SQL獲取范圍。

手動(dòng)輸入
手動(dòng)輸入為客戶提供了一個(gè)簡(jiǎn)單、易操作的平臺(tái),客戶可以隨時(shí)把自己編寫的SQL語句輸入到SQL Audit工具中進(jìn)行審核,根據(jù)審核結(jié)果直接對(duì)語句做調(diào)整,同時(shí)也可以將一個(gè).sql文件整體上傳上來,進(jìn)行批量的審核。

源代碼
源代碼是爛SQL最主要的來源,但因其編程語言多種多樣(C/C++/JAVA/GO/PYTHON/SHELL…...),編寫方式也千奇百怪,所以很難將每種場(chǎng)景的SQL都獲取完整,我們將代碼中的SQL分成了三類:
(1)源碼拼接SQL

通過拼接的方式生成SQL語句,拼接的過程可能會(huì)引入很多變量,這種情況無法獲取到完整的SQL,所以通過靜態(tài)文件提取SQL的方式會(huì)有很大缺陷,SQL Audit工具支持對(duì)Java代碼做語法解析,提取里面的SQL,對(duì)于其他語言的代碼目前暫不支持。
(2)無SQL的ORM框架
例如Hibernate、SQLAlchemy等這些ORM框架無法從代碼中獲取到SQL語句,SQL Audit工具提供了基于Java二進(jìn)制改寫技術(shù),在JVM運(yùn)行時(shí)動(dòng)態(tài)監(jiān)聽JDBC API,獲取SQL語句。
(3)配置SQL的ORM
很多業(yè)務(wù)系統(tǒng)基于Mybatis框架搭建訪問數(shù)據(jù)庫(kù)的能力,Mybatis通過注解或配置文件的方式編寫SQL語句,SQL Audit工具能夠?qū)ybatis的注解和配置文件進(jìn)行深度解析,提取SQL成功率達(dá)99%以上。
數(shù)據(jù)庫(kù)對(duì)象
數(shù)據(jù)庫(kù)表結(jié)構(gòu)、索引、約束的設(shè)計(jì)以及存儲(chǔ)過程、函數(shù)等PL/SQL的編寫對(duì)數(shù)據(jù)庫(kù)的性能起決定性作用,SQL Audit工具可以連接到數(shù)據(jù)庫(kù),獲取數(shù)據(jù)庫(kù)中的全部對(duì)象定義,從設(shè)計(jì)的規(guī)范性(如:命名規(guī)范、長(zhǎng)度/大小寫限制)、合理性(如:索引是否合理)和性能等方面進(jìn)行考量,給出審核建議。
數(shù)據(jù)庫(kù)日志
為了更全面地獲取到發(fā)生在數(shù)據(jù)庫(kù)的SQL語句,從數(shù)據(jù)庫(kù)本身的日志層面著手也是一個(gè)比較可行的方案,解析數(shù)據(jù)庫(kù)的redo、開啟數(shù)據(jù)庫(kù)審計(jì)日志、查詢SQL緩存區(qū)等方式都能夠有效獲取到運(yùn)行SQL,SQL Audit工具也支持通過數(shù)據(jù)庫(kù)日志獲取SQL語句的能力。
流量抓取
為了解決從源代碼中無法獲取全部SQL的問題,我們開發(fā)了基于流量抓取的SQL審核能力,它能極大提升對(duì)SQL獲取的完整度。IP+端口作為數(shù)據(jù)庫(kù)對(duì)外的統(tǒng)一入口,基本可以包含客戶業(yè)務(wù)和運(yùn)維所產(chǎn)生的全部SQL語句,通過對(duì)數(shù)據(jù)庫(kù)服務(wù)器端口的旁路監(jiān)聽,獲取到網(wǎng)絡(luò)協(xié)議包,經(jīng)過對(duì)數(shù)據(jù)庫(kù)網(wǎng)絡(luò)協(xié)議解析和重復(fù)SQL過濾,得到有效的SQL語句,最后將這些SQL傳入SQL Audit工具進(jìn)行審核。

SQL解析
SQL解析的過程就是將SQL語句按照語法規(guī)則解析成語法樹的過程,一般的解析過程分為詞法解析和語法解析,然后生成語法樹,大部分對(duì)SQL語句分析的工具都是直接遍歷語法樹實(shí)現(xiàn)的,SQL Audit工具沒有直接解析語法樹,而是增加了一個(gè)處理過程,將語法樹解析成Java描述類,后面所有的審核規(guī)則都是基于這個(gè)語法描述類進(jìn)行,這樣大大提高對(duì)審核規(guī)則的開發(fā)效率,同時(shí)降低了開發(fā)難度。

SQL審核
豐富的審核規(guī)則
審核的核心是審核規(guī)則,而審核規(guī)則的核心是對(duì)數(shù)據(jù)庫(kù)的理解+對(duì)客戶業(yè)務(wù)開發(fā)理解的實(shí)踐經(jīng)驗(yàn)總結(jié),我們結(jié)合GaussDB數(shù)據(jù)庫(kù)的最佳實(shí)踐+公司內(nèi)外部客戶的實(shí)際使用場(chǎng)景,整理出審核規(guī)則數(shù)百條,目前產(chǎn)品中已支持規(guī)則78條,包含了SQL開發(fā)過程中常見的規(guī)范和性能問題,后續(xù)會(huì)有更多的規(guī)則持續(xù)豐富到產(chǎn)品中。

SQL Audit同時(shí)提供了模板配置功能,客戶可以根據(jù)自身業(yè)務(wù)場(chǎng)景靈活地選擇需要審核的規(guī)則。
深度審核
SQL Audit審核流程如下圖所示:

當(dāng)一個(gè)SQL輸入到SQL Audit中后,首先會(huì)對(duì)SQL進(jìn)行語法解析,然后根據(jù)SQL中所依賴的表、視圖等對(duì)象,去數(shù)據(jù)庫(kù)中獲取元數(shù)據(jù)信息(列信息、索引信息等),如果這個(gè)SQL語句的性能可能受執(zhí)行計(jì)劃的影響,則會(huì)再?gòu)臄?shù)據(jù)庫(kù)中獲取該語句的執(zhí)行計(jì)劃,綜合上述全部信息,逐一匹配每一個(gè)相關(guān)的規(guī)則進(jìn)行審核,最終輸出全部違反規(guī)則項(xiàng)。
實(shí)踐案例
華為云內(nèi)部某系統(tǒng)有一部分的業(yè)務(wù)代碼是基于JAVA的Mybatis框架開發(fā),在將數(shù)據(jù)庫(kù)替換到GaussDB的過程中有大量的SQL做了兼容性改造,為保證改造后的SQL能夠高質(zhì)量地在GaussDB數(shù)據(jù)庫(kù)中運(yùn)行,該系統(tǒng)通過SQL Audit工具對(duì)整個(gè)代碼倉(cāng)進(jìn)行全面審核,同時(shí)在流水線中部署了SQL Audit審核插件,持續(xù)對(duì)增量代碼進(jìn)行看護(hù)。SQL Audit發(fā)現(xiàn)了大量的不規(guī)范和低性能的SQL,提前規(guī)避了風(fēng)險(xiǎn)SQL流入到生產(chǎn)環(huán)境,開發(fā)人員根據(jù)SQL Audit的審核報(bào)告對(duì)代碼進(jìn)行了優(yōu)化,業(yè)務(wù)切換到GaussDB后持續(xù)穩(wěn)定運(yùn)行。
以其中一個(gè)任務(wù)為例,該任務(wù)涉及SQL總數(shù)有1881個(gè),審核出有問題的SQL有300多個(gè)。
審核結(jié)果統(tǒng)計(jì)報(bào)告:

審核問題SQL詳情:

GaussDB在打造內(nèi)核競(jìng)爭(zhēng)力的同時(shí),希望給客戶提供全流程、全鏈路,面向開發(fā)和運(yùn)維的數(shù)據(jù)庫(kù)自動(dòng)駕駛體驗(yàn)。今年我們發(fā)布的SQL自動(dòng)審核工具,在開發(fā)環(huán)節(jié)幫助客戶寫好SQL,拒絕爛SQL。
未來,我們還將進(jìn)一步支持對(duì)PL/SQL審核的支持,比如存儲(chǔ)過程、函數(shù)、觸發(fā)器、包等的審核,以及與AI大模型的結(jié)合,大模型在SQL語言的處理上已經(jīng)做得很好,SQL Audit工具會(huì)和華為的盤古大模型進(jìn)行對(duì)接,通過大模型的能力增強(qiáng)它的審核、優(yōu)化和改寫能力。