使用shell並行執行多個指令碼
阿新 • • 發佈:2019-01-10
有沒有一種比較通用的並行執行多個SQL指令碼的方法呢?每種資料庫都提供命令列介面執行SQL語句,因此最容易想到的就是通過初始化多個併發的會話並行執行,每個會話執行一個單獨的查詢,用來抽取不同的資料部分。以Oracle例如,假設要從訂單表抽取資料,訂單表已經是按月做了範圍分割槽,分割槽名稱是orders_jan2008、orders_feb2008等。要從訂單表抽取一年的資料,可以初始化12個併發的SQL*Plus會話,每個抽取一個分割槽。每個會話執行的SQL指令碼應該類似:
並行抽取一個複雜的SQL查詢有時是可行的,儘管將一個單一查詢分成多個部分可能是一個挑戰。在並行模式下,協調多個獨立的程序,保證一個整體一致的檢視可能是非常困難的。而且所有並行技術都會使用更多的CPU和I/O資源,因此在執行任何並行抽取技術前需要評估對系統性能的影響。我們應該控制併發程序的個數,不然會影響系統其它程序的執行。
這12個SQL*Plus程序將並行匯出資料到12個檔案。如果需要,還可以在抽取後使用作業系統命令將12個檔案合併起來(如Linux的cat命令)。即使訂單表沒有分割槽,仍然可以基於邏輯條件執行並行抽取。邏輯方法是基於列值的邏輯範圍,例如:spool order_jan.dat select * from orders partition (orders_jan2008); spool off
select ... where order_date
between to_date('2008-01-01','yyyy-mm-dd') and to_date('2008-01-31','yyyy-mm-dd');
通過簡單的shell指令碼,可以從命令列接收並行度引數,使這些呼叫並行執行。a.sql檔案內容如下:#!/bin/bash export NLS_LANG=american_america.AL32UTF8 for(( i = 0; i < $1; i++ )) do { sqlplus user1/password1 << ! start a.sql exit; ! cat ./result.lst >> aa.txt } & done wait date
set echo off;
set heading off;
set line 1000;
set pagesize 0;
set numwidth 12;
set termout off;
set trimout on;
set trimspool on;
set feedback off;
set timing off;
spool result.lst
select * from mytable;
spool off
指令碼中使用了&符號,使得{}內的命令在後臺並行執行,並將每次生成的文字檔案result.lst合併到一個新的檔案aa.txt中。等到迴圈裡面的命令都結束之後才執行接下來的date命令。用這個示例說明並行執行多個SQL指令碼檔案(這裡多次執行同一個檔案a.sql,當然實際中應該是多個不同的SQL檔案)。mytable表有57606行記錄,如果執行兩次,檔案中應該有115212行記錄。[ [email protected] ~]$ ./a.sh 2
...
[[email protected] ~]$ cat result.lst | wc -l
57606
[[email protected] ~]$ cat aa.txt | wc -l
115212
換做MySQL資料庫,整體思路是一樣的,只要把sqlplus換成mysql客戶端,再針對MySQL的語法做相應的修改即可。並行抽取一個複雜的SQL查詢有時是可行的,儘管將一個單一查詢分成多個部分可能是一個挑戰。在並行模式下,協調多個獨立的程序,保證一個整體一致的檢視可能是非常困難的。而且所有並行技術都會使用更多的CPU和I/O資源,因此在執行任何並行抽取技術前需要評估對系統性能的影響。我們應該控制併發程序的個數,不然會影響系統其它程序的執行。