問題描述
Sparksql提供外接關係型數據庫的接口如下,
def jdbc(
url: String,
table: String,
columnName: String,
lowerBound: Long,
upperBound: Long,
numPartitions: Int,
connectionProperties: Properties): DataFrame
從上述接口可知,columnName列必須是整形類型,在現實使用場景中,並不一定總是存在整形列,且表中的整形列值如果不是分佈均勻的話,很容易就會出現數據傾斜現象。
如果不使用上述接口,而是使用如下
def jdbc(url: String, table: String, properties: Properties): DataFrame
便存在性能問題,即僅有一個task去讀取oracle中的數據
解決方法
Oracle存在兩個僞列:rownum、rowid。僞劣,即表中不存在的列。Rownum是邏輯存在的、整形列,且是自增的。Rowid是物理存在的,其值是一串隨機數,表徵該記錄的位置。
Rownum在select語句中,會對查詢結果集進行編號,利用這個特點,我們可以利用sparksql jdbc接口去實現分佈式多任務去讀取oracle數據,具體思路如下:
- select max(rownum) ,min(rownum) from
表名1
,查找最大序列號、最小序列號。 - 預定義一個task處理多少條記錄,然後對上述的max、min區間進行等值劃分,得出並行度,即上述接口中的numPartitions變量值。
- dataFrame = sqlContext.read.jdbc(url, select
表名1
.*, rownum from表名1
, rownum, minValue, maxValue, numPartitions, prop) - 丟棄“邏輯列”drop(rownum)