2009-07-10 25 views
15

मुझे एक विशाल तालिका को कस्टम एक्सएमएल फ़ाइल में बदलने के लिए एक कार्य दिया गया है। मैं इस नौकरी के लिए जावा का उपयोग करूँगा।विशाल तालिका से सभी रिकॉर्ड्स पुनर्प्राप्त करते समय ओओएम (स्मृति से बाहर) त्रुटि से कैसे बचें?

यदि मैं बस "ग्राहक से चुनें" जारी करता हूं, तो यह बड़ी मात्रा में डेटा लौटा सकता है जो अंततः ओओएम का कारण बनता है। मुझे आश्चर्य है, क्या एक तरीका है कि मैं उपलब्ध होने के तुरंत बाद रिकॉर्ड को संसाधित कर सकता हूं, और उसके बाद एसक्यूएल पुनर्प्राप्ति प्रक्रिया के दौरान स्मृति से रिकॉर्ड हटा सकता हूं?

--- पर 13 जुला 2009

संपादित मुझे मेरे सवाल का विस्तार से बता दें। मेरे पास 1 डीबी सर्वर और 1 एप्लीकेशन सर्वर है। जब मैं एप्लिकेशन में एक चुनिंदा क्वेरी जारी करता हूं, तो डेटा डीबी सर्वर से ऐप सर्वर तक यात्रा करेगा।

मुझे विश्वास है (अगर मैं गलत हूं तो मुझे सही करें) परिणामसेट को क्वेरी में सभी रिकॉर्ड प्राप्त होने तक प्रतीक्षा करने की आवश्यकता होगी। यहां तक ​​कि यदि हम 1000-रिकॉर्ड तालिका के लिए 4 के रूप में लाने का आकार सेट करते हैं, तो भी हम ऐप सर्वर की ढेर मेमोरी में 1000 रिकॉर्ड प्राप्त करते हैं, क्या यह सही है? प्राप्त आकार केवल/से डीबी सर्वर से राउंड ट्रिप की संख्या को प्रभावित करता है।

मेरा सवाल है कि ऐप सर्वर पर आने के तुरंत बाद उस 4 (या किसी भी संख्या) रिकॉर्ड पर प्रसंस्करण कैसे शुरू करें, और ऐप सर्वर में मेमोरी को खाली करने के लिए इसका निपटान करें?

+0

कौन सा एसक्यूएल सर्वर हो रहा है है आप उपयोग कर रहे हैं (यानी एमएस, ओरेकल, MySQL, आदि)? आप जो भी उपयोग कर रहे हैं उसके आधार पर इस मुद्दे को संभालने के विभिन्न तरीके हैं। –

+0

कृपया वह कोड दिखाएं जिसका उपयोग आप रिकॉर्ड्स को पुनर्प्राप्त करने के लिए करते हैं। यह स्पष्ट नहीं है कि आप बस उन पर फिर से चलते हैं, या उन्हें कुछ संग्रह में स्थानीय रूप से स्टोर करते हैं और फिर उस पर फिर से शुरू होते हैं। –

+0

मैं इस कार्य के लिए ओरेकल का उपयोग करने जा रहा हूं। मैंने अभी तक कोई कोड शुरू नहीं किया है, क्योंकि मैं अभी भी ऐसा करने का सबसे अच्छा तरीका खोज रहा हूं :) – janetsmith

उत्तर

4

मुझे लगता है कि आप this one रूप में एक ही समाधान का उपयोग कर सकते हैं। एक स्क्रोल करने योग्य परिणाम।

+1

धन्यवाद। यह भी एक संभावित समाधान है, हालांकि इस विधि के साथ, प्रति गोल यात्रा केवल 1 रिकॉर्ड (fetch आकार = 1)? – janetsmith

6

थोड़ी अधिक जानकारी के साथ मुझे एक और अधिक उपयोगी उत्तर मिल सकता है।

आप MySQL उपयोग कर रहे हैं:

stmt = conn.createStatement(java.sql.ResultSet.TYPE_FORWARD_ONLY, 
     java.sql.ResultSet.CONCUR_READ_ONLY); 
stmt.setFetchSize(Integer.MIN_VALUE); 

