1

数日前、EMC マス ファイラー上の多数のファイルを処理するスクリプトで問題が発生しました。ここに私の作業コードがあります

unset xP_Array
declare -a xP_Array
...
export LOG=$HOME/BIN/somelogfile
export OUT=/path/to/device
...
echo "`date '+%m/%d/%y %T:'` START -- MEM"                          >> $LOG

echo "`date '+%m/%d/%y %T:'` Go to work directory."                                              >> $LOG
cd ${OUT}

echo "`date '+%m/%d/%y %T:'` Fill the array."                                                   >> $LOG
for f in "$OUT"/*XML; do
    xP_Array+=( "${f#$OUT/}" )
done
echo "`date '+%m/%d/%y %T:'` Get array length."                                               >> $LOG
Plen=${#xP_Array[@]}

echo "`date '+%m/%d/%y %T:'` MEM: $Plen FILES TO PROCESS."                                      >> $LOG

echo "`date '+%m/%d/%y %T:'` Check if zero files."                                               >> $LOG
date_fmt='%m/%d/%y %T'
if (( Plen = 0 ))
then
    printf "%($date_fmt)T: ZERO FILES\n" $(date +%s)                                            >> $LOG
fi

echo "`date '+%m/%d/%y %T:'` Loop."                                                             >> $LOG
for i in "${xP_Array[@]}"
do
        echo "`date '+%m/%d/%y %T:'` Move file to run directory."                              >> $LOG
        mv $OUT/$i RUN/
        echo "`date '+%m/%d/%y %T:'` PROCESSING "$i"."                                          >> $LOG
        [[[DATABASE LOAD DONE HERE]]]
        echo "`date '+%m/%d/%y %T:'` Check DB LOAD return value."                                       >> $LOG
        EXIT=`echo $?`
        case $EXIT in
                0) echo "`date '+%m/%d/%y %T:'` COMPLETE."                                      >> $LOG
                mv RUN/"$i" "$ARCH"
                ;;
                *) echo "`date '+%m/%d/%y %T:'` ERROR. "$i" MOVED TO RECON."                    >> $LOG
                mv RUN/"$i" "$RECON"
                ;;
        esac
done

echo "`date '+%m/%d/%y %T:'` END -- MEM"                                    >> $LOG

それがより速く動作することができるかどうか疑問に思います。私はすでに DBA と協力して、データベースの挿入を高速化できるかどうかを確認していますが、ループ自体を高速に実行できるかどうか疑問に思っています。

ところで、すべてのechoステートメントはログ ファイルにリダイレクトされ、スクリプトの完了時に自分自身に電子メールで送信します。彼らはスクリプトを遅くしていますか?

このスクリプトを最適化して実行速度を上げることはできますか?

4

2 に答える 2

2

ここで私が考えることができるのはecho "date...ステートメントとCASEステートメントだけですが、それらの実行時間は実際にはごくわずかであるはずです。ここでは、bashスクリプトの微調整に時間を費やすよりも、SQLの調整に集中します。スクリプトで本当に何かをしたい場合は、@chepnerがすでに述べたヒントを使用できます。

もう1つの方法は、ファイル形式が同じである場合、すべてのファイルをマージするか、一度に100個のファイルをファイルとしてマージしてから、マージされたCSVファイルを使用して外部テーブルCSVをロードすることです。次に、外部テーブルを使用して実際のテーブルをロードできます。外部テーブルを使用して一度に1つのファイルでこれを開始し、パフォーマンスの違いがどの程度観察されるかを確認できます。

外部テーブルは、データファイル(適切にフォーマットされている場合)に関しては非常に便利なソリューションです。文字通り必要がないINSERTか、DELETE労力が必要ないためです。データファイルが指定されたディレクトリにある場合は、テーブル内にデータがあります。データファイルが存在しない場合、SELECTテーブルでを発行するとエラーが発生し、log簡単に処理できるいくつかのファイルが生成されます)。

于 2012-09-07T22:02:47.197 に答える
1
for f in "$OUT"/*XML; do
    xP_Array+=( "${f#$OUT/}" )
done

で置き換えることができます

pushd "$OUT"
xP_Array=( *XML )
popd

しかし、それがあなたのスクリプトの大きなボトルネックだとは思いません。

あなたの他のループでは、私が目にする唯一の実際のオーバーヘッドは、コマンド置換を繰り返し呼び出してEXITdateに割り当てることです。$?これは直接実行できます ( EXIT=$?)。実際の DB 負荷以外に最適化するものはないと思います。

人間が読める日付から切り替える場合は、現在の時刻を (UNIX タイムスタンプとして) に割り当て、SECONDSを呼び出す代わりに、ログ行のその変数を参照するだけで済みますdate

SECONDS=$(date +%s)
for i in "${xP_Array[@]}"
do
    echo "$SECONDS: Move file to run directory." >> $LOG
    # etc
done

十分に新しいbash(4.2以降だと思います)を使用するとprintf、UNIXタイムスタンプを読み取り可能な時間としてフォーマットできます。

printf "%(%m/%d/%Y %T)T" $SECONDS
于 2012-09-07T21:03:04.677 に答える