2015-12-13 7 views
6

पर MySQL क्वेरी को अनुकूलित करना मैं जेडीबीसी के साथ mysql का उपयोग कर रहा हूं।बड़ी तालिका

मेरे पास एक बड़ी उदाहरण तालिका है जिसमें 6.3 मिलियन पंक्तियां हैं जिन्हें मैं कुशल चुनिंदा प्रश्नों को करने की कोशिश कर रहा हूं। नीचे देखें: enter image description here

मैं मेज पर तीन अतिरिक्त अनुक्रमणिका बनाया है, नीचे देखें: enter image description here

एक SELECT क्वेरी करने से इस SELECT latitude, longitude FROM 3dag WHERE timestamp BETWEEN "+startTime+" AND "+endTime+" AND HourOfDay=4 AND DayOfWeek=3" की तरह एक रन टाइम 256,356 एमएस में अत्यंत उच्च, या एक छोटे से है कि है चार मिनट से ऊपर मेरा एक ही प्रश्न पर समझाने के लिए मुझे देता है यह: enter image description here

डेटा पुन: प्राप्त करने के लिए मेरे कोड के नीचे है:

Connection con = null; 
    PreparedStatement pst = null; 
    Statement stmt = null; 
    ResultSet rs = null; 

    String url = "jdbc:mysql://xxx.xxx.xxx.xx:3306/testdb"; 
    String user = "bigd"; 
    String password = "XXXXX"; 

    try { 
     Class.forName("com.mysql.jdbc.Driver"); 
     con = DriverManager.getConnection(url, user, password); 
     String query = "SELECT latitude, longitude FROM 3dag WHERE timestamp BETWEEN "+startTime+" AND "+endTime+" AND HourOfDay=4 AND DayOfWeek=3"; 
     stmt = con.prepareStatement("SELECT latitude, longitude FROM 3dag WHERE timestamp>=" + startTime + " AND timestamp<=" + endTime); 
     stmt = con.createStatement(java.sql.ResultSet.TYPE_FORWARD_ONLY, java.sql.ResultSet.CONCUR_READ_ONLY); 
     stmt.setFetchSize(Integer.MIN_VALUE); 
     rs = stmt.executeQuery(query); 

     System.out.println("Start"); 
     while (rs.next()) { 

      int tempLong = (int) ((Double.parseDouble(rs.getString(2))) * 100000); 
      int x = (int) (maxLong * 100000) - tempLong; 
      int tempLat = (int) ((Double.parseDouble(rs.getString(1))) * 100000); 
      int y = (int) (maxLat * 100000) - tempLat; 

      if (!(y > matrix.length) || !(y < 0) || !(x > matrix[0].length) || !(x < 0)) { 
       matrix[y][x] += 1; 
      } 
     } 
     System.out.println("End"); 
     JSONObject obj = convertToCRS(matrix); 
     return obj; 

    }catch (ClassNotFoundException ex){ 
     Logger lgr = Logger.getLogger(Database.class.getName()); 
     lgr.log(Level.SEVERE, ex.getMessage(), ex); 
     return null; 
    } 
    catch (SQLException ex) { 
     Logger lgr = Logger.getLogger(Database.class.getName()); 
     lgr.log(Level.SEVERE, ex.getMessage(), ex); 
     return null; 
    } finally { 
     try { 
      if (rs != null) { 
       rs.close(); 
      } 
      if (pst != null) { 
       pst.close(); 
      } 
      if (con != null) { 
       con.close(); 
      } 
     } catch (SQLException ex) { 
      Logger lgr = Logger.getLogger(Database.class.getName()); 
      lgr.log(Level.WARNING, ex.getMessage(), ex); 
      return null; 
     } 
    } 

while(rs.next()) पाश में हर पंक्ति निकाला जा रहा है मुझे एक ही भयानक रन-टाइम देता है।

