天天看點

性能優化技巧 - 程式遊标

很多算法都會産生落地的中間結果,進而影響性能,尤其是資料量較大的時候。這種情況下通常可用程式遊标來避免資料落地,下面舉例說明。

前半排序

計算目标:訂單表原來已按時間排序,需要将資料按日期、産品去除重複,再統計記錄條數。

由于去重後結果集較大,記憶體放不下,是以一般會用groupx去重,SPL腳本如下:

性能優化技巧 - 程式遊标

A2:循環訂單表。由于資料已按時間排序,是以每次取日期相同的一批數。

B2:按産品去重。注意,全量資料雖大,但按天取數相對較少,記憶體可以放下,是以這裡用id去重。

B3:傳回本批次的去重結果。注意,程式遊标并非一次性傳回所有資料,而是每次循環之後,先等待調用者的請求,如果調用者繼續要資料,程式遊标才會進行下一次循環,期間資料不落地。

主程式可通過cursor函數調用程式遊标,用法與普通遊标類似:

性能優化技巧 - 程式遊标

  可以看到,程式遊标可減少資料落地,進而提升計算性能。

 集合運算

資料庫進行集合運算時要先排序,如果資料量太大,則排序會耗費大量時間,遲遲不能輸出結果。在這種情況下,适合用程式遊标生成不落地的有序中間結果集,進而實作快速輸出。

比如兩張結構相同表:callRecordA、callRecordB。兩張表在時間字段callTime上建立了索引,每秒資料量萬級,現在對2015-01-01這一天的資料做并集運算,需要快速輸出前500條(比如在報表上快速呈現)。

這次将程式遊标和調用代碼寫在同一個腳本中,如下:

性能優化技巧 - 程式遊标

A1:用func定義程式遊标,相應的調用文法為cursor@c。

B2:循環一天中的每一秒。

C3:從資料庫查詢一秒的資料,因為是按索引取數,是以速度很快,而且對資料庫影響很小。注意A1是表名變量,程式遊标既可以從callRecordA取數,也可以從callRecordB取數。

C4:對一秒資料進行記憶體排序,以便形成有序結果集。由于資料在同一秒,是以隻需對其他字段排序。

A7A8:以表名為參數,取出2個程式遊标。

A9:對兩個遊标進行有序歸并,@u表示取并集。類似地,可以用@i和@d分别進行并交集、差集運算。