बड़ी 220 मिलियन पंक्तियों की तालिका (9 टमटम डेटा) पर प्रश्नों को कैसे गति दें?


31

समस्या:

हमारे पास एक सामाजिक साइट है जहां सदस्य एक दूसरे को अनुकूलता या मिलान के लिए रेट कर सकते हैं। इस user_match_ratingsतालिका में 220 मिलियन से अधिक पंक्तियाँ (9 गिग डेटा या लगभग 20 गिग इंडेक्स में) हैं। इस तालिका के विरुद्ध क्वेरीज़ धीमे-धीमे (थ्रेसहोल्ड> 2 सेकंड) में दिखाई देती हैं और सिस्टम में सबसे अधिक बार लॉग की जाने वाली धीमी क्वेरी है:

Query_time: 3  Lock_time: 0  Rows_sent: 3  Rows_examined: 1051
"select rating, count(*) as tally from user_match_ratings where rated_user_id = 395357 group by rating;"

Query_time: 4  Lock_time: 0  Rows_sent: 3  Rows_examined: 1294
"select rating, count(*) as tally from user_match_ratings where rated_user_id = 4182969 group by rating;"

Query_time: 3  Lock_time: 0  Rows_sent: 3  Rows_examined: 446
"select rating, count(*) as tally from user_match_ratings where rated_user_id = 630148 group by rating;"

Query_time: 5  Lock_time: 0  Rows_sent: 3  Rows_examined: 3788
"select rating, count(*) as tally from user_match_ratings where rated_user_id = 1835698 group by rating;"

Query_time: 17  Lock_time: 0  Rows_sent: 3  Rows_examined: 4311
"select rating, count(*) as tally from user_match_ratings where rated_user_id = 1269322 group by rating;"

MySQL संस्करण:

  • प्रोटोकॉल संस्करण: १०
  • संस्करण: 5.0.77-लॉग
  • संस्करण bdb: स्लीपेकैट सॉफ्टवेयर: बर्कले DB 4.1.24: (29 जनवरी, 2009)
  • संस्करण संकलन मशीन: x86_64 version_compile_os: redhat-linux-gnu

तालिका जानकारी:

SHOW COLUMNS FROM user_match_ratings;

देता है:

╔═══════════════╦════════════╦════╦═════╦════════╦════════════════╗
 id             int(11)     NO  PRI  NULL    auto_increment 
 rater_user_id  int(11)     NO  MUL  NULL                   
 rated_user_id  int(11)     NO  MUL  NULL                   
 rating         varchar(1)  NO       NULL                   
 created_at     datetime    NO       NULL                   
╚═══════════════╩════════════╩════╩═════╩════════╩════════════════╝

नमूना प्रश्न:

select * from mutual_match_ratings where id=221673540;

देता है:

╔═══════════╦═══════════════╦═══════════════╦════════╦══════════════════════╗
 id         rater_user_id  rated_user_id  rating  created_at           
╠═══════════╬═══════════════╬═══════════════╬════════╬══════════════════════╣
 221673540  5699713        3890950        N       2013-04-09 13:00:38  
╚═══════════╩═══════════════╩═══════════════╩════════╩══════════════════════╝

इंडेक्स

तालिका में 3 सूचकांक हैं:

  1. पर एकल सूचकांक rated_user_id
  2. पर समग्र सूचकांक rater_user_idऔरcreated_at
  3. पर समग्र सूचकांक rated_user_idऔरrater_user_id
user_match_ratings से सूचकांक दिखाएं;

देता है:

╔════════════════════╦════════════╦═══════════════════════════╦══════════════╦═══════════════╦═══════════╦═════════════╦══════════╦════════╦═════════════════════════╦════════════╦══════════════════╗
 Table               Non_unique  Key_name                   Seq_in_index  Column_name    Collation  Cardinality  Sub_part  Packed  Null                     Index_type  Comment          
