几天前,我的脚本处理了我们的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
语句都被重定向到一个日志文件,我在脚本完成时自己发送电子邮件。他们放慢了脚本的速度吗?
可以优化此脚本以更快地运行吗?
答案 0 :(得分:2)
我在这里唯一能想到的是echo "date...
语句和CASE
语句,但这些语句的执行时间应该可以忽略不计。我会集中精力调整SQL,而不是花时间在这里微调bash脚本。如果您真的想在脚本中执行某些操作,可以使用@chepner提到的提示。
另一种方式是,如果您的文件格式相同,那么您可以合并所有文件,或者一次合并100个文件作为CSV
文件,然后使用合并的CSV
文件加载External Tables。然后,您可以使用外部表加载实际表。您可以使用外部表一次一个文件开始执行该操作,并查看观察到的性能差异。
对于数据文件(如果格式正确),外部表是非常方便的解决方案,因为如果数据文件存在于指定目录中,则根本不需要INSERT
和/或DELETE
工作您将在表中找到您不会发现的数据(如果数据文件不存在,在表上发出SELECT
将导致错误并生成一些log
文件,这些文件很容易处理)。
答案 1 :(得分:1)
for f in "$OUT"/*XML; do
xP_Array+=( "${f#$OUT/}" )
done
可以替换为
pushd "$OUT"
xP_Array=( *XML )
popd
但我不认为这是你剧本中的一大瓶颈。
在你的另一个循环中,我看到的唯一真正的开销是重复调用date
和
使用命令替换将$?
分配给EXIT,这可以直接完成(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