2009-05-13 8 views
5

मेरे पास एक प्रश्न है जो कई तरीकों से रहता है (क्वेरी) जिसमें से कई पैरामीटर हो सकते हैं। मैं इसे अधिक रखरखाव करने के लिए फ़ाइल आकार और रेखा गणना को कम करने की कोशिश कर रहा हूं। नीचे इस तरह के एक घटना है:मैं पर्ल में एकाधिक डेटाबेस प्रश्नों को और अधिक कुशल कैसे बना सकता हूं?

$sql_update = qq { UPDATE database.table 
        SET column = 'UPDATE!' 
        WHERE id = ? 
       }; 

$sth_update = $dbh->prepare($sql_update); 

if ($dbh->err) { 
    my $error = "Could not prepare statement. Error: ". $dbh->errstr ." Exiting at line " . __LINE__; 
    print "$error\n"; 
    die; 
} 

$sth_rnupdate->execute($parameter); 

if ($dbh->err) { 
    my $error = "Could not execute statement. Error: ". $dbh->errstr ." Exiting at line " . __LINE__; 
    print "$error\n"; 
    die; 
} 

यह वह जगह है सिर्फ एक उदाहरण, तथापि, वहाँ विभिन्न अन्य चुनिंदा उदाहरण है कि सिर्फ एक पैरामीटर में पारित होने के लिए होते हैं लेकिन वहाँ भी दो या अधिक पैरामीटर के साथ कुछ है कर रहे हैं। मुझे लगता है कि मैं बस सोच रहा हूं कि यह सब एक समारोह/विधि में encapsulate करना संभव होगा, पैरामीटर की एक सरणी में गुजरना, पैरामीटर निष्पादन() फ़ंक्शन में कैसे पॉप्युलेट किया जाएगा?

यदि यह संभव था तो मैं एक विधि लिख सकता हूं जिसे आप बस SQL ​​क्वेरी और पैरामीटर में पास करते हैं और प्राप्त रिकॉर्ड के संदर्भ में वापस आते हैं। क्या यह बिल्कुल सुरक्षित है?

उत्तर

6

यदि लाइन-गिनती और रखरखाव कोड आपका एकमात्र लक्ष्य है, तो आपकी सबसे अच्छी शर्त कई बेहतरीन ओआरएम ढांचे/पुस्तकालयों में से किसी एक का उपयोग करना होगा। Class::DBI और DBIx::Class दो ठीक शुरुआती बिंदु हैं। बस मामले में, आप इन मॉड्यूल को जानने के लिए अतिरिक्त समय बिताने के बारे में चिंतित हैं - नहीं: मुझे शुरू करने और उत्पादक बनाने के लिए बस एक दोपहर का समय लगा।

Table->retrieve(id => $parameter)->column('UPDATE!')->update; 

केवल नीचे की ओर (यदि हैं) इन चौखटे के कि बहुत जटिल SQL कथन आवश्यक लेखन कस्टम तरीकों सीखने जो आपको कुछ अतिरिक्त समय लग सकता है है: उदाहरण के लिए कक्षा :: DBI का उपयोग करते हुए अपने उदाहरण सिर्फ एक लाइन है चारों ओर पाने के लिए समय (बहुत ज्यादा नहीं)।

+0

यह बहुत फायदेमंद लगता है। कक्षा :: डीबीआई मॉड्यूल कोर पर्ल के साथ आता है? (यूनिक्स के लिए) –

+0

नहीं। आपको इसे इंस्टॉल करना होगा। "क्लास :: डीबीआई इंस्टॉल करें" टाइप करना और एक सीपीएएन खोल के अंदर सभी निर्भरताओं के लिए 'वाई' के साथ प्रतिक्रिया देना आपके लिए इसे इंस्टॉल करेगा। –

2

"निष्पादन" फ़ंक्शन आपके सभी पैरामीटर वाले सरणी को स्वीकार करता है।

तुम सिर्फ एक रास्ता इंगित करने के लिए जो बयान संभाल आप निष्पादित करने के लिए चाहते हैं और आपका काम हो खोजने के लिए है ...

यह बहुत बेहतर होगा अपने बयान कहीं संभालती रखने के लिए क्योंकि अगर आप एक नया बना हर बार जब आप वास्तव में "तैयार" के लाभों को पोंछते नहीं हैं ...

सभी पंक्तियों को वापस करने के बारे में आप ऐसा कर सकते हैं (कुछ "fetchrow_hashref push" के दौरान) बड़े परिणाम सेट से सावधान रहें coudl अपनी सारी याददाश्त खाओ!

+0

मैं देख रहा हूं कि आप क्या कह रहे हैं - मुझे इसे थोड़ा सा पता लगाना होगा। मेरे सभी बयान उपरोक्त निर्दिष्ट कोड की नकल करते हैं, लेकिन एकमात्र चीज जो विविध है वह पैरामीटर और कथन स्वयं ही है। –

2

यहाँ एक सरल बंद का उपयोग कर दृष्टिकोण/कीवर्ड नाम से एक हैश में संग्रहीत गुमनाम बाद के चरणों (compiles, लेकिन नहीं अन्यथा का परीक्षण), RaiseError का उपयोग शामिल करने के लिए संपादित है:

