डबल क्वेरी के बिना MySQL पृष्ठ पर अंक लगाना?


115

अगर एक MySQL क्वेरी से परिणामों की संख्या प्राप्त करने का एक तरीका था, और उसी समय परिणामों को सीमित करने के लिए मैं सोच रहा था।

जिस तरह से शिश्न काम करता है (जैसा कि मैं इसे समझता हूं), पहले मैं कुछ ऐसा करता हूं

query = SELECT COUNT(*) FROM `table` WHERE `some_condition`

जब मैं num_rows (क्वेरी) प्राप्त करता हूं, तो मेरे पास परिणामों की संख्या होती है। लेकिन फिर वास्तव में मेरे परिणामों को सीमित करने के लिए, मुझे एक दूसरी क्वेरी करनी होगी जैसे:

query2 = SELECT COUNT(*) FROM `table` WHERE `some_condition` LIMIT 0, 10

मेरा प्रश्न: क्या दोनों में से कुल परिणाम प्राप्त करने के लिए दोनों हैं, और एक ही क्वेरी में वापस आए परिणामों को सीमित करें? या ऐसा करने का कोई और अधिक कुशल तरीका। धन्यवाद!


8
यद्यपि आप
क्वेरी

जवाबों:


66

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

दूसरा तरीका है SQL_CALC_FOUND_ROWSक्लॉज का उपयोग करना और फिर कॉल करना SELECT FOUND_ROWS()। इस तथ्य के अलावा कि आपको FOUND_ROWS()बाद में कॉल डालनी है, इसके साथ एक समस्या है: MySQL में एक बग है जो इस गुदगुदी को प्रभावित करता है ORDER BYजो दो प्रश्नों के भोले दृष्टिकोण की तुलना में बड़ी तालिकाओं पर इसे धीमा बनाने वाले प्रश्नों को प्रभावित करता है ।


2
हालाँकि, यह काफी दौड़-हालत का सबूत नहीं है, जब तक कि आप लेन-देन के भीतर दो प्रश्न नहीं करते हैं। यह आमतौर पर एक समस्या नहीं है, हालांकि।
निकोज़िक

"विश्वसनीय" से मेरा मतलब है कि एसक्यूएल खुद हमेशा आपके इच्छित परिणाम को वापस करने जा रहा है, और "बुलेट-प्रूफ" से मेरा मतलब था कि एसक्यूएल का उपयोग करने में कोई बाधा नहीं है। मेरे द्वारा उल्लिखित बग के अनुसार ORDER BY और LIMIT के साथ SQL_CALC_FOUND_ROWS का उपयोग करने के विपरीत।
स्टेटिक्सन

5
जटिल प्रश्नों पर, एक ही क्वेरी में गिनती लाने के लिए SQL_CALC_FOUND_ROWS का उपयोग करके दो अलग-अलग प्रश्न करने की तुलना में लगभग हमेशा धीमा होगा। ऐसा इसलिए है क्योंकि इसका मतलब है कि सभी पंक्तियों को पूर्ण रूप से पुनर्प्राप्त करने की आवश्यकता होगी, सीमा की परवाह किए बिना, फिर लिमिट क्लॉज में निर्दिष्ट केवल उन्हें वापस कर दिया जाएगा। मेरी प्रतिक्रिया भी देखें जिसमें लिंक हैं।
थोमसट्रेटर

आपके द्वारा इसकी आवश्यकता के कारण के आधार पर, आप कुल परिणामों को प्राप्त नहीं करने के बारे में सोचना चाह सकते हैं। ऑटो-पेजिंग विधियों को लागू करने के लिए यह एक अधिक सामान्य अभ्यास बन गया है। फेसबुक, ट्विटर, बिंग और Google जैसी साइटें इस पद्धति का उपयोग युगों से करती आ रही हैं।
थॉमस बी

68

मैं लगभग कभी दो प्रश्न नहीं करता।

बस जरूरत से एक अधिक पंक्ति लौटाएं, पृष्ठ पर केवल 10 प्रदर्शित करें, और यदि प्रदर्शित होने से अधिक हैं, तो "अगला" बटन प्रदर्शित करें।

SELECT x, y, z FROM `table` WHERE `some_condition` LIMIT 0, 11
// iterate through and display 10 rows.

// if there were 11 rows, display a "Next" button.

आपकी क्वेरी सबसे अधिक प्रासंगिक पहले के क्रम में वापस आनी चाहिए। संभावना है, ज्यादातर लोगों को 412 में से 236 पृष्ठ पर जाने की परवाह नहीं है।

जब आप एक Google खोज करते हैं, और आपके परिणाम पहले पृष्ठ पर नहीं होते हैं, तो आप संभवत: नौ नहीं, बल्कि दो पेज पर जाते हैं।


42
वास्तव में, यदि मुझे यह Google क्वेरी के पहले पृष्ठ पर नहीं मिलता है, तो आमतौर पर मैं पेज नौ पर छोड़ता हूं।
फिल

3
@ पहले मैंने इसे सुना लेकिन ऐसा क्यों?
TK123

