MySQL: पंक्तियों की संख्या गिनने का सबसे तेज़ तरीका


117

MySQL में कई पंक्तियों को गिनने का कौन सा तरीका तेज होना चाहिए?

यह:

SELECT COUNT(*) FROM ... WHERE ...

या, विकल्प:

SELECT 1 FROM ... WHERE ...

// and then count the results with a built-in function, e.g. in PHP mysql_num_rows()

कोई यह सोचेगा कि पहला तरीका और तेज़ होना चाहिए, क्योंकि यह स्पष्ट रूप से डेटाबेस क्षेत्र है और डेटाबेस इंजन किसी अन्य की तुलना में तेज़ होना चाहिए जब इस तरह की चीजों को आंतरिक रूप से निर्धारित किया जाता है।


1
ओह, मुझे एक समान प्रश्न ( stackoverflow.com/questions/1855226/… ) मिला। लेकिन तब, मैं उपयोग करता हूं SELECT 1और नहीं SELECT *। क्या कोई अंतर है?
फ्रांज

मुझे नहीं पता, लेकिन यह अनुमान है कि ये दो उत्तर समान हैं - mysql क्वेरी ऑप्टिमाइज़र प्रत्येक के लिए एक ही काम कर सकता है। पूर्व ने कहा कि पूर्व की तुलना में कम अस्पष्ट है। आप कुछ बेंचमार्क क्यों नहीं लिखते हैं और इसका परीक्षण करते हैं?
जेसी कोहेन

उह, मान लें कि मैं एसओ की खोज इंजन दृश्यता को अलग-अलग शब्दों में एक समान प्रश्न पूछकर बढ़ाने की कोशिश कर रहा हूं;)
फ्रांज

1
अंतर PHP की ओर भेजे गए डेटा की मात्रा है। आपके पास जितने अधिक कॉलम हैं, स्लो सेलेक्ट * SELECT 1 के सापेक्ष हो जाता है, क्योंकि सभी कॉलम केवल नंबर 1 के बजाय पुनर्प्राप्त किए जाते हैं। जब आप चलाते हैं mysql_query(), उदाहरण के लिए, पूरे परिणाम सेट को MySQL से PHP में भेजा जाता है, चाहे आप जो भी हों। उस डेटा के साथ करते हैं।
तून81

इस तरह से एक प्रश्न पूछना अंतर्दृष्टि या नए विचारों को प्राप्त करने का एक शानदार तरीका है, लेकिन अंततः यदि आपके पास वास्तव में एक विशिष्ट परिदृश्य है जहां आप अधिक गति चाहते हैं, तो आपको यह देखने के लिए परीक्षण चलाना होगा कि सबसे तेज़ क्या है।
still_dreaming_1

जवाबों:


124

जब आप COUNT(*)इसे गणना कॉलम इंडेक्स में लेते हैं, तो यह सबसे अच्छा परिणाम होगा। MyISAM इंजन के साथ मैसकल वास्तव में पंक्ति गणना को संग्रहीत करता है, यह हर बार जब आप सभी पंक्तियों को गिनने की कोशिश करते हैं तो सभी पंक्तियों की गणना नहीं करते हैं। (प्राथमिक कुंजी के कॉलम पर आधारित)

पंक्तियों को गिनने के लिए PHP का उपयोग करना बहुत स्मार्ट नहीं है, क्योंकि आपको mysql से php पर डेटा भेजना है। जब आप mysql पक्ष पर समान हासिल कर सकते हैं तो ऐसा क्यों करें?

यदि COUNT(*)धीमा है, तो आपको EXPLAINक्वेरी पर चलना चाहिए , और जांचें कि क्या इंडेक्स वास्तव में उपयोग किए जाते हैं, और उन्हें कहां जोड़ा जाना चाहिए।


निम्नलिखित सबसे तेज़ तरीका नहीं है, लेकिन एक मामला है, जहां COUNT(*)वास्तव में फिट नहीं होता है - जब आप परिणामों को समूहित करना शुरू करते हैं, तो आप समस्या में भाग सकते हैं, जहां COUNTवास्तव में सभी पंक्तियों की गिनती नहीं होती है।

उपाय है SQL_CALC_FOUND_ROWS। यह आमतौर पर तब उपयोग किया जाता है जब आप पंक्तियों का चयन कर रहे होते हैं लेकिन फिर भी कुल पंक्ति गणना (उदाहरण के लिए, पेजिंग के लिए) जानना आवश्यक है। जब आप डेटा पंक्तियों का चयन करते हैं, तो केवल SQL_CALC_FOUND_ROWSचयन के बाद कीवर्ड को जोड़ें :