मेरा प्रश्न है कि मैं इस प्रकार की क्वेरी को अनुकूलित करने के लिए क्या कर सकता हूं? मैं .setFetchSize() के बारे में उत्सुक हूं और यहां इष्टतम मूल्य क्या होना चाहिए। दस्तावेज़ीकरण से पता चलता है कि INTEGER.MIN_VALUE परिणाम पंक्ति-दर-पंक्ति लाने में परिणाम देता है, क्या यह सही है?

किसी भी मदद की सराहना की जाती है।

संपादित टाइमस्टैम्प पर एक नया सूचकांक बनाने के बाद, सप्ताह का दिन और HOUROFDAY मेरी क्वेरी 1 मिनट तेजी से चलाता है और समझाने मुझे इस देता है:

enter image description here

+1

कृपया स्क्रीनशॉट से बचें और टेक्स्ट फॉर्म में अपनी जानकारी दिखाएं। पढ़ने और काम करने के लिए यह बहुत आसान है। –

+0

ओह, मैंने सोचा कि यह चारों ओर एक और तरीका होगा। क्या यह एक एसई दिशानिर्देश है, या सिर्फ आपकी निजी वरीयता है? – kongshem

+3

एक कारण यह है कि आप किसी छवि से प्रतिलिपि और पेस्ट नहीं कर सकते :-) –

उत्तर

1

कुछ विचार सामने:

  • क्या आपने वास्तव में SQL निष्पादन समय (.executeQuery() से पहली पंक्ति तक जांच की थी?) या निष्पादन + 6.3 मिलियन पंक्तियों से अधिक पुनरावृत्ति है?
  • आप एक तैयार स्टेमेंट तैयार करते हैं लेकिन इसका उपयोग नहीं करते हैं ?!
  • उपयोग PreparedStatement, tiemstamp, सप्ताह का दिन HOUROFDAY गुजरती हैं, के रूप में मानकों
  • बनाएं एक सूचकांक कि आपके जहां हालत संतुष्ट कर सकते हैं। कुंजी को इस तरह से ऑर्डर करें कि आप उच्चतम रैंकिंग फ़ील्ड वाले अधिकांश आइटम को खत्म कर सकें। - आप किस समय वहाँ मिलता है

    CREATE INDEX stackoverflow on 3dag(hourOfDay, dayOfWeek, Timestamp); 
    

    MySQL के अंदर अपने एसक्यूएल करें:

IDEX कैसा लग सकता है?

  • stmt.setFetchSize(Integer.MIN_VALUE); के बिना प्रयास करें यह कई अनियंत्रित नेटवर्क राउंडट्रिप्स बना सकता है।
+0

कमांड लाइन में क्वेरी निष्पादित करने से मुझे एक ही रन टाइम मिलता है। जैसा कि आपने अभी सुझाया है, एक इंडेक्स बनाना, परिणामों की रिपोर्ट करेगा। प्रीपेडस्टेटमेंट के लिए, मैं 'java.sql.ResultSet.TYPE_FORWARD_ONLY, java.sql.ResultSet.CONCUR_READ_ONLY' सेट करने में असमर्थ हूं, इसलिए मैंने स्टेटमेंट का उपयोग क्यों किया। – kongshem

+0

वैसे आप किस लाइन की वापसी की उम्मीद करते हैं? यदि यह आपकी याददाश्त में बाढ़ नहीं आ रहा है, तो आप वैसे भी डिफ़ॉल्ट विकल्पों के साथ सहेज सकते हैं। – Jan

+0

एक और विचार - स्ट्रीमिंग के लिए MySQL को मजबूर करना परिणाम को स्मृति में केवल पंप करने से धीमा हो सकता है। – Jan

1

अपने प्रश्न के अनुसार, की प्रमुखता (जो है, में विशिष्ट मानों की संख्या) अपने Timestamp स्तंभ के बारे में 1/अपने Uid स्तंभ की प्रमुखता की 30 वीं है। यही है, आपके पास बहुत सारे और समान टाइमस्टैम्प हैं। यह आपकी क्वेरी की दक्षता के लिए अच्छी तरह से नहीं है।

कहा जा रहा है कि आप चीजों को गति देने के लिए निम्नलिखित compound covering index का उपयोग करने का प्रयास कर सकते हैं।

