InnoDB पंक्ति गणना को क्यों संग्रहीत नहीं करता है?


19

हर कोई जानता है कि, तालिकाओं में जो इंजन के रूप में InnoDB का उपयोग करते हैं, जैसे प्रश्न SELECT COUNT(*) FROM mytableबहुत ही सटीक और बहुत धीमे हैं, खासकर जब तालिका बड़ी हो जाती है और उस क्वेरी को निष्पादित करते समय लगातार पंक्ति सम्मिलन / विलोपन होते हैं।

जैसा कि मैंने इसे समझा, InnoDB एक आंतरिक चर में पंक्ति गणना को संग्रहीत नहीं करता है, जो इस समस्या का कारण है।

मेरा सवाल है: ऐसा क्यों है? क्या ऐसी सूचनाओं को संग्रहीत करना इतना कठिन होगा? इतनी सारी स्थितियों में जानना एक महत्वपूर्ण जानकारी है। एकमात्र कठिनाई मैं देख रहा हूं कि क्या इस तरह की आंतरिक गणना को लागू किया जाएगा, जब लेन-देन शामिल है: यदि लेन-देन अप्राप्त है, तो क्या आप इसके द्वारा डाली गई पंक्तियों को गिनते हैं या नहीं?

पुनश्च: मैं DBs का विशेषज्ञ नहीं हूं, मैं सिर्फ एक व्यक्ति हूं, जिसके पास MySQL एक साधारण शौक है। इसलिए अगर मैंने अभी कुछ मूर्खतापूर्ण पूछा है, तो अत्यधिक आलोचना न करें: डी।


6
धीमा, हाँ। निष्प्राण, नहीं। यह धीमा है क्योंकि यह सटीक परिणाम देता है। जब आपके पास 200M पंक्तियों की तालिका होती है, और संभवतः कई अन्य लेनदेन जो एक ही तालिका में सम्मिलित / हटाते हैं, संभवतः प्रति सेकंड कई पंक्तियाँ, एक और सवाल "क्या आपको सटीक संख्या की आवश्यकता है?"
ypercube y

@ypercube मुझे पता है कि मैंने कुछ बार phpmyadmin में कुछ पंक्ति गणना मान देखे जो बहुत बंद थे। साथ ही, वहाँ एक टिप्पणी है कि "कुछ सटीक नहीं हो सकता है"।
रादु मर्जिया

1
@RaduMurzea phpMyAdmin उपयोगकर्ताओं को आपके द्वारा ज्ञात गति कारणों के लिए InnoDB तालिकाओं के लिए तालिका गणना की एक वैकल्पिक विधि है। यह वह जगह है जहाँ आपके द्वारा उल्लिखित मासूमियत खेल में आती है। वास्तविक SELECT COUNT(*) FROM ...प्रश्न सटीक हैं। यदि आप चाहें, तो phpMyAdmin को गति की कीमत पर हमेशा सटीक पंक्ति गणना का उपयोग करने के लिए कॉन्फ़िगर किया जा सकता है। अधिक जानकारी: stackoverflow.com/questions/11926259/…
21

जवाबों:


9

मैं @RemusRusanu (उनके जवाब के लिए +1) से सहमत हूं

SELECT COUNT(*) FROM mydb.mytableInnoDB में एक व्यवहार्य भंडारण इंजन की तरह व्यवहार करना चाहिए। इसकी तुलना MyISAM से करें।

MyISAM

यदि mydb.mytableकोई MyISAM तालिका है, तो लॉन्च SELECT COUNT(*) FROM mydb.mytable;करना केवल चलाने के समान है SELECT table_rows FROM information_schema.table WHERE table_schema = 'mydb' AND table_name = 'mytable';। यह MyISAM तालिका के शीर्ष लेख में पंक्ति गणना की त्वरित खोज को ट्रिगर करता है।

InnoDB

यदि mydb.mytableआप एक InnoDB तालिका है, तो आप चीजों के हॉज-पॉज़ को चालू करते हैं। आपके पास MVCC चल रहा है, जो निम्नलिखित को नियंत्रित करेगा:

  • ib_logfile0 / ib_logfile1 (Redo Logs)
  • ibdata1
    • लॉग्स को पूर्ववत करें
    • रोलबैक
    • डेटा शब्दकोश परिवर्तन
  • बफर पूल प्रबंधन
  • लेन-देन अलगाव (4 प्रकार)
    • बार-बार पढ़ने योग्य
    • पढ़ो कमिटेड
    • बिना पढ़े लिखे
    • serializable