SELECT SQL_CALC_FOUND_ROWS [needed fields or *] FROM table LIMIT 20 OFFSET 0;

आपके द्वारा आवश्यक पंक्तियों का चयन करने के बाद, आप इस एकल क्वेरी के साथ गणना प्राप्त कर सकते हैं:

SELECT FOUND_ROWS();

FOUND_ROWS() क्वेरी का चयन करने वाले डेटा के तुरंत बाद कॉल करना होगा।


अंत में, सब कुछ वास्तव में नीचे आता है कि आपके पास कितनी प्रविष्टियां हैं और WHERE कथन में क्या है। आपको वास्तव में इस बात पर ध्यान देना चाहिए कि कैसे अनुक्रमित किया जा रहा है, जब बहुत सारी पंक्तियाँ (हजारों, लाखों, और ऊपर) हैं।


14
सुधार: MyISAMभंडार पंक्ति गिनती। अन्य स्टोरेज इंजन जैसे पंक्ति गणना को संग्रहीत InnoDB नहीं करते हैं और हर बार सभी पंक्तियों को गिनेंगे
द स्क्राम मिस्टर

1
क्या आप जानते हैं कि कौन सा सबसे तेज़ होगा जब आप केवल यह पता लगाना चाहते हैं कि क्या कोई पंक्ति है: SELECT 1 FROM ... LIMIT 1या SELECT COUNT(*) FROM ...?
फ्रांज

1
यह ध्यान रखना उपयोगी है कि अगर आपको डेटा की आवश्यकता है और केवल पेजिनेशन / आदि के लिए एक गिनती चाहते हैं। यह डेटा प्राप्त करने के लिए अधिक कुशल है फिर अपने प्रोग्राम में पंक्तियों को गिनें।
टाइजॉइड

6
यह अप्रासंगिक है कि क्या इंजन पंक्ति को गिनता है। प्रश्न स्पष्ट रूप से बताता है कि एक WHEREखंड है।
एल्वारो गोंजालेज

1
@ फ्रांज SELECT COUNT(*) FROM ...को स्कैन किए जाने के आधार पर काफी समय लग सकता है (जैसे कि एक बहुत बड़ी तालिका या लाखों / अरबों / खरबों का सूचकांक)। SELECT 1 FROM ... LIMIT 1तुरंत लौटा क्योंकि आप इसे पहली पंक्ति में सीमित कर रहे हैं।
jbo5112

59

मेरी टीम के साथियों के साथ बात करने के बाद, रिकार्डो ने हमें बताया कि यह तेज़ तरीका है:

show table status like '<TABLE NAME>' \G

लेकिन आपको यह याद रखना होगा कि परिणाम सटीक नहीं हो सकता है।

आप इसे कमांड लाइन से भी उपयोग कर सकते हैं:

$ mysqlshow --status <DATABASE> <TABLE NAME>

अधिक जानकारी: http://dev.mysql.com/doc/refman/5.7/en/show-table-statusus.html

और आप mysqlperformanceblog पर पूरी चर्चा पा सकते हैं


2
InnoDB के लिए, यह एक अनुमान है।
मार्टिन टूरनोइज

2
यह पता करने के लिए बहुत अच्छा है जब बहुत बड़ी तालिकाओं में पंक्तियों की संख्या के मोटे विचार की आवश्यकता होती है जहां गिनती (*) का शाब्दिक समय लग सकता है!
मार्क हैनसेन

इसने मुझे मेरे सारे बाल खींचने से बचा लिया। COUNT (*) मेरे डेटाबेस में सभी 33 मिलियन से अधिक पंक्तियों को गिनने के लिए उम्र ले रहा था। वैसे भी, मैं केवल यह जानना चाहता था कि मेरी समानांतर हटाई गई पंक्तियाँ फ़ंक्शन काम कर रही थीं या नहीं। मुझे एक सटीक संख्या की आवश्यकता नहीं थी।
joemar.ct

1
+1 तालिका स्थिति का उपयोग करने के बजाय "COUNT (*)" इस प्रश्न का सही उत्तर होना चाहिए क्योंकि यह "सबसे तेज़" "सटीकता" नहीं है।
1

2
का उपयोग करते हुए SHOW TABLE STATUS(या समतुल्य SELECTमें information_schema) तेजी से होता है, लेकिन यह एक हैंडल नहीं करता WHEREखंड। यह MyISAM के लिए सटीक है, लेकिन InnoDB के लिए imprecise (कभी-कभी 2 के कारक द्वारा बंद)।
रिक जेम्स

