【大數據】SparkSql 連接查詢中的謂詞下推處理 (一)

来源:https://www.cnblogs.com/vivotech/archive/2019/05/14/10862789.html
-Advertisement-
Play Games

SparkSql 是架構在 Spark 計算框架之上的分散式 Sql 引擎,使用 DataFrame 和 DataSet 承載結構化和半結構化數據來實現數據複雜查詢處理,提供的 DSL可以直接使用 scala 語言完成 Sql 查詢,同時也使用 thriftserver 提供服務化的 Sql 查詢... ...


本文首發於 vivo互聯網技術 微信公眾號 https://mp.weixin.qq.com/s/YPN85WBNcnhk8xKjTPTa2g

作者:李勇

目錄:

1.SparkSql

2.連接查詢和連接條件

3.謂詞下推

4.內連接查詢中的謂詞下推規則

4.1.Join後條件通過AND連接

4.2.Join後條件通過OR連接

4.3.分區表使用OR連接過濾條件

1.SparkSql

SparkSql 是架構在 Spark 計算框架之上的分散式 Sql 引擎,使用 DataFrame 和 DataSet 承載結構化和半結構化數據來實現數據複雜查詢處理,提供的 DSL可以直接使用 scala 語言完成 Sql 查詢,同時也使用  thriftserver 提供服務化的 Sql 查詢功能。

SparkSql 提供了 DataSource API ,用戶通過這套 API 可以自己開發一套 Connector,直接查詢各類數據源,數據源包括 NoSql、RDBMS、搜索引擎以及 HDFS 等分散式文件系統上的文件等。和 SparkSql 類似的系統有 Hive、PrestoDB 以及 Impala,這類系統都屬於所謂的" Sql on Hadoop "系統,每個都相當火爆,畢竟在這個不搞 SQL 就是耍流氓的年代,沒 SQL 確實很難找到用戶使用。

2.連接查詢和連接條件

Sql中的連接查詢(join),主要分為內連接查詢(inner join)、外連接查詢(outter join)和半連接查詢(semi join),具體的區別可以參考wiki的解釋。

連接條件(join condition),則是指當這個條件滿足時兩表的兩行數據才能"join"在一起被返回,例如有如下查詢:

其中的"LT.id=RT.idAND LT.id>1"這部分條件被稱為"join中條件",直接用來判斷被join的兩表的兩行記錄能否被join在一起,如果不滿足這個條件,兩表的這兩行記錄並非全部被踢出局,而是根據連接查詢類型的不同有不同的處理,所以這並非一個單表的過濾過程或者兩個表的的“聯合過濾”過程;而where後的"RT.id>2"這部分被稱為"join後條件",這裡雖然成為"join後條件",但是並非一定要在join後才能去過濾數據,只是說明如果在join後進行過濾,肯定可以得到一個正確的結果,這也是我們後邊分析問題時得到正確結果的基準方法。

3.謂詞下推

所謂謂詞(predicate),英文定義是這樣的:A predicate is a function that returns bool (or something that can be implicitly converted to bool),也就是返回值是true或者false的函數,使用過scala或者spark的同學都知道有個filter方法,這個高階函數傳入的參數就是一個返回true或者false的函數。

但是如果是在sql語言中,沒有方法,只有表達式。where後邊的表達式起的作用正是過濾的作用,而這部分語句被sql層解析處理後,在資料庫內部正是以謂詞的形式呈現的。

那麼問題來了,謂詞為什麼要下推呢? SparkSql中的謂詞下推有兩層含義,第一層含義是指由誰來完成數據過濾,第二層含義是指何時完成數據過濾。要解答這兩個問題我們需要瞭解SparkSql的Sql語句處理邏輯,大致可以把SparkSql中的查詢處理流程做如下的劃分:

SparkSql首先會對輸入的Sql語句進行一系列的分析(Analyse),包括詞法解析(可以理解為搜索引擎中的分詞這個過程)、語法分析以及語義分析(例如判斷database或者table是否存在、group by必須和聚合函數結合等規則);之後是執行計劃的生成,包括邏輯計劃和物理計劃。其中在邏輯計劃階段會有很多的優化,對謂詞的處理就在這個階段完成;而物理計劃則是RDD的DAG圖的生成過程;這兩步完成之後則是具體的執行了(也就是各種重量級的計算邏輯,例如join、groupby、filter以及distinct等),這就會有各種物理操作符(RDD的Transformation)的亂入。