5
थोड़ी देर, लेकिन यहाँ मेरा तर्क है। कुछ खोज, खोज इंजन अनुकूलित लिंक फार्मों पर हावी हैं। तो पहले कुछ पृष्ठ स्थिति नंबर 1 के लिए अलग-अलग फार्म से लड़ रहे हैं, उपयोगी परिणाम अभी भी क्वेरी के साथ जुड़ा हुआ है, बस शीर्ष पर नहीं।
फिल

4
COUNTएक समग्र कार्य है। आप एक क्वेरी में गिनती और सभी परिणाम कैसे लौटाते हैं ? उपरोक्त क्वेरी केवल 1 पंक्ति वापस करेगी, चाहे जो LIMITभी सेट हो। यदि आप जोड़ते हैं GROUP BY, तो यह सभी परिणाम लौटाएगा, लेकिन COUNTगलत होगा
pixelfreak


27

दोहरे-क्वेरी से बचने के लिए एक और तरीका यह है कि वर्तमान पृष्ठ के लिए सभी पंक्तियों को पहले लिगिट क्लॉज का उपयोग किया जाए, उसके बाद केवल दूसरी COUNT (*) क्वेरी करें यदि पंक्तियों की अधिकतम संख्या पुनः प्राप्त की गई थी।

कई अनुप्रयोगों में, सबसे अधिक संभावना परिणाम यह होगा कि परिणाम के सभी एक पृष्ठ पर फिट होते हैं, और पेजिंग करने के लिए आदर्श के बजाय अपवाद है। इन मामलों में, पहली क्वेरी परिणामों की अधिकतम संख्या प्राप्त नहीं करेगी।

उदाहरण के लिए, स्टैकओवरफ़्लो प्रश्न पर उत्तर शायद ही कभी किसी दूसरे पृष्ठ पर फैलते हैं। एक उत्तर पर टिप्पणियाँ 5 की सीमा पर शायद ही कभी फैलती हैं या उन सभी को दिखाने के लिए आवश्यक होती हैं।

इसलिए इन अनुप्रयोगों में आप केवल पहले एक एलआईआईटी के साथ एक क्वेरी कर सकते हैं, और फिर जब तक वह सीमा पूरी नहीं हो जाती है, आपको पता है कि दूसरी COUNT (*) क्वेरी करने की आवश्यकता के बिना कितनी पंक्तियाँ हैं - अधिकांश स्थितियों को कवर करें।


1
@thomasrutter मेरे पास एक ही दृष्टिकोण था, लेकिन आज इसके साथ एक दोष की खोज की। परिणामों के अंतिम पृष्ठ में तब अंकन डेटा नहीं होगा। अर्थात, मान लें कि प्रत्येक पृष्ठ में 25 परिणाम होने चाहिए, अंतिम पृष्ठ में संभवतः ऐसा नहीं होगा, मान लें कि इसमें 7 हैं ... इसका मतलब है कि गिनती (*) कभी नहीं चलेगी, और इसलिए कोई पृष्ठांकन प्रदर्शित नहीं होगा उपयोगकर्ता।
द्वंद्व

2
नहीं - यदि आप कहते हैं, तो 200 परिणाम, आप अगले 25 को क्वेरी करते हैं और आपको केवल 7 वापस मिलते हैं, जो आपको बताता है कि परिणामों की कुल संख्या 207 है और इसलिए आपको COUNT (*) के साथ एक और क्वेरी करने की आवश्यकता नहीं है क्योंकि आप पहले से ही जानते हैं कि यह क्या कहने जा रहा है। आपके पास पेजेशन दिखाने के लिए आवश्यक सभी जानकारी है। यदि आपको उपयोगकर्ता को नहीं दिखाने के लिए पेजिंग की समस्या है, तो आपके पास कहीं और बग है।
थोमसट्रेटर

15

ज्यादातर स्थितियों में यह बहुत तेजी से और कम संसाधन से दो अलग-अलग प्रश्नों में इसे करने के लिए गहन है, भले ही यह एक-काउंटर के रूप में लगता है।

यदि आप SQL_CALC_FOUND_ROWS का उपयोग करते हैं, तो बड़ी तालिकाओं के लिए यह आपकी क्वेरी को बहुत धीमा कर देता है, दो प्रश्नों को निष्पादित करने की तुलना में भी धीमा, पहला COUNT (*) और दूसरा एक LIMIT के साथ। इसका कारण यह है कि SQL_CALC_FOUND_ROWS के कारण पंक्तियों को पहले की बजाए पंक्तियों को लाने के बाद LIMIT क्लॉज लागू किया जाता है , इसलिए यह सीमाओं को लागू करने से पहले सभी संभावित परिणामों के लिए पूरी पंक्ति प्राप्त करता है। यह एक सूचकांक से संतुष्ट नहीं हो सकता क्योंकि यह वास्तव में डेटा प्राप्त करता है।

