1. 程式人生 > >一道面試題引出的系列資料庫效能,資料安全問題及解決方案

一道面試題引出的系列資料庫效能,資料安全問題及解決方案

事件背景:

SELECT * FROM girls WHERE age BETWEEN 18 and 24 and boyfriend='no';

上週在朋友圈看到一張照片,隨手轉發並且提出了一個問題。

面試題一枚可好:請問以下SQL有什麼可能的邏輯問題、語法問題、效能問題,可以怎樣進行索引優化、邏輯優化以提升效能?

SELECT.jpg

這個問題在朋友圈引起了很多朋友的興趣,轉發並且提問,希望有一個標準答案輸出作為參考。

標準答案沒有,但是我可以說說我的看法,當然前提是『這個SQL中的一切都是可以質疑的』。管中窺豹,博方家一笑。

開發規範

首先從開發規範上來講,『SELECT *』一般不是最佳實踐,因為你不清楚這個表中有多少個欄位(Column),這樣的輸出是無法格式化和預期的,其輸出結果可能也不全部是你需要的,所以儘量明確定義你需要的欄位名。

那麼第二個問題來了,『SELECT *』和 『SELECT col1,col2 ..』,除了語義上,還有什麼區別?

你要知道的是,當做出這樣的改寫,這條SQL的長度增加,SQLID改變,佔用的Shared Pool共享記憶體也較以前增加了。進行資料字典的列驗證增多,消耗也會增加,也就是CPU佔用會增加(當然這可能是微微的改變);

其次,SQL語句中的,age 和 boyfriend 欄位查詢,都沒有使用繫結變數,這對於不同查詢,如 between 20 and 24,無法共享SQL,會進一步導致硬解析上的高CPU消耗,更多的Shared Pool共享記憶體的佔用;

再次,當 age 和 boyfriend 查詢不適用繫結變數時,可能為資料庫帶來安全注入的風險;

最後,根據程式碼格式規範,BETWEEN 之後的 and 也應該以大寫 AND 形式出現。

這樣的開發規範有助於大家改善程式碼質量,提高效率,規避風險,可是如果都靠DBA手工去做,顯然難度太大,雲和恩墨的SQM - SQL質量管控平臺,可以自動的幫助我們稽核SQL,管控SQL規範,詳情請參閱:SQL稽核,提升開發規範和效能

SE.2.jpg

資料結構和元資料

我們再從資料結構、資料模型和元資料的角度來思考一下,我相信大家見識過各種各樣的資料結構命名法,我見過的遠遠超出想象,各種各樣詭異的命名會坑到我們懷疑人生。

所以,對於以上的SQL查詢,你一定要確定 girls 這個表名的真實定義,是否和你想想的相符合,難道你就篤定這裡是『對面的女孩』大本營?

其次,很少有資料庫裡存在 age 欄位的設計,因為那會是一個不斷改變的事實,更合理的做法是儲存『出生日期』,這是基本資料模型設計的守則。

再次,boyfriend 欄位,你需要確認這裡儲存的確定是你期望的含義『男朋友』,如果是,並且儲存的資料是 Yes | No,如果你不確定其大小寫和格式規範,是應該用 upper 或者 lower 去對一端進行轉換,否則你的查詢可能無法順利匹配;

最後,為什麼我們戶籍重要的登記資訊是『婚姻狀況』?因為 boyfriend 的狀態可能極不穩定,也可能不是1:1的關係,更加該欄位需要頻繁變更,可能很難以維持一致性。

並且,如果這個欄位存在,應該以 0 | 1 標識,可以極大減少儲存的佔用,並且提高查詢效率。

當然,很多朋友說,應當去掉 boyfriend 這個限定條件,因為一旦加上這個約束,你可能面對的情況是 no rows return 的尷尬局面。

關於這個條件,有朋友給了這樣幾個建議:

  1. 去掉 boyfriend ='no' ,你懂的 (這位是老司機)

  2. boyfriend 的名字叫 no 就尷尬了(這個直追 Null 那個梗)

  3. 有朋友還要加幾個條件 and cost < 2000 RMB and beautiful > 85分 and height > 165 order by cost,beautiful desc,height desc (我不得不表示,孩子,你還是嫩啊);

  4. 用 boyfriend is NULL (這是技術流)

