रैंड() द्वारा MySQL का ऑर्डर कैसे काम करता है?




select random (3)

मैं MySQL में तेज़ यादृच्छिक चयन करने के तरीके पर कुछ शोध और परीक्षण कर रहा हूं। इस प्रक्रिया में मुझे कुछ अप्रत्याशित परिणाम सामने आए हैं और अब मुझे पूरा यकीन नहीं है कि मुझे पता है कि रैंड () वास्तव में कैसे काम करता है।

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

SELECT * FROM Table T JOIN (SELECT CEIL(MAX(ID)*RAND()) AS ID FROM Table) AS x ON T.ID >= x.ID LIMIT 1;

जबकि सामान्य ऑर्डर द्वारा रैंड () मेरी टेस्ट टेबल पर 30-40 सेकंड लेता है, उसकी क्वेरी 0.1 सेकंड में काम करती है। वह बताता है कि ब्लॉग में यह कैसे काम करता है, इसलिए मैं इसे छोड़ दूंगा और आखिरकार अजीब बात पर जाउंगा।

मेरी तालिका एक प्राथमिक कुंजी id और username , age इत्यादि जैसी अन्य गैर-अनुक्रमित सामग्री है। यह वह चीज है जिसे मैं समझाने के लिए संघर्ष कर रहा हूं

SELECT * FROM table ORDER BY RAND() LIMIT 1; /*30-40 seconds*/
SELECT id FROM table ORDER BY RAND() LIMIT 1; /*0.25 seconds*/
SELECT id, username FROM table ORDER BY RAND() LIMIT 1; /*90 seconds*/

मैं लगभग तीन प्रश्नों के लिए लगभग एक ही समय देखने की उम्मीद कर रहा था क्योंकि मैं हमेशा एक कॉलम पर सॉर्ट कर रहा हूं। लेकिन किसी कारण से ऐसा नहीं हुआ। यदि आप इसके बारे में कोई विचार करते हैं तो कृपया मुझे बताएं। मेरे पास एक प्रोजेक्ट है जहां मुझे रैंड () द्वारा तेजी से आदेश देने की ज़रूरत है और व्यक्तिगत रूप से मैं इसका उपयोग करना पसंद करूंगा

SELECT id FROM table ORDER BY RAND() LIMIT 1;
SELECT * FROM table WHERE id=ID_FROM_PREVIOUS_QUERY LIMIT 1;

जो, हाँ, जय की विधि से धीमी है, हालांकि यह समझना छोटा और आसान है। मेरे प्रश्न कई जॉइन और WHERE क्लॉज के साथ बड़े हैं और जब जय की विधि अभी भी काम करती है, तो सवाल वास्तव में बड़ा और जटिल हो जाता है क्योंकि मुझे जॉइन (जिसे उसकी क्वेरी में एक्स कहा जाता है) में सभी जॉइन और कहां उपयोग करने की आवश्यकता होती है।

आपके समय के लिए धन्यवाद!


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

अभ्यास बेहतर है कि सभी सिद्धांतों! योजनाओं की जांच क्यों न करें? :)

mysql> explain select name from avatar order by RAND() limit 1;
+----+-------------+--------+-------+---------------+-----------------+---------+------+-------+----------------------------------------------+
| id | select_type | table  | type  | possible_keys | key             | key_len | ref  | rows  | Extra                                        |
+----+-------------+--------+-------+---------------+-----------------+---------+------+-------+----------------------------------------------+
|  1 | SIMPLE      | avatar | index | NULL          | IDX_AVATAR_NAME | 302     | NULL | 30062 | Using index; Using temporary; Using filesort |
+----+-------------+--------+-------+---------------+-----------------+---------+------+-------+----------------------------------------------+
1 row in set (0.00 sec)

mysql> explain select * from avatar order by RAND() limit 1;
+----+-------------+--------+------+---------------+------+---------+------+-------+---------------------------------+
| id | select_type | table  | type | possible_keys | key  | key_len | ref  | rows  | Extra                           |
+----+-------------+--------+------+---------------+------+---------+------+-------+---------------------------------+
|  1 | SIMPLE      | avatar | ALL  | NULL          | NULL | NULL    | NULL | 30062 | Using temporary; Using filesort |
+----+-------------+--------+------+---------------+------+---------+------+-------+---------------------------------+
1 row in set (0.00 sec)

 mysql> explain select name, experience from avatar order by RAND() limit 1;