टेबल काउंट के लिए InnoDB पूछना इन अशुभ चीजों के माध्यम से नेविगेशन की आवश्यकता है। वास्तव में, कोई भी वास्तव में कभी नहीं जानता है कि क्या SELECT COUNT(*) from mydb.mytableरिपीटेबल केवल पढ़ता है या इसमें वह रीड भी शामिल है जो प्रतिबद्ध हैं और जो बिना पढ़े हुए हैं।

आप innodb_stats_on_metadata को सक्षम करके चीजों को थोड़ा स्थिर करने का प्रयास कर सकते हैं ।

MySQL प्रलेखन के अनुसार innodb_stats_on_meta_data पर

जब यह चर सक्षम होता है (जो कि वैरिएबल बनने से पहले जैसा डिफ़ॉल्ट होता है), InnoDB मेटाडेटा स्टेटमेंट्स जैसे SHOW TABLE STATUS या SHOW INDEX के दौरान, या जब INFORMATION_SCHEME टेबल TABLES या STATISTICS तक पहुँचता है, तो आँकड़े अद्यतन करता है। (ये अपडेट ANALYZE TABLE के लिए जैसा होता है, वैसा ही होता है।) अक्षम होने पर, इन ऑपरेशन के दौरान InnoDB आँकड़े अपडेट नहीं करता है। इस चर को अक्षम करने से उन स्कीमाओं तक पहुंच की गति में सुधार हो सकता है जिनमें बड़ी संख्या में टेबल या इंडेक्स होते हैं। यह उन प्रश्नों के लिए निष्पादन योजनाओं की स्थिरता में सुधार कर सकता है जिनमें इनोबीडी टेबल शामिल हैं।

इसे अक्षम करना आपको EXPLAIN योजना स्थापित करने के संदर्भ में अधिक स्थिर गणना दे सकता है या नहीं दे सकता है। यह SELECT COUNT(*) from mydb.mytableया तो अच्छे तरीके से, बुरे तरीके से, या बिल्कुल नहीं, प्रदर्शन को प्रभावित कर सकता है । इसे आज़माइए और देखिए !!!


16

स्टार्टर के लिए 'करंट काउंट' जैसी कोई चीज किसी वैरिएबल में स्टोर करने के लिए नहीं है। एक क्वेरी की तरह SELECT COUNT(*) FROM ...वर्तमान अलगाव स्तर और सभी समवर्ती लंबित लेनदेन के अधीन है। अलगाव स्तर के आधार पर, क्वेरी बिना लंबित लेनदेन द्वारा डाले या हटाए पंक्तियों को देख या नहीं देख सकती है। जवाब देने का एकमात्र तरीका उन पंक्तियों को गिनना है जो वर्तमान लेनदेन के लिए दिखाई देते हैं।

ध्यान दें कि मैंने गणना के दौरान शुरू या समाप्त होने वाले समवर्ती लेनदेन के और भी अधिक कांटेदार विषय को नहीं छुआ । रोलबैक का उल्लेख नहीं ...


1
ठीक है, इसलिए यह अलगाव स्तर पर निर्भर है, जो समझ में आता है। लेकिन इसे अभी भी लागू किया जा सकता है।
रादु मर्जिया

@SoboLan बहुत सारे कारण हैं कि ऐसा क्यों नहीं करना चाहिए और हो सकता है, जिनमें से अधिकांश ऊपर सूचीबद्ध हैं। क्या आप लेन-देन प्रति तालिका प्रारंभ (जो भी Oracle के SCN MySQL में है) प्रति गणना की सूची को बनाए रखकर इसे लागू करेंगे? इस तरह की गणनाओं का प्रबंधन एक बड़े पैमाने पर ओवरहेड होगा - एक डेटाबेस के बारे में सोचें जिसमें 100 या अधिकतम समवर्ती सत्रों में से प्रत्येक में एक ही टेबल पर बड़ी मात्रा में INSERTs / DELETE हो। बनाए रखना असंभव है।
फिलो