29

शानदार सवाल, शानदार जवाब। यदि कोई इस पृष्ठ को पढ़ रहा है और उस भाग को गायब कर रहा है, तो परिणामों को प्रतिध्वनित करने का त्वरित तरीका है:

$counter = mysql_query("SELECT COUNT(*) AS id FROM table");
$num = mysql_fetch_array($counter);
$count = $num["id"];
echo("$count");

5
mysql_query PHP 5.5.0 के रूप में एक पदावनत समारोह है।
उमर तारिक

8
क्यों नहीं as count? idपहली नज़र में भ्रामक है।
ओरखान अलीखानोव

इस सवाल का जवाब नहीं देता
मानसिक

17

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

SELECT TABLE_NAME AS 'Table Name', TABLE_ROWS AS 'Rows' FROM information_schema.TABLES WHERE TABLES.TABLE_SCHEMA = '`YOURDBNAME`' AND TABLES.TABLE_TYPE = 'BASE TABLE'; 

उदाहरण:

+-----------------+---------+
| Table Name      | Rows    |
+-----------------+---------+
| some_table      |   10278 |
| other_table     |     995 |

यह मुझे एक परिणाम देता है। लेकिन गिनती (1) और इस एक से परिणाम अलग हैं। यह तरीका हमेशा काउंट क्वेरी से कम संख्या देता है। कोई विचार?
अयप्पन सेकर

3
पाठकों के लिए बस एक नोट। यह विधि बहुत तेज़ है लेकिन यह केवल तब लागू होती है जब आप अनुमानित संख्याओं के साथ काम कर सकते हैं क्योंकि इसमें संग्रहीत मूल्य information_schemaवैसा नहीं होता है जैसा कि SELECT count(*) FROMमामले में InnoDB द्वारा उपयोग किए जाने पर लौटाया जाता है। यदि आपको सख्त मूल्य की आवश्यकता है तो ध्यान रखें कि यह विधि केवल MyISAM तालिकाओं के साथ सख्त मूल्य देती है। InnoDB के साथ पंक्तियों की संख्या लगभग अनुमानित है।
बार्टोज़ फ़रिन

13

मैंने हमेशा समझा है कि नीचे मुझे सबसे तेज़ प्रतिक्रिया समय मिलेगा।

SELECT COUNT(1) FROM ... WHERE ...

1
1 का चयन नहीं करेंगे ... कहाँ ... और भी तेज हो?
पैट्रिक

3
@patrick - के SELECT 1 ...रूप में कई पंक्तियों के रूप में वापसी करेंगे WHEREऔर LIMITपूछेंगे, और वे सभी "1" होंगे।
रिक जेम्स

1
show table status like '<TABLE NAME>' यह बहुत तेज होगा।
गहरे

@deep - लेकिन प्रासंगिक नहीं है अगर आपके पास एक WHEREखंड है। और, InnoDB के लिए, यह केवल एक अनुमान है।
रिक जेम्स

@RickJames हां सच!
गहरा

6

यदि आपको संपूर्ण परिणाम सेट की गिनती प्राप्त करने की आवश्यकता है, तो आप निम्नलिखित दृष्टिकोण अपना सकते हैं:

SELECT SQL_CALC_FOUND_ROWS * FROM table_name LIMIT 5;
SELECT FOUND_ROWS();

यह सामान्य रूप से COUNTयद्यपि किसी को लगता है कि इसके विपरीत का उपयोग करने से तेज है, क्योंकि यह आंतरिक रूप से गणना कर रहा है और उपयोगकर्ता को डेटा वापस नहीं भेजता है, इस प्रकार प्रदर्शन में सुधार का संदेह है।

इन दो प्रश्नों को करना योग प्राप्त करने के लिए अंकुरण के लिए अच्छा है, लेकिन विशेष रूप से WHEREखंडों का उपयोग करने के लिए नहीं ।


Intersting। क्या यह सबसे सामान्य डेटाबेस सिस्टम में काम करता है? MySQL, Postgres, SQLite ...?
फ्रांज

4
यह वास्तव में अक्सर COUNT (*) का उपयोग करने से अधिक तेज़ नहीं है। देखें stackoverflow.com/questions/186588/...
toon81

2
इस फ़ंक्शन का उपयोग करते समय आपको बहुत सावधान रहना चाहिए। इसके लापरवाह उपयोग ने एक बार हमारे पूरे उत्पादन वातावरण को पीसने की जगह पर ला दिया। यह बहुत संसाधन गहन है, इसलिए देखभाल के साथ उपयोग करें।
जैनिस पेइसेनीक्स

