MySQL中三种关联查询方式的简单比较
看看下面三个关联查询的SQL语句有何区别?
SELECT*FROMfilmJOINfilm_actorON(film.film_id=film_actor.film_id) SELECT*FROMfilmJOINfilm_actorUSING(film_id) SELECT*FROMfilm,film_actorWHEREfilm.film_id=film_actor.film_id
最大的不同更多是语法糖,但有一些有意思的东西值得关注。
为了方便区别,我们将前两种写法称作是ANSI风格,第三种称为Theta风格。
Theta风格
在FROM短语中列出了关联的表名,而WHERE短语则指定如何关联。
这种写法被认为是古老的方式,有些时候比较难以理解,请看下面查询:
SELECT*FROMfilm,film_actorWHEREfilm.film_id=film_actor.film_idANDactor_id=17ANDfilm.length>120
上述查询列出片长超过120分钟的电影,其中包括演员编号是17的条件。别在意查询结果,查询本身如何呢?WHERE表达式中包含三个条件,要看出哪个条件是关联,哪个条件是过滤还是稍费点事的。不过还是相对简单的,但如果是5个表,20多个条件呢?
ANSI风格:ON
使用JOIN...ON可以将表关联的条件和记录过滤条件分开,将上面的语句重写后的结果如下:
SELECT*FROMfilmJOINfilm_actorON(film.film_id=film_actor.film_id)WHEREactor_id=17ANDfilm.length>120
看起来清晰许多。
注意:ON语句中的括号不是必须的,我个人喜欢这样写而已。
ANSI风格:USING
有一种特殊情况,当两个要关联表的字段名是一样的,我们可以使用 USING,可减少SQL语句的长度:
SELECT*FROMfilmJOINfilm_actorUSING(film_id)WHEREactor_id=17ANDfilm.length>120
这个时候括号就是必须的了。这种写法很好,输入更少的单词,查询的性能也非常棒,但还需要注意一些差异。
USING和ON
下面语句是可行的:
SELECTfilm.title,film_idFROMfilmJOINfilm_actorUSING(film_id)WHEREactor_id=17ANDfilm.length>120;
但下面这个就不行:
SELECTfilm.title,film_idFROMfilmJOINfilm_actorON(film.film_id=film_actor.film_id)WHEREactor_id=17ANDfilm.length>120;ERROR1052(23000):Column'film_id'infieldlistisambiguous
因为USING"知道"film_id字段在两个表中都有,所以没有指定确切的表都没关系,两个值必须一致就是。
ON就没那么智能,你必须指明要关联的表和字段名。
上面两个实际的结果是比较有趣的,当使用USING时,字段只在结果中出现一次:
SELECT*FROMfilmJOINfilm_actorUSING(film_id)WHEREactor_id=17ANDfilm.length>120LIMIT1\G ***************************1.row*************************** film_id:96 title:BREAKINGHOME description:ABeautifulDisplayofaSecretAgentAndaMonkeywhomustBattleaSumoWrestlerinAnAbandonedMineShaft release_year:2006 language_id:1 original_language_id:NULL rental_duration:4 rental_rate:2.99 length:169 replacement_cost:21.99 rating:PG-13 special_features:Trailers,Commentaries last_update:2006-02-1505:03:42 actor_id:17 last_update:2006-02-1505:05:03
而使用ON时,字段就会出现两次:
SELECT*FROMfilmJOINfilm_actorONfilm.film_id=film_actor.film_idWHEREactor_id=17ANDfilm.length>120LIMIT1\G ***************************1.row*************************** film_id:96 title:BREAKINGHOME description:ABeautifulDisplayofaSecretAgentAndaMonkeywhomustBattleaSumoWrestlerinAnAbandonedMineShaft release_year:2006 language_id:1 original_language_id:NULL rental_duration:4 rental_rate:2.99 length:169 replacement_cost:21.99 rating:PG-13 special_features:Trailers,Commentaries last_update:2006-02-1505:03:42 actor_id:17 film_id:96 last_update:2006-02-1505:05:03
幕后
MySQL对两者的处理方式是相同的,使用EXPLAINEXTENDED我们可以看到:
EXPLAINEXTENDEDSELECTfilm.title,film_idFROMfilmJOINfilm_actorUSING(film_id)WHEREactor_id=17ANDfilm.length>120\G ***************************1.row*************************** ... 2rowsinset,1warning(0.00sec) root@mysql-5.1.51>SHOWWARNINGS\G ***************************1.row*************************** Level:Note Code:1003 Message:select`sakila`.`film`.`title`AS`title`,`sakila`.`film`.`film_id`AS`film_id` from`sakila`.`film`join`sakila`.`film_actor` where( (`sakila`.`film`.`film_id`=`sakila`.`film_actor`.`film_id`) and(`sakila`.`film_actor`.`actor_id`=17) and(`sakila`.`film`.`length`>120) )
最终所有的查询都被转成了Theta风格。
译者:就是说这三种方式除了写法不同外,没什么区别。