2013-04-14 13 views
7

में प्राकृतिक जॉइन बनाम हाल ही में, मैंने एक बड़ी मात्रा में डेटा पुनर्प्राप्त करने के साथ निपटाया जिसमें MySQL डेटाबेस से हजारों रिकॉर्ड शामिल हैं। चूंकि यह इतना बड़ा डेटा सेट संभालने का मेरा पहला समय था, इसलिए मैंने SQL कथन की दक्षता के बारे में नहीं सोचा था। और समस्या आती है।क्लाउड

यहाँ डेटाबेस की तालिकाओं कर रहे हैं (यह एक पाठ्यक्रम प्रणाली की बस एक साधारण डेटाबेस मॉडल है):

पाठ्यक्रम:

+-----------+---------------------+------+-----+---------+----------------+ 
| Field  | Type    | Null | Key | Default | Extra   | 
+-----------+---------------------+------+-----+---------+----------------+ 
| course_id | int(10) unsigned | NO | PRI | NULL | auto_increment | 
| name  | varchar(20)   | NO |  | NULL |    | 
| lecturer | varchar(20)   | NO |  | NULL |    | 
| credit | float    | NO |  | NULL |    | 
| week_from | tinyint(3) unsigned | NO |  | NULL |    | 
| week_to | tinyint(3) unsigned | NO |  | NULL |    | 
+-----------+---------------------+------+-----+---------+----------------+ 

का चयन करें:

+-----------+------------------+------+-----+---------+----------------+ 
| Field  | Type    | Null | Key | Default | Extra   | 
+-----------+------------------+------+-----+---------+----------------+ 
| select_id | int(10) unsigned | NO | PRI | NULL | auto_increment | 
| card_no | int(10) unsigned | NO |  | NULL |    | 
| course_id | int(10) unsigned | NO |  | NULL |    | 
| term  | varchar(7)  | NO |  | NULL |    | 
+-----------+------------------+------+-----+---------+----------------+ 

जब मैं छात्र द्वारा चुने गए सभी पाठ्यक्रमों को पुनर्प्राप्त करना चाहते हैं (उनके कार्ड नंबर के साथ), एसक्यूएल कथन

012 है
SELECT course_id, name, lecturer, credit, week_from, week_to 
FROM `course` WHERE course_id IN (
    SELECT course_id FROM `select` WHERE card_no=<student's card number> 
); 

लेकिन, यह बेहद धीमा था और यह लंबे समय तक कुछ भी वापस नहीं आया। तो मैंने खंड NATURAL JOIN में बदल दिया। यहां एसक्यूएल,

SELECT course_id, name, lecturer, credit, week_from, week_to 
FROM `select` NATURAL JOIN `course` 
WHERE card_no=<student's card number>; 

यह तुरंत लौटता है और ठीक काम करता है!

तो मेरे सवाल है:

  • NATURAL JOIN और WHERE IN क्लाज के बीच क्या अंतर है?
  • उन्हें अलग-अलग प्रदर्शन कैसे करता है? (क्या ऐसा हो सकता है क्योंकि मैं कोई INDEX स्थापित नहीं करता हूं?)
  • हम NATURAL JOIN या WHERE IN का उपयोग कब करेंगे?
+2

'चयन' एक तालिका के लिए एक भयानक नाम है। –

उत्तर

4

सैद्धांतिक रूप से दो प्रश्न समकक्ष हैं। मुझे लगता है कि यह MySQL क्वेरी ऑप्टिमाइज़र का केवल खराब कार्यान्वयन है जो जॉइन इनके मुकाबले अधिक कुशल होने का कारण बनता है। तो मैं हमेशा जॉइन का उपयोग करता हूं।

क्या आपने दो प्रश्नों के लिए EXPLAIN के आउटपुट को देखा है? यहाँ मैं एक WHERE IN के लिए मिल गया है:

+----+--------------------+-------------------+----------------+-------------------+---------+---------+------------+---------+--------------------------+ 
| 1 | PRIMARY   | t_users   | ALL   | NULL    | NULL | NULL | NULL  | 2458304 | Using where    | 
| 2 | DEPENDENT SUBQUERY | t_user_attributes | index_subquery | PRIMARY,attribute | PRIMARY | 13  | func,const |  7 | Using index; Using where | 
+----+--------------------+-------------------+----------------+-------------------+---------+---------+------------+---------+--------------------------+ 

यह जाहिरा तौर पर सबक्वेरी प्रदर्शन कर रहा है, तो मुख्य तालिका परीक्षण में प्रत्येक पंक्ति के माध्यम से जा है कि क्या यह में है - यह सूचकांक का उपयोग नहीं करता। जॉइन के लिए मुझे मिलता है:

+----+-------------+-------------------+--------+---------------------+-----------+---------+---------------------------------------+------+-------------+ 
| id | select_type | table    | type | possible_keys  | key  | key_len | ref         | rows | Extra  | 
+----+-------------+-------------------+--------+---------------------+-----------+---------+---------------------------------------+------+-------------+ 
| 1 | SIMPLE  | t_user_attributes | ref | PRIMARY,attribute | attribute | 1  | const         | 15 | Using where | 
| 1 | SIMPLE  | t_users   | eq_ref | username,username_2 | username | 12  | bbodb_test.t_user_attributes.username | 1 |    | 
+----+-------------+-------------------+--------+---------------------+-----------+---------+---------------------------------------+------+-------------+ 

अब यह सूचकांक का उपयोग करता है। उप क्वेरी में के अलावा और खंड

SELECT course_id, name, lecturer, credit, week_from, week_to 
FROM `course` c 
WHERE c.course_id IN (
    SELECT s.course_id 
    FROM `select` s 
    WHERE card_no=<student's card number> 
    AND c.course_id = s.course_id 
); 

नोटिस:

+1

दो प्रश्न बराबर नहीं हैं। एक जॉइन उप-चयन से अलग परिणाम देगा। –

+0

@a_horse_with_no_name यदि उप-चयन केवल 'row_id' प्रति पंक्ति एक पंक्ति देता है, तो दोनों बराबर हैं। यदि यह कई पंक्तियों को वापस कर सकता है, तो शामिल होने से क्रॉस-उत्पाद उत्पन्न होता है जबकि कहां से केवल एक पंक्ति प्रति पंक्ति उत्पन्न करेगा। – Barmar

+1

बिल्कुल। और वहां उन दो बयानों के लिए एक ही बात नहीं है (वे जाहिर है कि इस मामले में एक ही परिणाम लौटने के लिए ऐसा होता है जो "बराबर होने" जैसा नहीं है)। उनका मतलब मूल रूप से कुछ अलग है और @ आरए को इसके बारे में पता होना चाहिए। –

3

इस प्रयास करें। इसे सह-संबंधित उप-क्वेरी कहा जाता है क्योंकि यह दो पाठ्यक्रम_आईड्स से संबंधित है, जैसे कि प्राकृतिक जॉइन करता है।

मुझे लगता है कि बाड़मेर की इंडेक्स स्पष्टीकरण चिह्न पर है।

संबंधित मुद्दे