SQL作業運行慢如何定位
作業運行慢可以通過以下步驟進行排查處理。
可能原因1:FullGC原因導致作業運行慢
判斷當前作業運行慢是否是FullGC導致:
1.登錄DLI控制臺,單擊“作業管理 > SQL作業”。
2.在SQL作業頁面,在對應作業的“操作”列,單擊“更多 > 歸檔日志”。
3.在OBS目錄下,獲取歸檔日志文件夾,詳細如下。
?Spark SQL作業:
查看帶有“driver”或者為“container_ xxx _000001”的日志文件夾則為需要查看的Driver日志目錄。
?Spark Jar作業:
Spark Jar作業的歸檔日志文件夾以“batch”開頭。
4.進入歸檔日志文件目錄,在歸檔日志文件目錄下,下載“gc.log.*”日志。
5.打開已下載的“gc.log.*”日志,搜索“Full GC”關鍵字,查看日志中是否有時間連續,并且頻繁出現“Full GC”的日志信息。
FullGC問題原因定位和解決:
原因1 小文件過多 :當一個表中的小文件過多時,可能會造成Driver內存FullGC。
1.登錄DLI控制臺,選擇SQL編輯器,在SQL編輯器頁面選擇問題作業的隊列和數據庫。
2.執行以下語句,查看作業中表的文件數量。“ 表名 ”替換為具體問題作業中的表名稱。
select count(distinct fn) FROM
(select input_file_name() as fn from 表名) a
3.如果小文件過多,則可以參考SQL作業相關問題章節“作業開發-如何合并小文件”來進行處理。
原因2 廣播表 :廣播也可能會造成Driver內存的FullGC。
- 登錄DLI控制臺,單擊“作業管理 > SQL作業”。
- 在SQL作業頁面,在對應作業所在行,單擊按鈕,查看作業詳情,獲取作業ID。
- 在對應作業的“操作”列,單擊“Spark UI”,進入“Spark UI”頁面。
- 在“Spark UI”頁面,在上方菜單欄選擇“SQL”。參考下圖,根據作業ID,單擊Description中的超鏈接。
- 查看對應作業的DAG圖,判斷是否有BroadcastNestedLoopJoin節點。
作業的DAG圖。

- 如果存在廣播,則參考下方“SQL作業中存在join操作,因為自動廣播導致內存不足,作業一直運行中”處理。
可能原因2:數據傾斜
判斷當前作業運行慢是否是數據傾斜導致
1.登錄DLI控制臺,單擊“作業管理 > SQL作業”。
2.在SQL作業頁面,在對應作業所在行,單擊按鈕,查看作業詳情信息,獲取作業ID。
3.在對應作業的“操作”列,單擊“Spark UI”,進入到Spark UI頁面。
4.在“Spark UI”頁面,在上方菜單欄選擇“Jobs”。參考下圖,根據作業ID,單擊鏈接。

5.根據Active Stage可以看到當前正在運行的Stage運行情況,單擊Description中的超鏈接。

6.在Stage中,可以看到每一個Task開始運行時間“Launch Time”,以及Task運行耗時時間“Duration”。
7.單擊“Duration”,可以根據耗時進行排序,排查是否存在單個Task耗時過長導致整體作業時間變長問題。
參考下圖可以看到數據傾斜時,單個任務的shuffle數據遠大于其他Task的數據,導致該任務耗時時間變長。
數據傾斜示例圖