╠════════════════════╬════════════╬═══════════════════════════╬══════════════╬═══════════════╬═══════════╬═════════════╬══════════╬════════╬═════════════════════════╬════════════╬══════════════════╣
 user_match_ratings  0           PRIMARY                    1             id             A          220781193    NULL      NULL    BTREE                                                 
 user_match_ratings  1           user_match_ratings_index1  1             rater_user_id  A          11039059     NULL      NULL    BTREE                                                 
 user_match_ratings  1           user_match_ratings_index1  2             created_at     A          220781193    NULL      NULL    BTREE                                                 
 user_match_ratings  1           user_match_ratings_index2  1             rated_user_id  A          4014203      NULL      NULL    BTREE                                                 
 user_match_ratings  1           user_match_ratings_index2  2             rater_user_id  A          220781193    NULL      NULL    BTREE                                                 
 user_match_ratings  1           user_match_ratings_index3  1             rated_user_id  A          2480687      NULL      NULL    BTREE                                                 
╚════════════════════╩════════════╩═══════════════════════════╩══════════════╩═══════════════╩═══════════╩═════════════╩══════════╩════════╩═════════════════════════╩════════════╩══════════════════╝

इंडेक्स के साथ भी ये क्वेरी धीमी है।

मेरा प्रश्न:

एक सर्वर पर इस तालिका / डेटा को किसी अन्य डेटाबेस से अलग करेगा जिसमें मेमोरी में इस डेटा को संग्रहीत करने के लिए पर्याप्त रैम है जो इन प्रश्नों को गति देगा? क्या ऐसा कुछ भी है जिसमें टेबल / इंडेक्स स्थापित किए गए हैं ताकि हम इन प्रश्नों को तेज कर सकें?

वर्तमान में हमारे पास 16GB मेमोरी है; हालाँकि, हम या तो मौजूदा मशीन को 32GB में अपग्रेड करना चाहते हैं या कम से कम इतना ठोस राज्य ड्राइव के साथ एक नई मशीन जोड़ना चाहते हैं।


1
आपका प्रश्न अविश्वसनीय है। मुझे आपके वर्तमान समाधान के लिए बहुत दिलचस्पी है कि आप <= 2 सेकंड में परिणाम कैसे प्राप्त करने में कामयाब रहे? क्योंकि मेरे पास एक तालिका है जिसमें केवल 20 मिलियन रिकॉर्ड हैं और अभी भी इसके लिए 30 सेकंड लगते हैं SELECT QUERY। क्या आप सुझाव देंगे? PS आपके प्रश्न ने मुझे इस समुदाय (y) में शामिल होने के लिए मजबूर किया;
NullPointer

2
जिस टेबल पर आप क्वेरी कर रहे हैं, उस पर अनुक्रमणिका देखें। अक्सर उपयुक्त इंडेक्स बनाकर प्रश्नों में बहुत सुधार किया जा सकता है। हमेशा नहीं, बल्कि ऐसे बहुत से उदाहरण देखे गए जहाँ क्वेरीज़ पर क्लॉज़ पर कॉलम के विरुद्ध एक इंडेक्स प्रदान करके प्रश्नों को तेज़ बनाया जाता है। खासकर अगर एक टेबल बड़ा और बड़ा होता है।
रैंकनुअल

ज़रूर @Ranknoodle। धन्यवाद। मैं क्रमशः जाँच करूँगा।
नलपॉइंटर

जवाबों:


28

