你今天高效率了嗎 ? 高效思考 聰明使用 SAS – SAS Sort Information
目錄
前言
以 SAS 排序資料我們會想到 SORT procedure 或者 SQL procedure 的 ORDER BY,但是很少人會想到如果是「排序過的資料」又該如何處理。以下介紹 SAS 隱藏的技巧,對大量數據排序極為有用的 Sort Information。
什麼是排序資訊 (Sort Information) ?
SAS 在以 Sort procedure 或 SQL procedure with ORDER BY 執行排序之後,會生成排序資訊 (Sort Information),這個資訊告訴我們資料的排序依據 (Sortedby) 以及排序是否已驗證 (Validated)。
這個隱藏資訊可利用 Contents procedure 呼叫出來,例如:
proc sort data=sashelp.cars out=cars;
by Make EngineSize;
run;
proc contents data=cars; run;

說明:
1. proc sort → 排序
2. proc contents → 請 SAS 提供排序資訊 (Sort Information)
↑↑↑ 由 Contents procedure 的結果可知,排序依據是汽車製造商 (Make) 及排氣量 (EngineSize) 排序,且由 SAS 所驗證。
為何需要排序資訊 ?
SAS 在排序資料時,可粗略分為三個步驟:
- 讀取資料
- 產生中繼檔案 (暫存資料) 以排序資料
- 輸出排序好的資料
這裡注意到 SAS 需額外的空間來暫存資料,以經驗法則來說,排序一個資料大約需要原本資料大小的四倍空間,因此我們常說排序快慢與系統的硬碟空間、記憶體大小有密切關係。然而,當資料量很大時,如何減少排序所需要耗費的資源就很重要,尤其是避免不必要的排序,例如一組數據已經排序過了。
排序資訊如何幫助我們提高效率 ?
對 SAS 來說,任何「需要排序資料才可以執行」的程序,SAS 都會檢查排序資訊。經由排序資訊所提供的資訊,確認某個變項確實已排序,SAS 就會跳過排序的步驟,大幅節省系統資源 (CUP time 及 I/O)、提高工作效率。
我們以虛擬資料,比較三種常見的情況,實際測試看看排序資訊如何發揮高效率。
假如今天有一億筆的門診資料,在外部或 input data 時已排序過 (然而 SAS 並不知道),以 id 為合併鍵值時:
狀況一:不使用 Sort (SAS 認為資料未排序)
data outpatient;
do id=1 to 100000000;
output;
end;
run;
proc sql;
create table nosort as
select a.*
from outpatient a, outpatient b
where a.id=b.id;
quit;
NOTE: 已建立表格 WORK.NOSORT,該表格包含 100000000 列和 1 欄。
NOTE: 已使用 SQL Statement (總處理時間):
實際時間 54.14 秒
CPU 時間 53:25 秒
proc contents data=outpatient; run;

↑↑↑在沒有使用排序的情況下,儘管資料本身已排序過,對 SAS 來說資料仍然是末排序的。因此已排序的部分顯示為「NO」。
已排序 → NO
已驗證 → NO
以 SQL procedure 執行合併耗時: 54.14 秒
狀況二:使用 SORTEDBY= option (告訴 SAS 資料已排序)
data outpatient2 (sortedby= id);
do id=1 to 100000000;
output;
end;
run;
proc sql;
create table sortedby as
select a.*
from outpatient a, outpatient b
where a.id=b.id;
quit;
NOTE: 已建立表格 WORK.SORTEDBY,該表格包含 100000000 列和 1 欄。NOTE: 已使用 SQL Statement (總處理時間):
實際時間 34.89 秒
CPU 時間 33.51 秒
proc contents data=outpatient2; run;


說明:
sortedby=id → 在建立資料或匯入資料時,告訴 SAS 變項 ID 已經排序過了
↑↑↑Contents 程序顯示資料已排序,且排序的依據為 id。這裡要注意的是,雖然經由 SORTEDBY= option,已排序的資訊由「NO」轉為「YES」,然而已驗證的部分仍然為「NO」,這是因為 SAS 尚未確認資料是否真的已排序。
已排序 → YES
已驗證 → NO
以 SQL procedure 執行合併耗時: 34.89 秒
狀況三:使用 SORTEDBY= option & PRESORTED option (告訴 SAS 資料已排序、已驗證)
data outpatient3 (sortedby= id);
do id=1 to 100000000;
output;
end;
run;
proc sort data=outpatient3 presorted out=outpatient3;
by id;
run;
proc sql;
create table sortedby as
select a.*
from outpatient3 a, outpatient3 b
where a.id=b.id;
quit;
NOTE: 已建立表格 WORK.SORTEDBY,該表格包含 100000000 列和 1 欄。NOTE: 已使用 SQL Statement (總處理時間):
實際時間 29.36 秒
CPU 時間 29.17 秒
proc contents data=outpatient3; run;


說明:
1. sortedby=id → 在建立資料或匯入資料時,告訴 SAS 變項 ID 已經排序過了
2. presorted → 告訴 SAS 變項 id 是排序過的資料且已驗證 (此 option 會抑制 Sort procedure 排序)
為了讓 SAS 知道資料已排序,且驗證資料已排序,可以利用 SORTEDBY= option 加上 PRESORTED option。如此一來,SAS 便不需再執行檢查資料是否真的排序過 (已驗證為 YES),可再節省執行程序的時間。
已排序 → YES
已驗證 → NO
以 SQL procedure 執行合併耗時: 29.36 秒
要點總結
- 任何需要執行排序的 SAS 程序都需要檢查排序資訊 (Sort Information)
- 如果可以確定某個變項事已事先排序過,在匯入資料時可利用 SORTEDBY option 告訴 SAS 資料已經排序過 (已排序由 NO 轉為 YES),即可跳過排序
- 加強 SAS 的效率,可結合 Sort procedure 的 PRESORTED option,告訴 SAS 資料確實已排序過,不需要再驗證
延伸閱讀
SAS 9.4 Language Reference: Sorted Data Sets, Sixth Edition
https://amadeus.co.uk/tips/using-the-presorted-option-with-proc-sort-in-sas-92/
根據內文~ 標題的”SAS” INFORMATION 是不是改成 “SORT” INFORMATION 更適合呢~~
已改成 sort information,感謝指教 😀