CREATE INDEX 3dag_q ON ('Timestamp' HourOfDay, DayOfWeek, Latitude, Longitude) 

यह सहायता क्यों होगी? चूंकि आपकी पूरी क्वेरी इंडेक्स से तथाकथित तंग इंडेक्स स्कैन के साथ संतुष्ट हो सकती है। MySQL क्वेरी इंजन आपकी क्वेरी से मेल खाने वाले सबसे छोटे टाइमस्टैम्प मान के साथ प्रविष्टि में इंडेक्स को यादृच्छिक-एक्सेस करेगा। इसके बाद यह क्रमशः सूचकांक को पढ़ेगा और पंक्तियों से अक्षांश और देशांतर को खींच देगा।

आप MySQL सर्वर पर संक्षेप में कुछ करने का प्रयास कर सकते हैं।

SELECT COUNT(*) number_of_duplicates, 
     ROUND(Latitude,4) Latitude, ROUND(Longitude,4) Longitude 
    FROM 3dag 
WHERE timestamp BETWEEN "+startTime+" 
        AND "+endTime+" 
    AND HourOfDay=4 
    AND DayOfWeek=3 
GROUP BY ROUND(Latitude,4), ROUND(Longitude,4) 

यह एक छोटा परिणाम सेट वापस कर सकता है। संपादित करें यह आपके अक्षांश/लंबे मानों को मापता है (राउंड ऑफ) और फिर उन्हें गोल करके डुप्लीकेट किए गए आइटमों की संख्या को गिनें। जितना अधिक आप उन्हें चारों ओर घुमाते हैं (यानी, ROUND(val,N) फ़ंक्शन कॉल में दूसरा नंबर छोटा होता है) अधिक डुप्लिकेट मान आप पाएंगे, और कम क्वेरी आपकी क्वेरी द्वारा उत्पन्न की जाएगी। कम पंक्तियां समय बचाती हैं।

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

अधिक सुझाव

अपनी तालिका में FLOAT मूल्यों में अपने अक्षांश और देशांतर कॉलम बनाने अगर वे GPS सटीकता की है। यदि उनके पास जीपीएस उपयोग DOUBLE से अधिक सटीकता है। varchar(30) कॉलम में संख्याओं को संग्रहीत करना और स्थानांतरित करना काफी अक्षम है।

इसी तरह, अपने HourOfDay और DayOfWeek कॉलम SMALLINT या यहां तक ​​कि TINYINT डेटा तालिका में अपनी तालिका बनाएं। 0 और 31 के बीच के मानों के लिए 64 बिट पूर्णांक अपमानजनक है। सैकड़ों पंक्तियों के साथ, इससे कोई फर्क नहीं पड़ता। लाखों लोगों के साथ यह करता है।

अंत में, यदि आपके प्रश्नों हमेशा इस

SELECT Latitude, Longitude 
    FROM 3dag 
    WHERE timestamp BETWEEN SOME_VALUE 
         AND ANOTHER_VALUE 
    AND HourOfDay = SOME_CONSTANT_DAY 
    AND DayOfWeek = SOME_CONSTANT_HOUR 

की तरह लग रहे इस यौगिक सूचकांक को कवर आपकी क्वेरी में तेजी लाने के लिए आदर्श होना चाहिए।

CREATE INDEX 3dag_hdtll ON (HourOfDay, DayofWeek, `timestamp`, Latitude, Longitude) 
+0

मुझे लगता है कि आप मेरे मैट्रिक्स को गलत पढ़ते हैं, आकार 1371 x 838 है :) मैं प्रत्येक अक्षांश लंबे मूल्य के लिए 5 दशमलव का उपयोग कर रहा हूं। फिर भी धन्यवाद। मैं संक्षेप में सुझाव देखता हूं। – kongshem

+0

कवर इंडेक्स –

+0

