2013-04-14 25 views
7

最近、私は、MySQLデータベースから数千のレコードで構成される大量のデータを取得することに取り組んだ。このような大きなデータセットを処理するのは初めてのことだったので、SQL文の効率性については考えていませんでした。そして、問題が起こります。ここで NATURAL JOINとWHERE IN句

は(それはカリキュラムシステムの単純なデータベースモデルである)データベース のテーブルです:

コース:

+-----------+---------------------+------+-----+---------+----------------+ 
| 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 |    | 
+-----------+------------------+------+-----+---------+----------------+ 

Iを学生が(カード番号で)選択したすべてのコースを検索したい場合、 のSQL文は

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> 
); 

しかし、非常に遅く、長時間何も返さなかった。 WHERE IN節をNATURAL JOINに変更しました。ここにSQLがあります。

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

すぐに戻り、正常に動作します!

だから私の質問は次のとおりです。

  • NATURAL JOINWHERE IN節の違いは何ですか?
  • これらの機能が異なるのはなぜですか? (INDEXを設定していない可能性がありますか?)
  • NATURAL JOINまたはWHERE INはいつ使用しますか?
+2

'select'はテーブルのawfull名です。 –

答えて

4

理論的には、2つのクエリは同等です。私は、MySQLクエリオプティマイザの実装がうまくいかないため、JOINがWHERE INよりも効率的になると思います。だから私はいつもJOINを使います。

2つのクエリについて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 | 
+----+--------------------+-------------------+----------------+-------------------+---------+---------+------------+---------+--------------------------+ 

それは明らかにそれはでますかどうかをテストメインテーブルのすべての行を通過、サブクエリを実行しています - それは、インデックスを使用しません。 JOINの場合:

+----+-------------+-------------------+--------+---------------------+-----------+---------+---------------------------------------+------+-------------+ 
| 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 
); 

お知らせサブクエリでAND句の追加:

+1

2つのクエリは同等ではありません。 JOINはサブ選択とは異なる結果を生成します。 –

+0

@a_horse_with_no_name副選択が 'course_id'ごとに1つの行しか戻さない場合、2つは等価です。複数の行を返すことができる場合、結合はクロス積を生成し、一方、where-inは1つのコースにつき1つの行しか生成しません。 – Barmar

+1

正確に。そのため、これらの2つのステートメントは同じものではありません(これらのステートメントは「同等」と同じではありません)。彼らは根本的に異なる何かを意味し、@ rAyはそれを認識すべきです。 –

3

はこれを試してみてください。 NATURAL JOINと同じように、2つのcourse_idsに関連するので、これは共同関連サブクエリと呼ばれます。

私はBarmarのインデックスの説明は印だと思います。