6

मैंनेCOUNT(*) बनाम के निष्पादन समय की तुलना करने के लिए कुछ बेंचमार्क किएCOUNT(id) (आईडी तालिका की प्राथमिक कुंजी है - अनुक्रमित)।

परीक्षणों की संख्या: 10 * 1000 प्रश्न

परिणाम: COUNT(*) तेजी से 7%

देखें: बेंचमार्कग्राफ

मेरी सलाह का उपयोग करना है: SELECT COUNT(*) FROM table


1
FYI करना भी एक सामान्य तरीका है COUNT(1), जिससे कुछ बेंचमार्क देखना दिलचस्प होगा ...
Sliq

4

इसे इस्तेमाल करे:

SELECT
    table_rows "Rows Count"
FROM
    information_schema.tables
WHERE
    table_name="Table_Name"
AND
    table_schema="Database_Name";

@ मैं माफी चाहता हूँ। मेरा मतलब है, यह वास्तव में अच्छा है अगर किसी ने नीचा दिखाने वाले को कुछ स्पष्टीकरण दिया कि वह ऐसा क्यों करता है, इसलिए हर कोई इसके बारे में कुछ सीख सकता है।
बैकुंठ

1
यह आपको एक अनुमानित उत्तर देगा। यदि आपको एक सटीक उत्तर की आवश्यकता है, तो आपको प्रदर्शन select count(*) from table_nameया कुछ और करने की आवश्यकता है। dba.stackexchange.com/questions/151769/…
प्रोग्रामर

@Programster धन्यवाद। लगभग एक साल से मुझे अंधेरे में छोड़ना बेहतर है।
बैकुंठ 28:16

1
@bayuah मुझे यकीन नहीं है कि आप अपनी अंतिम टिप्पणी से क्या मतलब है। मैं केवल आपको यह मान सकता हूं कि मैं वही हूं जो आपके जवाब को डाउन-वोट करता है, जो मैं नहीं हूं।
प्रोग्रामर

1
@Programster नहीं, मुझे क्षमा करें, मेरा मतलब यह नहीं था। मेरा मतलब है कि आपकी व्याख्या के लिए धन्यवाद, इसलिए मैं अनुमान लगा सकता हूं कि शायद डाउनवॉटर ने सोचा था कि जब वह ऐसा करेगा / करेगी।
बैकुंठ

3

शायद आप ऐसा करने पर विचार करना चाहें SELECT max(Id) - min(Id) + 1। यह केवल तभी काम करेगा जब आपके आईड्स अनुक्रमिक हों और पंक्तियों को हटाया न जाए। हालांकि यह बहुत तेज है।


3
सावधान रहें: सर्वर कभी-कभी ऑटो वेतन वृद्धि मूल्य> 1 (बैकअप कारणों के लिए) का उपयोग करते हैं, इसलिए यह समाधान अच्छा है लेकिन आपको पहले अपने डीबी कॉन्फ़िगरेशन की जांच करनी चाहिए।
एलेक्स

1

EXPLAIN SELECT id FROM ....मेरे लिए चाल चली। और मैं rowsपरिणाम के कॉलम के तहत पंक्तियों की संख्या देख सकता था ।


0

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

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

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

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


1
और आपने उस पंक्ति को कैसे अपडेट किया इसका विवरण क्या है? हालांकि, इसका मतलब है कि एक टेबल पर दोषपूर्ण डिजाइन, जहां सभी पंक्तियों को सवारी के लिए आने के लिए एक व्यर्थ इंट की आवश्यकता होगी।
ड्रू

5
हाँ, यह वास्तव में बेवकूफ है। प्रत्येक पंक्ति के साथ आपको पहली पंक्ति को अनदेखा करना होगा। मैं बस एक योग तालिका बनाऊंगा और एक ट्रिगर के आधार पर आबाद करूंगा। उपयोगकर्ता तालिका सम्मिलित करें, योग तालिका अद्यतन करें। उपयोगकर्ता तालिका हटाएं, योग तालिका अपडेट करें।
HTMLGuy

-1

प्राथमिक कुंजी पर एक शर्त के साथ एक गणना (*) स्टेटमेंट ने पूर्ण तालिका स्कैन से बचने के लिए पंक्ति की गिनती बहुत तेजी से वापस की।

SELECT COUNT(*) FROM ... WHERE <PRIMARY_KEY> IS NOT NULL;

यह मेरे लिए बहुत तेज था

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