能夠完成數據過濾的主體有兩個,第一是分散式Sql層(在execute階段),第二個是數據源。那麼謂詞下推的第一層含義就是指由Sql層的Filter操作符來完成過濾,還是由Scan操作符在掃描階段完成過濾。

上邊提到,我們可以通過封裝SparkSql的Data Source API完成各類數據源的查詢,那麼如果底層數據源無法高效完成數據的過濾,就會執行全局掃描,把每條相關的數據都交給SparkSql的Filter操作符完成過濾,雖然SparkSql使用的Code Generation技術極大的提高了數據過濾的效率,但是這個過程無法避免大量數據的磁碟讀取,甚至在某些情況下會涉及網路IO(例如數據非本地化存儲時);如果底層數據源在進行掃描時能非常快速的完成數據的過濾,那麼就會把過濾交給底層數據源來完成(至於哪些數據源能高效完成數據的過濾以及SparkSql又是如何完成高效數據過濾的則不是本文討論的重點,會在其他系列的文章中介紹)。

那麼謂詞下推第二層含義,即何時完成數據過濾則一般是在指連接查詢中,是先對單表數據進行過濾再和其他表連接還是在先把多表進行連接再對連接後的臨時表進行過濾,則是本系列文章要分析和討論的重點。

4.內連接查詢中的謂詞下推規則

假設我們有兩張表,表結構很簡單,數據也都只有兩條,但是足以講清楚我們的下推規則,兩表如下,一個lefttable,一個righttable:

4.1.Join後條件通過AND連接

先來看一條查詢語句:

這個查詢是一個內連接查詢,join後條件是用and連接的兩個表的過濾條件,假設我們不下推,而是先做內連接判斷,這時是可以得到正確結果的,步驟如下:

  1. 左表id為1的行在右表中可以找到,即這兩行數據可以"join"在一起

  2. 左表id為2的行在右表中可以找到,這兩行也可以"join"在一起

至此,join的臨時結果表(之所以是臨時表,因為還沒有進行過濾)如下:

然後使用where條件進行過濾,顯然臨時表中的第一行不滿足條件,被過濾掉,最後結果如下:

來看看先進行謂詞下推的情況。先對兩表進行過濾,過濾的結果分別如下:

然後再對這兩個過濾後的表進行內連接處理,結果如下:

可見,這和先進行join再過濾得到的結果一致。

4.2.Join後條件通過OR連接

再來看一條查詢語句:

我們先進行join處理,臨時表的結果如下:

然後使用where條件進行過濾,最終查詢結果如下:

如果我們先使用where條件後每個表各自的過濾條件進行過濾,那麼兩表的過濾結果如下:

然後對這兩個臨時表進行內連接處理,結果如下:

表格有問題吧,只有欄位名,沒有欄位值,怎麼回事?是的,你沒看錯,確實沒有值,因為左表過濾結果只有id為1的行,右表過濾結果只有id為2的行,這兩行是不能內連接上的,所以沒有結果。

那麼為什麼where條件中兩表的條件被or連接就會出現錯誤的查詢結果呢?分析原因主要是因為,對於or兩側的過濾條件,任何一個滿足條件即可以返回TRUE,那麼對於"LT.value = 'two' OR RT.value = 'two' "這個查詢條件,如果使用LT.value='two'把只有LT.value為'two'的左表記錄過濾出來,那麼對於左表中LT.value不為two的行,他們可能在跟右表使用id欄位連接上之後,右表的RT.value恰好為two,也滿足"LT.value = 'two' OR RT.value = 'two' ",但是可惜呀可惜,這行記錄因為之前的粗暴處理,已經被過濾掉,結果就是得到了錯誤的查詢結果。所以這種情況下謂詞是不能下推的。

但是OR連接兩表join後條件也有兩個例外,這裡順便分析第一個例外。第一個例外是過濾條件欄位恰好為Join欄位,比如如下的查詢:

在這個查詢中,join後條件依然是使用OR連接兩表的過濾條件,不同的是,join中條件不再是id相等,而是value欄位相等,也就是說過濾條件欄位恰好就是join條件欄位。大家可以自行採用上邊的分步法分析謂詞下推和不下推時的查詢結果,得到的結果是相同的。