那麼如何去檢查核定資料字典的資訊,如何確保SQL的效能,及時發現和解決問題?雲和恩墨的自動化巡檢診斷平臺 - Bethune 正可以幫助你自動發現數據庫中安全隱患,參考:免費的白求恩自動巡檢平臺助你資料庫平安

select.4.jpg

關於效能

我們再來討論一下效能。

首先,在這個SQL中,Between AND 可以進行優化改寫,between 18 and 24,最簡單的有兩種改寫方法:

  1. 將 between and 改寫成 >= 和 <= ,這會減少Oracle自己的轉換,同時減少了SQL字元長度,縮減了網路傳輸,Shared Pool佔用;

  2. 可以將 between and 改寫成 IN (18,19 .. 24 ),資料庫會將 In 值列表轉換成幾個等值比較,然後 CONCATENATION,其成本通常更低;

其次,這個表可能不是很小,而是很大,因為可能 boys 已經被分離出去,所以這個表應當考慮分割槽,輔助其他條件,通過分割槽剪裁快速縮減查詢結果。

所以有朋友建議的SQL是這個樣子的:

SELECT * FROM girls

WHERE (age between 18 and 24) and NOT EXISTS (SELECT * FROM boys WHERE girls.boyfriend_id = boys.boyfriend_id);

再次,有朋友建議的索引優化:對 age 加 bitmap 索引,開並行。

注意,bitmap 對於這個頻繁變更的表不是一個好選擇,鑑於我們的判斷,boyfriend = 'no' 的記錄數極少,那麼關於 age + boyfriend 的複合索引就能快速的找到記錄,如果你是樂觀主義者,就加個 rownum 的限制,如果你是一個悲觀主義者,那麼就可以去掉boyfriend欄位,然後加個 rownum 的限制。

最後,其實我們很容易發現對於age和boyfriend的儲存,行存不如列式儲存,如果使用Oracle 12c的IN-Memory,在記憶體中進行列式壓縮,可以極大的提高查詢效能。

select.5.jpg

如果您非常關注資料庫的效能,那麼雲和恩墨的資料庫效能監控平臺,將會讓您對資料庫的效能一目瞭然,及時預警。參考:洞若觀火,ZONE助力效能提升

select.6.jpg

可是注意,以上我們的推斷,是基於Oracle資料庫的考慮,如果資料庫是 MySQL、Redis,或是其他產品,該如何去調整和優化呢?

如果是MySQL,是否資料量相當龐大之後,如何分庫分表?

那麼多資料庫,那麼多管理、監控和優化工作,你一定要關注一下雲和恩墨最新推出的 zCloud 雲管平臺,讓多雲、多資料管理、優化,融為一體,何以解多資料庫管理之憂?唯有zCloud。

select.7.jpg

關於隱私和安全

如果你以為就只有這些?

select.8.jpg

那麼我還可以告訴你,如果完成以上查詢,並且碰巧獲得了輸出,那麼你可能已經違反了歐盟的GDPR法案,涉嫌侵犯了使用者隱私(哈哈哈哈哈哈,開心嗎)。

在2018年5月25日正式生效的 GDPR 法案,對於使用者的隱私做出了嚴格的界定,如果侵犯濫用使用者隱私資訊,將遭遇高達2000萬歐元或企業年營業額4%的高額懲罰,注意最後一條保護的隱私內容:

公民基本的身份資訊,如姓名、地址和身份證號等;

網路資料,如位置、IP地址、Cookie資料和RFID標籤等;

醫療保健 和 遺傳資料;

生物識別資料,如指紋、虹膜等;

種族或民族資料;

政治觀點;

性取向;

參考前文:GDPR 法案帶來的思考。所以對於企業資料的管理者,如何保護資料安全,確保使用者隱私不被任意訪問,不被DBA不授權訪問,都是一個值得重視的問題,雲和恩墨已經提供針對 GDPR 的安全增強解決方案,歡迎垂詢。

千言萬語,千頭萬緒,匯成最後的答案:這條SQL最終不應該被執行,也不會有返回結果。

select.9.jpg

加油吧,少年!