http://www.oracle.com/technology/tech/java/sqlj_jdbc/htdocs/jdbc_faq.html से:

java.util.Properties info = new java.util.Properties(); 
info.put ("user", "scott"); 
info.put ("password","tiger"); 
info.put ("defaultRowPrefetch","15"); 
getConnection ("jdbc:oracle:oci:@",info); 
+1

Integer.MIN_VALUE? वास्तव में? यह एक नकारात्मक संख्या है। क्या आप कुछ, 10, 100 या 1000 की तरह नहीं चाहते हैं? –

+0

मैं ओरेकल का उपयोग कर रहा हूं। आपका MySQL कोड मुझे एक अच्छी दिशा देता है :) – janetsmith

+0

+1 TYPE_FORWARD_ONLY इस मामले में डीबी के लिए एक महान संकेत है। फिर यह जेडीबीसी चालक पर निर्भर करता है अगर यह इसके साथ कुछ भी उपयोगी करता है। –

4

यदि आप जेडीबीसी का उपयोग कर रहे हैं तो आप एक रिसॉर्टसेट का उपयोग एक कर्सर के साथ कर सकते हैं जिसे आप एक समय में एक रिकॉर्ड के माध्यम से फिर से चलाते हैं। आपको यह सुनिश्चित करने की ज़रूरत है कि आप एक्सएमएल बनाने के लिए डीओएम का उपयोग करने के बजाए एक समय में एक फ़ाइल में अपने एक्सएमएल को एक रिकॉर्ड में लिख दें।

+1