我們來看看上邊不能下推時出現的情況在這種查詢里會不會出現。對於左表,如果使用LT.value='two'過濾掉不符合條件的其他行,那麼因為join條件欄位也是value欄位,說明在左表中LT.value不等於two的行,在右表中也不能等於two,否則就不滿足"LT.value=RT.value"了。這裡其實有一個條件傳遞的過程,通過join中條件,已經在邏輯上提前把兩表整合成了一張表。

至於第二個例外,則涉及了SparkSql中的一個優化,所以需要單獨介紹。

4.3.分區表使用OR連接過濾條件

如果兩個表都是分區表,會出現什麼情況呢?我們先來看如下的查詢:

此時左表和右表都不再是普通的表,而是分區表,分區欄位是pt,按照日期進行數據分區。同時兩表查詢條件依然使用OR進行連接。試想,如果不能提前對兩表進行過濾,那麼會有非常巨量的數據要首先進行連接處理,這個代價是非常大的。但是如果按照我們在2中的分析,使用OR連接兩表的過濾條件,又不能隨意的進行謂詞下推,那要如何處理呢?SparkSql在這裡使用了一種叫做“分區裁剪”的優化手段,即把分區並不看做普通的過濾條件,而是使用了“一刀切”的方法,把不符合查詢分區條件的目錄直接排除在待掃描的目錄之外。

我們知道分區表在HDFS上是按照目錄來存儲一個分區的數據的,那麼在進行分區裁剪時,直接把要掃描的HDFS目錄通知Spark的Scan操作符,這樣,Spark在進行掃描時,就可以直接咔嚓掉其他的分區數據了。但是,要完成這種優化,需要SparkSql的語義分析邏輯能夠正確的分析出Sql語句所要表達的精確目的,所以分區欄位在SparkSql的元數據中也是獨立於其他普通欄位,進行了單獨的標示,就是為了方便語義分析邏輯能區別處理Sql語句中where條件里的這種特殊情況。

更多內容敬請關註 vivo 互聯網技術 微信公眾號

 

註:轉載文章請先與微信號:labs2020 聯繫。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 判斷是否為閏年的方法很多,如: 《指定日期,判斷其所屬年份是否為閏年》 https://www.cnblogs.com/insus/p/10841868.html《C#或VB.NET判斷指定的年份是否為閏年》https://www.cnblogs.com/insus/archive/2012/06/ ...
  • 查詢練習一 ...
  • 1 SQL是什麼? 答:是結構話語言,是一種操作關係型資料庫的語言。 2 SQL語言分類? 3 數據類型? 整數:int,bit 小數:decimal 字元串:varchar,char 日期時間: date, time, datetime 枚舉類型(enum) 整數:int,bit 小數:decim ...
  • 欲知道當前資料庫空間使用大小,可以從下麵這個系統表sys.database_files 得到。 SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO -- -- Author: Insus.NET -- Create date: 2019-05-14 -- ...
  • 一、問題的提出 在應用系統開發初期,由於開發資料庫數據比較少,對於查詢SQL語句,複雜視圖的的編寫等體會不出SQL語句各種寫法的性能優劣,但是如果將應用系統提交實際應用後,隨著資料庫中數據的增加,系統的響應速度就成為目前系統需要解決的最主要的問題之一。系統優化中一個很重要的方面就是SQL語句的優化。 ...
  • SQL常用函數說明以及使用 以下補充以下常用的函數,更多的請看oracle函數API文檔 to_char to_date to_number nvl 空值賦值 字元串處理 ltrim 刪除左邊空白符或指定字元 rtrim 刪除右邊空白符或指定字元,與上面類似 trim 刪除空白符或制定字元,與上面類 ...
  • SQL SERVER 資料庫日誌占用很大的空間 ,如果長時間不清除,就會影響數據存儲。 一、工具 sql server 二 方法步驟 1、打開sql server 資料庫,找到要清除日誌的庫。 2、滑鼠選中對應的資料庫名稱,右鍵——屬性,將選項里的恢復模式改成【簡單】。 3、右鍵——任務——收縮—— ...
  • 從sysindexes和sysobjects系統,可以獲取用戶表的一些數據,如果表名,創建時間,表存儲的記錄數等。 下麵代碼,是代碼運行的當前資料庫的用戶表數據。 SELECT o.[name],[crdate],MAX(i.[rows]) AS [rows] FROM sysindexes AS ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...