2014-12-22 35 views
0

我有這個perl腳本,它從sqlplus數據庫中獲取數據......每當某個特定序列的狀態值發生變化時,此數據庫就會添加一個新條目數。現在我們需要在每次狀態變化時選擇條目,並準備一個具有舊狀態,新狀態和其他字段的csv文件。數據庫表示例。如何提高perl腳本的使用sqlplus的效率

SERIALNUMBER   STATE    AT      OPERATORID SUBSCRIBERID TRANSACTIONID 
51223344558899  Available   20081008T10:15:47   vsuser 
51223344558857  Available   20081008T10:15:49   vsowner 
51223344558899  Used     20081008T10:20:25   vsuser 
51223344558860  Stolen    20081008T10:15:49   vsanyone 
51223344558857  Damaged    20081008T10:50:49   vsowner 
51223344558899  Damaged    20081008T10:50:25   vsuser 
51343253335355  Available   20081008T11:15:47   vsindian 

我的腳本:

#! /usr/bin/perl 

#use warnings; 
use strict; 


#my $circle = 
#my $schema = 
my $basePath = "/scripts/Voucher-State-Change"; 

#my ($sec, $min, $hr, $day, $month, $years) = localtime(time); 
#$years_+=1900;$mont_+=1; 
#my $timestamp=sprintf("%d%02d%02d",$years,$mont,$moday); 


sub getDate { 
    my $daysago=shift; 
    $daysago=0 unless ($daysago); 
    #my @months=qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec); 
    my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time-(86400*$daysago)); 
    # YYYYMMDD, e.g. 20060126 
    return sprintf("%d%02d%02d",$year+1900,$mon+1,$mday); 
    } 

my $filedate=getDate(1); 
#my $startdate="${filedate}T__:__:__"; 
my $startdate="20081008T__:__:__"; 
print "$startdate\n"; 


##### Generating output file--- 
my $outputFile = "${basePath}/VoucherStateChangeReport.$filedate.csv"; 
open (WFH, ">", "$outputFile") or die "Can't open output file $outputFile for writing: $!\n"; 
print WFH "VoucherSerialNumber,Date,Time,OldState,NewState,UserId\n"; 



##### Generating log file--- 
my $logfile = "${basePath}/VoucherStateChange.$filedate.log"; 
open (STDOUT, ">>", "$logfile") or die "Can't open logfile $logfile for writing: $!\n"; 
open (STDERR, ">>", "$logfile") or die "Can't open logfile $logfile for writing: $!\n"; 
print "$logfile\n"; 

##### Now login to sqlplus----- 
my $SQLPLUS='/opt/oracle/product/11g/db_1/bin/sqlplus -S system/[email protected]'; 
`$SQLPLUS \@${basePath}/VoucherQuery1.sql $startdate> ${basePath}/QueryResult1.txt`; 


open (FH1, "${basePath}/QueryResult1.txt"); 

while (my $serial = <FH1>) { 
    chomp ($serial); 
    my $count = `$SQLPLUS \@${basePath}/VoucherQuery2.sql $serial $startdate`; 
    chomp ($count); 
    $count =~ s/\s+//g; 
    #print "$count\n"; 
    next if $count == 1; 

    `$SQLPLUS \@${basePath}/VoucherQuery3.sql $serial $startdate> ${basePath}/QueryResult3.txt`; 

# print "select * from sample where SERIALNUMBER = $serial----\n"; 
    open (FH3, "${basePath}/QueryResult3.txt"); 


    my ($serial_number, $state, $at, $operator_id); 
    my $count1 = 0; 
    my $old_state; 
    while (my $data = <FH3>) { 
      chomp ($data); 
        #print $data."\n"; 
      my @data = split (/\s+/, $data); 
      my ($serial_number, $state, $at, $operator_id) = @data[0..3]; 
      #my $serial_number = $data[0]; 
      #my $state = $data[1]; 
      #my $at = $data[2]; 
      #my $operator_id = $data[3]; 


      $count1++; 
      if ($count1 == 1) { 
       $old_state = $data[1]; 
       next; 
       } 

      my ($date, $time) = split (/T/, $at); 
      $date =~ s/(\d{4})(\d{2})(\d{2})/$1-$2-$3/; 

      print WFH "$serial_number,$date,$time,$old_state,$state,$operator_id\n"; 
      $old_state = $data[1]; 
      } 
     } 
close(WFH); 

查詢在VoucherQuery1.sql:

select distinct SERIALNUMBER from sample where AT like '&1'; 

查詢在VoucherQuery2.sql:

select count(*) from sample where SERIALNUMBER = '&1' and AT like '&2'; 

查詢在VoucherQuery2.sql:

select * from sample where SERIALNUMBER = '&1' and AT like '&2'; 

和我的樣本輸出:

VoucherSerialNumber,Date,Time,OldState,NewState,UserId 
51223344558857,2008-10-08,10:50:49,Available,Damaged,vsowner 
51223344558899,2008-10-08,10:20:25,Available,Used,vsuser 
51223344558899,2008-10-08,10:50:25,Used,Damaged,vsuser 

腳本工作相當精細。但問題是,實際的數據庫表在特定的一天中有數百萬條記錄...因此它正在提高性能問題......請您告訴我們如何提高此腳本在時間&負載方面的效率。唯一的限制是,我不能使用DBI模塊... 同樣在sql查詢中出現任何錯誤的情況下,錯誤消息會傳到QueryResult?.txt文件。我想在我的日誌文件中處理並接收這些錯誤。這是如何實現的?謝謝

+2

在數據庫中進行處理和結果構建似乎是最有效的,並且可以直接將結果轉儲到文件中,而完全繞過Perl中的結果處理。使用存儲過程。 – reinierpost

+0

感謝您的回覆..但我有點新手在存儲過程..同時我已經取代了前兩個查詢「選擇不同的SERIALNUMBER從(選擇d。*,count(*)over(由SERIALNUMBER分區)cnt從樣本d )其中cnt> 1;「並顯示改善... – user2611539

回答

0

我認爲你需要調整你的查詢。如果是Oracle數據庫,那麼使用EXPLAIN PLAN是一個很好的起點。