एक्सएमएल पीढ़ी के संबंध में, मैंने पहले इसके बारे में सोचा है। मैं xml आउटपुट के लिए StAX का उपयोग करने जा रहा हूं (http://blogger.ziesemer.com/2007/06/xml- जनरेशन-in-java.html) – janetsmith

4

मेरे अनुभव से मैंने जो अंगूठा सीखा है, वह यह है कि आप डेटाबेस से अपने डेटा को अपने एप्लिकेशन सर्वर पर कभी भी नहीं लाते हैं। एक चीज जो आप कर सकते हैं वह आपके डेटा को पेज करने के लिए एक प्रक्रिया को लागू करना है।

आप लगभग 1000-5000 रिकॉर्ड वाले डेटा का एक पृष्ठ ला सकते हैं, उन्हें संसाधित कर सकते हैं, फिर अगले पृष्ठ के लिए डेटा प्राप्त कर सकते हैं।

+1

मैं इस विकल्प को दूसरा स्थान देता हूं। लेकिन इस मामले में उदाहरण सीमा अच्छी नहीं है। 1000 से 5000 कहें, इसे बड़ा बनाएं। फिर से लाना ज्यादा समय नहीं लगेगा, क्योंकि पहले से ही एक निष्पादन योजना उपलब्ध होगी। इसके अलावा, यह सभी डेटाबेस सर्वर के साथ काम करता है। –

+0

मुझे लगता है कि 10,000 से 50,000 या 100,000 भी काम कर सकते हैं। सुनिश्चित नहीं है कि एक पंक्ति का डेटा कितना बड़ा है। लेकिन 50,000 ठीक लगता है। इसे अपने आप आज़माएं। –

+0

@ विनीगर: सीमा संपादित की गई है। यह सब इस बात पर निर्भर करता है कि कितनी मेमोरी उपलब्ध है, और तालिका की सामग्री क्या है। लेकिन, मुझे लगता है कि 1000-5000 बेहतर है। – Kirtan

0

ओओएम त्रुटि होने पर कौन सा चरण होता है, क्या यह डेटा पुनर्प्राप्ति या एक्सएमएल फ़ाइल में डेटा प्रोसेसिंग पर है?

यदि इसका डेटा पुनर्प्राप्ति है, तो बैच में डेटा प्राप्त करें। पंक्तियों की कुल संख्या पहले प्राप्त करें, प्राथमिक कुंजी द्वारा चयन का आदेश दें और चबाने योग्य आकारों में चयनित पंक्तियों को सीमित करें।

यदि यह XML फ़ाइल बना रहा है, तो प्रत्येक ग्राहक का XML नोड System.out.println पर भेजें, इसे स्मृति में न रखें। प्रोग्राम को कमांड लाइन के माध्यम से लॉन्च करें और सभी आउटपुट को फ़ाइल में रीडायरेक्ट करें;

java MyConverter > results.txt 

जैसा कि आप रिकॉर्ड के माध्यम से लूप करते हैं, सभी फाइल में सहेजे जाते हैं।

1

संपूर्ण तालिका को निर्यात करने के लिए एक अवधारणा। (विशेषज्ञों को ध्यान दें: मुझे इसकी कमियों के बारे में पता है।)

import java.io.BufferedWriter; 
import java.io.File; 
import java.io.FileOutputStream; 
import java.io.OutputStreamWriter; 
import java.io.PrintWriter; 
import java.sql.Connection; 
import java.sql.DriverManager; 
import java.sql.PreparedStatement; 
import java.sql.ResultSet; 
import java.sql.ResultSetMetaData; 
public class FullTableExport { 
    public static String toXML(String s) { 
     if (s != null) { 
      StringBuilder b = new StringBuilder(s.length()); 
      for (int i = 0, count = s.length(); i < count; i++) { 
       char c = s.charAt(i); 
       switch (c) { 
       case '<': 
        b.append("&lt;"); 
        break; 
       case '>': 
        b.append("&gt;"); 
        break; 
       case '\'': 
        b.append("&#39;"); 
        break; 
       case '"': 
        b.append("&quot;"); 
        break; 
       case '&': 
        b.append("&amp;"); 
        break; 
       default: 
        b.append(c); 
       } 
      } 
      return b.toString(); 
     } 
     return ""; 
    } 
    public static void main(String[] args) throws Exception { 
     String table = "CUSTOMER"; 
     int batch = 100; 

     Class.forName("oracle.jdbc.driver.OracleDriver"); 
     Connection conn = DriverManager.getConnection(
      "jdbc:oracle:thin:@server:orcl", "user", "pass"); 
     PreparedStatement pstmt = conn.prepareStatement(
      "SELECT /*+FIRST_ROWS(" + batch + ") */ * FROM " + table); 
     ResultSet rs = pstmt.executeQuery(); 
     rs.setFetchSize(batch); 
     ResultSetMetaData rsm = rs.getMetaData(); 
     File output = new File("result.xml"); 
     PrintWriter out = new PrintWriter(new BufferedWriter(
      new OutputStreamWriter(
      new FileOutputStream(output), "UTF-8")), false); 
     out.printf("<?xml version='1.0' encoding='UTF-8'?>%n"); 
     out.printf("<table name='%s'>%n", toXML(table)); 
     int j = 1; 
     while (rs.next()) { 
      out.printf("\t<row id='%d'>%n", j++); 
      for (int i = 1; i <= rsm.getColumnCount(); i++) { 
       out.printf("\t\t<col name='%s'>%s</col>%n", 
        toXML(rsm.getColumnName(i)), 
        toXML(rs.getString(i))); 
      } 
      out.printf("\t</row>%n"); 
     } 
     out.printf("</table>%n", table); 
     out.flush(); 
    } 
} 

संपादित कमियों (धन्यवाद @JS):

  • कोई बाहरी पुस्तकालयों ojdbc
  • कुछ भी नहीं परे इस्तेमाल किया बंद कर दिया है
  • एक सामान्य अपवाद फेंक दिया है
  • यह एक मुख्य विधि है
  • एक्सएम के लिए प्रिंट का उपयोग एल पीढ़ी
  • ओरेकल विशिष्ट एसक्यूएल
  • सादा पाठ पासवर्ड
  • कुछ कॉलम स्ट्रिंग प्रतिनिधित्व में अजीब लग
  • UTF-8 भी अंतरराष्ट्रीय
  • XML संरचना पदचिह्न बड़े
+0

जब आप नमूना कोड पोस्ट करें और कमियों को जानें, तो आपको कम से कम उनका उल्लेख करना चाहिए। जैसा कि आप जानते हैं उदाहरण कोड * उत्पादन प्रणाली में दिखाएगा। –

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