# define cached SQL in hash, to access by keyword 
# 
sub genCachedSQL { 
    my $dbh = shift; 
    my $sqls = shift; # hashref for keyword => sql query 
    my %SQL_CACHE; 
    while (my($name,$sql) = each %$sqls) { 
    my $sth = $dbh->prepare($sql); 
    $SQL_CACHE{$name}->{sth} = $sth; 

    $SQL_CACHE{$name}->{exec} = sub { # closure for execute(s) 
     my @parameters = @_; 
     $SQL_CACHE{$name}->{sth}->execute(@parameters); 

     return sub { # closure for resultset iterator - check for undef 
      my $row; eval { $row = $SQL_CACHE{$name}->{sth}->fetchrow_arrayref(); }; 
      return $row; 
     } # end resultset closure 

    } # end exec closure 

    } # end while each %$sqls 

    return \%SQL_CACHE; 

} # end genCachedSQL 


my $dbh = DBI->connect('dbi:...', { RaiseError => 1 }); 

# initialize cached SQL statements 
# 
my $sqlrun = genCachedSQL($dbh, 
{'insert_table1' => qq{ INSERT INTO database.table1 (id, column) VALUES (?,?) }, 
    'update_table1' => qq{ UPDATE database.table1 SET column = 'UPDATE!' WHERE id = ? }, 
    'select_table1' => qq{ SELECT column FROM database.table1 WHERE id = ? }}); 

# use cached SQL 
# 
my $colid1 = 1; 
$sqlrun->{'insert_table1'}->{exec}->($colid1,"ORIGINAL"); 
$sqlrun->{'update_table1'}->{exec}->($colid1); 
my $result = $sqlrun->{'select_table1'}->{exec}->($colid1); 
print join("\t", @$_),"\n" while(&$result()); 

my $colid2 = 2; 
$sqlrun->{'insert_table1'}->{exec}->($colid2,"ORIGINAL"); 

# ... 
+0

यह उत्कृष्ट है। मैं थोड़ी देर बाद इस समाधान को लागू करने की कोशिश करूंगा और आपको बताऊंगा कि मैं कैसे चल रहा हूं। –

+1

योगदान करने में खुशी हुई - निश्चित रूप से यह सुनिश्चित करना सुनिश्चित करें कि कैसे खराब निष्पादन परीक्षण मामलों के लिए eval व्यवहार करता है – bubaker

+0

त्वरित प्रश्न बुबेकर, इस क्वेरी ने fetchall_arrayref() निष्पादित किया जिसके परिणामस्वरूप सभी रिकॉर्ड्स प्राप्त हुए, जो समस्याग्रस्त है क्योंकि मेरी क्वेरी वापस आ रही है औसतन 9 कॉलम के औसत के साथ 300,000 रिकॉर्ड के अतिरिक्त। क्या इस क्वेरी को fetchrow_arrayref() या fetchrow_hashref का उपयोग व्यक्तिगत रिकॉर्ड के माध्यम से करने के लिए करने का कोई तरीका है? –

1

मैं bubaker के साथ बहुत प्रभावित हूँ इसके लिए बंद करने का उदाहरण।

बस वही, यदि मूल लक्ष्य को कोड-बेस को छोटे और अधिक रखरखाव करने के लिए किया गया था, तो मैं सोचने में मदद नहीं कर सकता कि मूल कोड से बहुत सारे शोर भीख को हटाया जा सकता है, इससे पहले कि कोई रूपांतरण पर उतरे सीडीबीआई या डीबीआईसी आदि के लिए (दोनों महान पुस्तकालयों के बावजूद वे दोनों हैं।)

$dbh विशेषताओं में RaiseError सेट के साथ instantiated किया गया था, तो उस कोड के सबसे दूर चला जाता है:

$sql_update = qq { UPDATE database.table 
        SET column = 'UPDATE!' 
        WHERE id = ? 
       }; 
$sth_update = $dbh->prepare($sql_update); 
$sth_update->execute($parameter); 

मैं नहीं देख सकता है कि मूल कोड में से निपटने त्रुटि है कि आप ज्यादा जोड़ रहा है RaiseError द्वारा उत्पादित वेनिला die से नहीं मिलेगा, लेकिन यदि यह महत्वपूर्ण है, तो मैनपेज में HandleError विशेषता देखें।

इसके अलावा, अगर ऐसे कथनों का पुन: उपयोग नहीं किया जा रहा है (जो अक्सर उन्हें तैयार करने का मुख्य उद्देश्य होता है, तो कैश करने के लिए उन्हें कैसे अनुकूलित किया जाता है; दूसरा कारण प्लेसहोल्डर्स का उपयोग करके एसक्यूएल इंजेक्शन के खिलाफ कम करना है), तो क्यों नहीं do का उपयोग करें?

$dbh->do($sql_update, \%attrs, @parameters); 
4

प्रत्येक डेटाबेस कॉल के बाद त्रुटियों की जांच करने में कोई समझ नहीं है। कितना थकाऊ!

इसके बजाय, जब आप डेटाबेस से कनेक्ट होते हैं, तो RaiseError विकल्प को सत्य पर सेट करें। फिर यदि कोई डेटाबेस त्रुटि उत्पन्न होती है, तो एक अपवाद फेंक दिया जाएगा। यदि आप इसे नहीं पकड़ते हैं (एक eval {} ब्लॉक में), तो आपका प्रोग्राम एक संदेश के साथ मर जाएगा, जैसा कि आप मैन्युअल रूप से ऊपर कर रहे थे।

संबंधित मुद्दे