यदि आप दो प्रश्नों का दृष्टिकोण लेते हैं, तो पहला केवल COUNT (*) प्राप्त करना है और वास्तव में लाने और वास्तविक डेटा प्राप्त नहीं करना है, यह अधिक तेज़ी से संतुष्ट हो सकता है क्योंकि यह आमतौर पर अनुक्रमित का उपयोग कर सकता है और इसके लिए वास्तविक पंक्ति डेटा प्राप्त नहीं करना पड़ता है हर पंक्ति इसे देखती है। फिर, दूसरी क्वेरी को केवल पहले $ ऑफसेट + $ सीमा पंक्तियों को देखना होगा और फिर वापस लौटना होगा।

MySQL के प्रदर्शन ब्लॉग की यह पोस्ट इसे और स्पष्ट करती है:

http://www.mysqlperformanceblog.com/2007/08/28/to-sql_calc_found_rows-or-not-to-sql_calc_found_rows/

पृष्ठांकन के अनुकूलन के बारे में अधिक जानकारी के लिए, इस पोस्ट और इस पोस्ट को देखें


2

मेरा उत्तर देर से आ सकता है, लेकिन आप दूसरी क्वेरी (सीमा के साथ) को छोड़ सकते हैं और अपनी बैक एंड स्क्रिप्ट के माध्यम से जानकारी को फ़िल्टर कर सकते हैं। उदाहरण के लिए PHP में, आप कुछ ऐसा कर सकते हैं:

if($queryResult > 0) {
   $counter = 0;
   foreach($queryResult AS $result) {
       if($counter >= $startAt AND $counter < $numOfRows) {
            //do what you want here
       }
   $counter++;
   }
}

लेकिन निश्चित रूप से, जब आपके पास विचार करने के लिए हजारों रिकॉर्ड होते हैं, तो यह बहुत तेजी से अक्षम हो जाता है। पूर्व-गणना की गणना में देखने के लिए एक अच्छा विचार हो सकता है।

यहाँ इस विषय पर एक अच्छा पढ़ा है: http://www.percona.com/ppc2009/PPC2009_mysql_pagination.pdf


लिंक मृत, मुझे लगता है कि यह सही है: percona.com/files/pretations/ppc2009/… । संपादित नहीं करेगा क्योंकि यह सुनिश्चित नहीं है कि यह क्या है।
हेक्टोर्ग87

1
query = SELECT col, col2, (SELECT COUNT(*) FROM `table`) AS total FROM `table` WHERE `some_condition` LIMIT 0, 10

16
यह क्वेरी तालिका में रिकॉर्ड की कुल संख्या लौटाती है; उस स्थिति से मेल खाने वाले रिकॉर्ड की संख्या नहीं।
लॉरेंस बरसांती

1
अभिलेखों की कुल संख्या जो पेजेशन (@ लॉरेंस) के लिए आवश्यक है।
imme

ओह, ठीक है, बस whereखंड को आंतरिक क्वेरी में जोड़ें और आपको पृष्ठांकित परिणामों के साथ सही "कुल" मिलता है (पृष्ठ limitखंड के साथ चुना गया है
एरेनोर पाज़

सब-क्वेरी काउंट (*) को उसी की आवश्यकता होगी जहाँ क्लॉज़ या इसके बाद परिणाम की सही संख्या वापस नहीं आएगी
AKrush95

1

2020 में एक जवाब की तलाश में किसी के लिए। MySQL प्रलेखन के अनुसार:

"SQL_CALC_FOUND_ROWS क्वेरी संशोधक और FOUND_ROWS () फ़ंक्शन के साथ MySQL 8.0.17 के रूप में पदावनत किए गए हैं और भविष्य के MySQL संस्करण में हटा दिए जाएंगे। प्रतिस्थापन के रूप में, अपनी क्वेरी को LIMIT के साथ निष्पादित करने पर विचार करें, और फिर COUNT (*) के साथ दूसरी क्वेरी। और बिना यह निर्धारित करने के लिए कि क्या अतिरिक्त पंक्तियाँ हैं।

मुझे लगता है कि यह तय करता है।

https://dev.mysql.com/doc/refman/8.0/en/information-functions.html#function_found-rows


0

आप सबक्वेरी में अधिकांश क्वेरी का पुन: उपयोग कर सकते हैं और इसे एक पहचानकर्ता को सेट कर सकते हैं। उदाहरण के लिए एक मूवी क्वेरी जो रनटाइम द्वारा अक्षर 'ऑर्डरिंग' वाली फिल्मों को ढूंढती है, मेरी साइट पर इस तरह दिखेगी।

SELECT Movie.*, (
    SELECT Count(1) FROM Movie
        INNER JOIN MovieGenre 
        ON MovieGenre.MovieId = Movie.Id AND MovieGenre.GenreId = 11
    WHERE Title LIKE '%s%'
) AS Count FROM Movie 
    INNER JOIN MovieGenre 
    ON MovieGenre.MovieId = Movie.Id AND MovieGenre.GenreId = 11
WHERE Title LIKE '%s%' LIMIT 8;

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


-14
SELECT * 
FROM table 
WHERE some_condition 
ORDER BY RAND()
LIMIT 0, 10

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