इसे लागू करना काफी मुश्किल है। ज़रा सोचिए कि गिनती को DB में बनाए रखना पड़ता है, इसका मतलब कहीं-कहीं मेटाडेटा में होता है, और इस गिनती को हर उस लेन-देन को बनाए रखना पड़ता है जो किसी पंक्ति को सम्मिलित या हटाता है। आप उस मेटाडेटा को कैसे लॉक करेंगे? और आप रोलबैक कैसे संभालेंगे? तुच्छ से दूर है। और परिणाम प्रश्नों के एक बहुत ही संकीर्ण सबसेट के लिए उपयोग करने योग्य होगा।
रेमस रुसानु

3
@JackDouglas दिलचस्प। पिछले COUNT(*)प्रश्नों में मैंने जो कुछ देखा है, वह वास्तव में आवश्यक है और आमतौर पर डेवलपर अनुभवहीनता का परिणाम है (इससे पहले कि हम उन्हें चुनें!) या खराब ऐप डिज़ाइन को गिनें।
फिलो

1
@SoboLAN - नहीं, यह नहीं होगा। एक ऐसी सेवा का होना जो पूर्वनिर्धारित समय अंतराल पर किसी प्रकार की सांख्यिकी तालिका को अद्यतन करती है, बहुत बेहतर है। एक बड़े डेटाबेस और कई प्रशासकों के साथ अधिकांश तालिकाओं को क्वेरी करने की कल्पना करें, तालिका में SELECT COUNT(*)एक गैर-अनुकूलित जोड़ें WHEREऔर आपके पास कुछ उपयोगकर्ता होंगे जो कई संदिग्ध-उपयोगी स्टेट काउंटरों के लिए db को अपने घुटनों तक लाएंगे।
एनबी

0

जबकि यह सैद्धांतिक रूप से संभव होगा कि किसी दिए गए तालिका के लिए पंक्तियों की संख्या का सही-सही अंदाजा लगाना InnoDB के साथ हो, यह बहुत अधिक लॉकिंग की कीमत पर होगा, जो प्रदर्शन को नकारात्मक रूप से प्रभावित करेगा। यह भी अलगाव स्तर के आधार पर भिन्न होगा।

MyISAM पहले से ही टेबल लेवल लॉकिंग करता है, इसलिए वहां कोई अतिरिक्त लागत नहीं है।

मुझे शायद ही कभी किसी तालिका के लिए पंक्ति गणना की आवश्यकता होती है, हालांकि मैं COUNT (*) का उपयोग बहुत कम करता हूं। मैं आम तौर पर एक WHERE क्लॉज संलग्न है। एक छोटे परिणाम सेट पर एक कुशल सूचकांक का उपयोग करना, मुझे लगता है कि वे काफी तेजी से हैं।

मैं असहमत हूं कि गिनती गलत है। गणना डेटा के एक स्नैपशॉट का प्रतिनिधित्व करती है, और मैंने हमेशा उन्हें सटीक पाया है।

संक्षेप में, MySQL ने आपको इसे InnoDB के लिए कार्यान्वित करने के लिए छोड़ दिया है। आप प्रत्येक क्वेरी के बाद एक गणना और वेतन वृद्धि / इसे बढ़ा सकते हैं। हालांकि, आसान समाधान शायद MyISAM पर स्विच करना है।


2
यह नहीं एक लेन-देन संबंधी प्रणाली में पंक्तियों की एक सटीक गिनती रखने के लिए संभव। क्योंकि सक्रिय लेनदेन के रूप में कई अलग-अलग (और सही) पंक्तिबद्ध हैं।
a_horse_with_no_name

5
मैंने यहां '-1' के लिए एक दिया, हालांकि, इसका आसान समाधान शायद MyISAM को बदलना है। ' मैं कभी भी पंक्ति गणना प्राप्त करने के लिए MyISAM पर स्विच करने की अनुशंसा नहीं करूंगा।
डेरेक डाउनी

@a_horse_with_no_name, इसलिए आप सहमत हैं कि प्रत्येक लेन-देन के लिए "सही" पंक्तिबद्ध होगा। मेरे लिए संभव लगता है।
माक्र्स एडम्स

1
@Dest, मैंने कभी नहीं कहा "बस पंक्ति गणना प्राप्त करने के लिए"।
माक्र्स एडम्स

@a_horse_with_no_name, यह सही नहीं लगता है। निश्चित रूप से हम केवल पंक्तियों जब लेन-देन हो जाता है की संख्या की गणना कर रहे हैं प्रतिबद्ध है ना?
पचेरियर
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.