इस मुद्दे पर विचार, यादृच्छिक क्रम में फेंक दिया:

  • इस प्रश्न के लिए स्पष्ट सूचकांक है: (rated_user_id, rating)। एक क्वेरी जो केवल मिलियन उपयोगकर्ताओं में से एक के लिए डेटा प्राप्त करती है और 17 सेकंड की आवश्यकता होती है वह कुछ गलत कर रही है: (rated_user_id, rater_user_id)सूचकांक से पढ़ना और फिर ratingस्तंभ के लिए तालिका (सैकड़ों से हजारों) मानों से पढ़ना , जैसा ratingकि किसी भी सूचकांक में नहीं है। तो, क्वेरी को तालिका की कई पंक्तियों को पढ़ना होगा जो कई अलग-अलग डिस्क स्थानों में स्थित हैं।

  • तालिकाओं में कई अनुक्रमित जोड़ना शुरू करने से पहले, पूरे डेटाबेस के प्रदर्शन का विश्लेषण करने की कोशिश करें, धीमे प्रश्नों का पूरा सेट, डेटाटाइप्स, आपके द्वारा उपयोग किए जाने वाले इंजन और कॉन्फ़िगरेशन सेटिंग्स के विकल्पों की फिर से जाँच करें।

  • MySQL, 5.1, 5.5 या 5.6 के नए संस्करण (भी: Percona और MariaDB संस्करणों के लिए) पर विचार करें। बग के रूप में कई लाभ सही किए गए हैं, अनुकूलक में सुधार हुआ है और आप धीमी गति से प्रश्नों के लिए कम सीमा निर्धारित कर सकते हैं जो आपके दूसरे से कम है। (10 मिलीसेकंड की तरह)। यह आपको धीमी क्वेरी के बारे में बेहतर जानकारी देगा।

  • के डेटाटाइप के लिए विकल्प ratingअजीब है। VARCHAR(1)? क्यों नहीं CHAR(1)? क्यों नहीं TINYINT? यह आपको कुछ स्थान बचाएगा, दोनों तालिका और अनुक्रमणिका में (जो) उस स्तंभ को शामिल करेगा। एक varchar (1) कॉलम को char (1) पर एक और बाइट की आवश्यकता होती है और अगर वे utf8 हैं, तो (var) char कॉलम को 1 (टिनींट) के बजाय 3 (या 4) बाइट्स की आवश्यकता होगी।


2
यदि% गलत डायटाइप का उपयोग करते हैं तो% के संदर्भ में कितना प्रदर्शन प्रभाव या भंडारण अपव्यय होता है?
फ्लाइंगअटोम

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

-1

मैंने कभी-कभी 60 मिलियन रिकॉर्ड के साथ जर्मन सरकार के लिए तालिकाओं को संभाला।

हमारे पास इस तालिका में बहुत सारे थे।

और हमें एक तालिका से कुल पंक्तियों को कई बार जानने की आवश्यकता थी।

Oracle और Microsoft प्रोग्रामर के साथ बात करने के बाद हम इतने खुश नहीं थे ...

तो हम, डेटाबेस प्रोग्रामर के समूह ने फैसला किया कि हर तालिका में रिकॉर्ड हमेशा एक रिकॉर्ड होता है जिसमें कुल रिकॉर्ड संख्या संग्रहीत होती है। हमने INSERT या DELETE पंक्तियों के आधार पर इस नंबर को अपडेट किया।

हमने अन्य सभी तरीकों की कोशिश की। यह अब तक का सबसे तेज तरीका है।

हम 1998 के बाद से इस तरह का उपयोग करते हैं और हमारे सभी मल्टी मिलियन रिकॉर्ड तालिकाओं में पंक्तियों की कोई गलत संख्या कभी नहीं थी।


7
मैं पिछले 18 वर्षों में पेश की गई कुछ विशेषताओं को देखने का सुझाव दूंगा। दूसरों के बीच, count(*)कुछ सुधार हुए हैं।
डेज़ो

आप कैसे जानते हैं कि आपके पास कोई गलत संख्या नहीं है यदि आप उन्हें गिन नहीं सकते हैं? uhmmmm ...
टोनका

-3

मैं रेटिंग प्रकारों पर विभाजन की कोशिश करूंगा, जैसे:

Mut_match_ratings_N, पारस्परिक_match_ratings_S, आदि।

आपको प्रत्येक प्रकार के लिए एक क्वेरी करनी चाहिए, लेकिन शायद यह दूसरे तरीके से तेज है। कोशिश तो करो।

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

यदि ऐसा है, तो आपको अन्य दृष्टिकोण की तलाश करनी चाहिए, या यदि अंतरिक्ष और रखरखाव (या एप्लिकेशन लॉजिक) के संदर्भ में सस्ती है, तो तालिका की दो प्रतियां (आपकी प्रारंभिक तालिका, और विभाजन वाले) बनाए रखें।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.