+----+-------------+--------+------+--------------+------+---------+------+-------+---------------------------------+
| id | select_type | table  | type | possible_keys | key  | key_len | ref  | rows  | Extra                           |
+----+-------------+--------+------+---------------+------+---------+------+-------+---------------------------------+
|  1 | SIMPLE      | avatar | ALL  | NULL          | NULL | NULL    | NULL | 30064 | Using temporary; Using filesort |
+----+-------------+--------+------+---------------+------+---------+------+-------+---------------------------------+

आप इंडेक्स id, username क्यों नहीं जोड़ते हैं id, username तालिका पर id, username देखते हैं कि क्या यह mysql को सिर्फ एक फाइलोर्ट और अस्थायी तालिका के बजाय इंडेक्स का उपयोग करने के लिए मजबूर करता है।


हालांकि "रैंड () द्वारा तेज़ क्रम" जैसी कोई चीज़ नहीं है, आपके विशिष्ट कार्य के लिए एक कार्यवाही है।

किसी भी यादृच्छिक पंक्ति को प्राप्त करने के लिए , आप इस जर्मन ब्लॉगर की तरह कर सकते हैं: http://www.roberthartung.de/mysql-order-by-rand-a-case-study-of-alternatives/ (मैं नहीं देख सका एक हॉटलिंक यूआरएल। अगर कोई एक देखता है, तो लिंक को संपादित करने के लिए स्वतंत्र महसूस करें।)

पाठ जर्मन में है, लेकिन एसक्यूएल कोड पृष्ठ के नीचे और बड़े सफेद बक्से में थोड़ा सा है, इसलिए इसे देखना मुश्किल नहीं है।

असल में वह जो करता है वह एक प्रक्रिया बनाता है जो वैध पंक्ति प्राप्त करने का काम करता है। इससे 0 और max_id के बीच एक यादृच्छिक संख्या उत्पन्न होती है, एक पंक्ति लाने का प्रयास करें, और यदि यह अस्तित्व में नहीं है, तब तक जारी रखें जब तक आप ऐसा नहीं करते हैं। वह एक अस्थायी पंक्तियों में उन्हें संग्रहीत करके यादृच्छिक पंक्तियों की एक्स संख्या लाने की अनुमति देता है, ताकि आप संभवतः केवल एक पंक्ति लाने के लिए प्रक्रिया को फिर से लिख सकें।

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

अद्यतन: विभिन्न निष्पादन समय

चुनें * रैंड द्वारा टेबल ऑर्डर से () LIMIT 1; / 30-40 सेकंड /

रैंड द्वारा टेबल ऑर्डर से आईडी चुनें () LIMIT 1; / 0.25 सेकंड /

चयन आईडी, रैंक द्वारा तालिका ऑर्डर से उपयोगकर्ता नाम () LIMIT 1; / 9 0 सेकंड /

मैं लगभग तीन प्रश्नों के लिए लगभग एक ही समय देखने की उम्मीद कर रहा था क्योंकि मैं हमेशा एक कॉलम पर सॉर्ट कर रहा हूं। लेकिन किसी कारण से ऐसा नहीं हुआ। यदि आप इसके बारे में कोई विचार करते हैं तो कृपया मुझे बताएं।

इसे अनुक्रमण के साथ करना पड़ सकता है। id अनुक्रमित है और पहुंचने में तेज़ी से है, जबकि परिणामस्वरूप username जोड़ना है, इसका मतलब है कि इसे प्रत्येक पंक्ति से पढ़ने और मेमोरी टेबल में रखना होगा। * इसे सब कुछ स्मृति में भी पढ़ना है, लेकिन इसे डेटा फ़ाइल के चारों ओर कूदने की आवश्यकता नहीं है, जिसका अर्थ है कि कोई समय गुम हो गया है।

यह केवल तभी फर्क पड़ता है जब परिवर्तनीय लम्बाई कॉलम (वर्कर / टेक्स्ट) हो, जिसका अर्थ है कि उसे लंबाई की जांच करनी है, फिर उस लंबाई को छोड़ दें, क्योंकि प्रत्येक पंक्ति के बीच एक सेट लम्बाई (या 0) छोड़ने के विपरीत।





random