數據傾斜原因和解決
Shuffle的數據傾斜基本是由于join中的key值數量不均衡導致。
1.對join連接條件進行group by 和count,統計每個連接條件的key值的數量。示例如下:
lefttbl表和righttbl表進行join關聯,其中lefttbl表的num為連接條件的key值。則可以對lefttbl.num進行group by和count統計。
SELECT * FROM lefttbl a LEFT join righttbl b on a.num = b.int2;
SELECT count(1) as count,num from lefttbl group by lefttbl.num ORDER BY count desc;
2.考慮在對應key值上添加concat(cast(round(rand() *999999999)as string)隨機數進行打散。
3.如果確實因為單個key值傾斜嚴重且不可對key值拼接隨機值打散,則參考上方"配置AE參數解決數據傾斜"處理。
查看DLI SQL日志
場景概述
日常運維時需要查看DLI SQL日志。
操作步驟
1.在DataArts Studio控制臺獲取DataArts Studio執行DLI作業的job id。
查找job id

2.在DLI控制臺,選擇“作業管理”>“SQL作業”。
3.在SQL作業管理頁面,輸入對應的job id,找到對應的作業。
4.在“操作”列中,單擊“更多”>“歸檔日志”>“下載日志到本地”。
5.在所下載的日志中搜索對應jobId,即可查看具體的執行日志。
查看DLI的執行SQL記錄
場景概述
執行SQL作業過程中需要查看對應的記錄。
操作步驟
1.登錄DLI管理控制臺。
2.在左側導航欄單擊“作業管理”>“SQL作業”進入SQL作業管理頁面。
3.輸入作業ID或者執行的語句可以篩選所要查看的作業。
配置AE參數解決數據傾斜
場景概述
如果觀察到SQL執行時間較長,可進入SparkUI查看對應SQL的執行狀態。
如果觀察到一個stage運行時間超過20分鐘且只剩余一個task在運行,即為數據傾斜的情況。
數據傾斜樣例

操作步驟
1.登錄數據湖探索管理控制臺,選擇“SQL作業”,在要修改的作業所在行的“操作”列,單擊“編輯”進入SQL編輯器界面。
2.在SQL編輯器界面,單擊“設置”,在“配置項”嘗試添加以下幾個Spark參數進行解決。
參數項如下,冒號前是配置項,冒號后是配置項的值。
spark.sql.enableToString:false
spark.sql.adaptive.join.enabled:true
spark.sql.adaptive.enabled:true
spark.sql.adaptive.skewedJoin.enabled:true
spark.sql.adaptive.enableToString:false
spark.sql.adaptive.skewedPartitionMaxSplits:10
說明spark.sql.adaptive.skewedPartitionMaxSplits表示傾斜拆分力度,可不加,默認為5,最大為10。
3.單擊“執行”重新運行作業,查看優化效果。
DLI控制臺中無法查詢到對應表
問題現象
已知存在某DLI表,但在DLI頁面查詢不到該表。
問題根因
已有表但是查詢不到時,大概率是因為當前登錄的用戶沒有對該表的查詢和操作權限。
解決措施
聯系創建該表的用戶,讓該用戶給需要操作該表的其他用戶賦予查詢和操作的權限。賦權操作如下:
1.使用創建表的用戶賬號登錄到DLI管理控制臺,選擇“數據管理 > 庫表管理”。
2.單擊對應的數據庫名稱,進入到表管理界面。在對應表的“操作”列,單擊“權限管理”,進入到表權限管理界面。
3.單擊“授權”,授權對象選擇“用戶授權”,用戶名選擇需要授權的用戶名,勾選對應需要操作的權限。如“查詢表”、“插入”等根據需要勾選。
4.單擊“確定”完成權限授權。
5.授權完成后,再使用已授權的用戶登錄DLI控制臺,查看是否能正常查詢到對應表。
OBS表壓縮率較高
當Parquet/Orc格式的OBS表對應的文件壓縮率較高時(跟文本相比,超過5倍壓縮率),建議在提交導入數據到DLI表作業時,在submit-job請求體conf字段中配置“dli.sql.files.maxPartitionBytes=33554432”,該配置項默認值為128MB,將其配置成32MB,可以減少單個任務讀取的數據量,避免因過高的壓縮比,導致解壓后單個任務處理的數據量過大。
如何避免字符碼不一致導致的亂碼
DLI只支持UTF-8文本格式。
執行創建表和導入操作時,用戶的數據需要是以UTF-8編碼。
刪除表后再重新創建同名的表,需要對操作該表的用戶和項目重新賦權
問題場景
A用戶通過SQL作業在某數據庫下創建了表testTable,并且授權testTable給B用戶插入和刪除表數據的權限。后續A用戶刪除了表testTable,并重新創建了同名的表testTable,如果希望B用戶繼續保留插入和刪除表testTable數據的權限,則需要重新對該表進行權限賦予。
問題根因
刪除表后再重建同名的表,該場景下表權限不會自動繼承,需要重新對需要操作該該表的用戶或項目進行賦權操作。
解決方案
表刪除再創建后,需要重新對需要操作該表的用戶或項目進行賦權操作。具體操作如下:
1.在管理控制臺左側,單擊“數據管理”>“庫表管理”。
2.單擊需要設置權限的表所在的數據庫名,進入該數據庫的“表管理”頁面。
3.單擊所選表“操作”欄中的“權限管理”,將顯示該表對應的權限信息。
4.單擊表權限管理頁面右上角的“授權”按鈕。
5.在彈出的“授權”對話框中選擇相應的權限。
6.單擊“確定”,完成表權限設置。
DLI分區內表導入的文件不包含分區列的數據,導致數據導入完成后查詢表數據失敗
問題現象
DLI分區內表導入了CSV文件數據,導入的文件數據沒有包含對應分區列的字段數據。分區表查詢時需要指定分區字段,導致查詢不到表數據。
問題根因
DLI分區內表在導入數據時,如果文件數據沒有包含分區字段,則系統會默認指定分區值“ HIVE_DEFAULT_PARTITION ”,當前Spark判斷分區為空時,則會直接返回null,不返回具體的數據。
解決方案
1.登錄DLI管理控制臺,在“SQL編輯器”中,單擊“設置”。
2.在參數設置中,添加參數“spark.sql.forcePartitionPredicatesOnPartitionedTable.enabled”,值設置為“false”。
3.上述步驟參數設置完成后,則可以進行全表查詢,不用查詢表的時候要包含分區字段。
創建OBS外表,因為OBS文件中的某字段存在回車換行符導致表字段數據錯誤
問題現象
創建OBS外表,因為指定的OBS文件內容中某字段包含回車換行符導致表字段數據錯誤。
例如,當前創建的OBS外表語句為:
CREATE TABLE test06 (name string, id int, no string) USING csv OPTIONS (path "obs://dli-test-001/test.csv");
test.csv文件內容如下:
Jordon,88,"aa
bb"
因為最后一個字段的aa和bb之間存在回車換行。創建OBS外表后,查詢test06表數據內容顯示如下:
name id classno
Jordon 88 aa
bb" null null
解決方案
創建OBS外表時,通過multiLine=true來指定列數據包含回車換行符。針對舉例的建表語句,可以通過如下示例解決:
CREATE TABLE test06 (name string, id int, no string) USING csv OPTIONS (path "obs://dli-test-001/test.csv",multiLine=true);
SQL作業中存在join操作,因為自動廣播導致內存不足,作業一直運行中
問題現象
SQL作業中存在join操作,作業提交后狀態一直是運行中,沒有結果返回。
問題根因
Spark SQL作業存在join小表操作時,會觸發自動廣播所有executor,使得join快速完成。但同時該操作會增加executor的內存消耗,如果executor內存不夠時,導致作業運行失敗。
解決措施
1.排查執行的SQL中是否有使用“/*+ BROADCAST(u) */”強制做broadcastjoin。如果有,則需要去掉該標識。
2.設置spark.sql.autoBroadcastJoinThreshold=-1,具體操作如下:
a.登錄DLI管理控制臺,單擊“作業管理 > SQL作業”,在對應報錯作業的“操作”列,單擊“編輯”進入到SQL編輯器頁面。
b.單擊“設置”,在參數設置中選擇“spark.sql.autoBroadcastJoinThreshold”參數,其值設置為“-1”。
c.重新單擊“執行”,運行該作業,觀察作業運行結果。
join表時沒有添加on條件,造成笛卡爾積查詢,導致隊列資源爆滿,作業運行失敗
問題現象
運行的SQL語句中存在join表,但是join沒有添加on條件,多表關聯造成笛卡爾積查詢,最終導致隊列資源占滿,該隊列上的作業運行失敗。
例如,如下問題SQL語句,存在三個表的left join,并且沒有指定on條件,造成笛卡爾積查詢。
select
case
when to_char(from_unixtime(fs.special_start_time), 'yyyy-mm-dd') < '2018-10-12' and row_number() over(partition by fg.goods_no order by fs.special_start_time asc) = 1 then 1
when to_char(from_unixtime(fs.special_start_time), 'yyyy-mm-dd') >= '2018-10-12' and fge.is_new = 1 then 1
else 0 end as is_new
from testdb.table1 fg
left join testdb.table2 fs
left join testdb.table3 fge
where to_char(from_unixtime(fs.special_start_time), 'yyyymmdd') = substr('20220601',1,8)
解決措施
在使用join進行多表關聯查詢時,不管表數據量大小,join時都需要指定on條件來減少多表關聯的數據量,從而減輕隊列的負荷,提升查詢效率。
例如,問題現象中的問題語句可以根據業務場景,在join時通過指定on條件來進行優化,這樣會極大減少關聯查詢的結果集,提升查詢效率。
select
case
when to_char(from_unixtime(fs.special_start_time), 'yyyy-mm-dd') < '2018-10-12' and row_number() over(partition by fg.goods_no order by fs.special_start_time asc) = 1 then 1
when to_char(from_unixtime(fs.special_start_time), 'yyyy-mm-dd') >= '2018-10-12' and fge.is_new = 1 then 1
else 0 end as is_new
from testdb.table1 fg
left join testdb.table2 fs on fg.col1 = fs.col2
left join testdb.table3 fge on fg.col3 = fge.col4
where to_char(from_unixtime(fs.special_start_time), 'yyyymmdd') = substr('20220601',1,8)
手動在OBS表的分區目錄下添加了數據,但是無法查詢到該部分數據
問題現象
手動在OBS表的分區目錄下上傳了分區數據,但是在SQL編輯器中查詢該表新增的分區數據時卻查詢不到。
解決方案
手動添加分區數據后,需要刷新OBS表的元數據信息。具體操作如下:
MSCK REPAIR TABLE table_name ;
執行完上述命令后,再執行對應OBS分區表的數據查詢即可。
為什么insert overwrite覆蓋分區表數據的時候,覆蓋了全量數據?
如果需要動態覆蓋DataSource表指定分區數據,需要先配置參數:dli.sql.dynamicPartitionOverwrite.enabled=true,再通過“insert overwrite”語句實現,“dli.sql.dynamicPartitionOverwrite.enabled”默認值為“false”。
為什么SQL作業一直處于“提交中”?
SQL作業一直在提交中,有以下幾種可能:
- 剛購買DLI隊列后,第一次進行SQL作業的提交。需要等待5~10分鐘,待后臺拉起集群后,即可提交成功。
- 若剛剛對隊列進行網段修改,立即進行SQL作業的提交。需要等待5~10分鐘,待后臺重建集群后,即可提交成功。
- 按需隊列,已空閑狀態(超過1個小時)。后臺資源已經釋放。此時進行SQL作業的提交。需要等待5~10分鐘,待后臺重新拉起集群后,即可提交成功。
跨源連接RDS表中create_date字段類型是datetime,為什么dli中查出來的是時間戳呢?
Spark中沒有datetime數據類型,其使用的是TIMESTAMP類型。
您可以通過函數進行轉換。
例如:
select cast(create_date as string), * from
table where create_date>'2221-12-01 00:00:00';
SQL作業執行完成后,修改表名導致datasize修改失敗怎么辦?
如果執行SQL后立即修改了表名,可能會導致表的數據大小結果不正確。
如需修改表名,建議在SQL作業執行完成后,間隔5分鐘再修改表名。
從DLI導入數據到OBS,為什么數據量出現差異?
問題現象
使用DLI插入數據到OBS臨時表文件,數據量有差異。
根因分析
出現該問題可能原因如下:
- 作業執行過程中,讀取數據量錯誤。
- 驗證數據量的方式不正確。
通常在執行插入數據操作后,如需確認插入數據量是否正確,建議通過查詢語句進行查詢。
如果OBS對存入的文件數量有要求,可以在插入語句后加入“DISTRIBUTE BY number”。例如,在插入語句后添加“DISTRIBUTE BY 1”,可以將多個task生成的多個文件匯總為一個文件。
操作步驟
1.在管理控制臺檢查對應SQL作業詳情中的“結果條數”是否正確。 檢查發現讀取的數據量是正確的。
2.確認客戶驗證數據量的方式是否正確。客戶驗證的方式如下:
a.通過OBS下載數據文件。
b.通過文本編輯器打開數據文件,發現數據量缺失。
根據該驗證方式,初步定位是因為文件數據量較大,文本編輯器無法全部讀取。
通過執行查詢語句,查詢OBS數據進一步進行確認,查詢結果確認數據量正確。
因此,該問題為驗證方式不正確造成。