ठीक करने का प्रयास करें ठीक है, इसलिए आपके द्वारा प्रस्तावित क्वेरी से परिणाम मुझे 2 मिनट और 11 सेकंड का रन टाइम देता है। यह सवाल वास्तव में क्या किया?क्या यह परिणामस्वरूप अक्षांश और देशांतर मूल्यों को चार दशमलव के साथ गिनता है? आउटपुट के माध्यम से एक त्वरित रन से पता चलता है कि बहुत सारे अक्षरों के लंबे मूल्य 1 होते थे, उनमें से अधिकतर 10 से 50 घटनाओं के बीच थे और सबसे बड़ा 400 था। – kongshem

0

मैं अपने ट्रैकिंग ऐप से बाहर निकल रहा हूं। यह मैं दक्षता के लिए करता हूं:

सबसे पहले, एक संभावित समाधान इस बात पर निर्भर करता है कि आप समय अंतराल की भविष्यवाणी/नियंत्रण कर सकते हैं या नहीं। प्रत्येक X मिनट या दिन में एक बार स्नैपशॉट स्टोर करें, उदाहरण के लिए। आइए हम कहें कि आप सभी घटनाओं को बुधवार को प्रदर्शित करना चाहते हैं। आप एक स्नैपशॉट सहेज सकते हैं जो पहले से ही आपकी फाइल फ़िल्टर कर चुका है। इससे चीजें तेजी से बढ़ जाएंगी, लेकिन कस्टम टाइम अंतराल और वास्तविक लाइव कवरेज के लिए व्यवहार्य समाधान नहीं है।

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

दूसरा कारक: आप अपना टाइमस्टैम्प कैसे स्टोर करते हैं, यह बहुत महत्वपूर्ण है। उदाहरण के लिए, VARCHAR से बचें। यदि आप UNIXTIME को परिवर्तित कर रहे हैं जो आपको अनावश्यक लैगटाइम भी देगा।चूंकि आप एक जियोट्रैकिंग एप्लिकेशन के रूप में विकसित हो रहे हैं, इसलिए आपका टाइमस्टैम्प यूनिटाइम में होगा - एक पूर्णांक। कुछ डिवाइस मिलीसेकंड के साथ काम करते हैं, मैं उनका उपयोग न करने की सलाह दूंगा। 1449878400000 (2015/12/12 0 जीएमटी) के बजाय 1449878400

मैं unixtime सेकंड में अपने सभी geopoint datetimes बचाने के लिए और का उपयोग केवल पल बिंदु सर्वर द्वारा प्राप्त किया गया था (जो इस क्वेरी आप प्रस्ताव के लिए अप्रासंगिक है timestamping के लिए mysql timestamps)।

आप एक पूर्ण क्वेरी चलाने के बजाय अनुक्रमित दृश्य तक पहुंचने से कुछ समय निकाल सकते हैं। क्या उस समय एक बड़ी क्वेरी में महत्वपूर्ण है परीक्षण के अधीन है।

अंत में, आप BETWEEN का उपयोग नहीं और कुछ इसी तरह का उपयोग कर यह क्या (नीचे स्यूडोकोड)

WHERE (timecode > start_Time AND timecode < end_time) 

देखें कि मैं > और < को >= और <= बदलने में अनुवाद किया जाएगा द्वारा अधिक एक छोटी बिट्सी दाढ़ी सकता है क्योंकि संभावना है कि आपका टाइमस्टैम्प लगभग सटीक दूसरे पर कभी नहीं होगा और यहां तक ​​कि यदि यह भी है, तो आप शायद ही कभी प्रभावित होंगे कि 1 भूगर्भीय/समय घटना प्रदर्शित होती है या नहीं।

+1

मैं वर्तमान में डेटा प्रकारों के आपके प्रस्तावित सुधारों के साथ डेटा को एक नई तालिका में डाल रहा हूं। मैंने इसे 32 मिलियन पंक्तियों के साथ डेटा के थोड़ा बड़े सेट पर किया, इसलिए डालने में कुछ समय लगता है। धन्यवाद, धन्यवाद! – kongshem

+1

ओह, और मेरी तालिका में टाइमस्टैम्प यूनिक्स टाइमस्टैम्प है :) – kongshem

+0

हाँ, मैंने देखा। मेरी गलती। –

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