MySQL的表联结
MySQL的联结操作使得我们可以在一次查询对对多个数据表进行检索,这些联结操作包括:
內联结:INNER JOIN,CROSS JOIN,JOIN
以上三种联结类型类似,结果集中只包含两个表中匹配的数据。 (有时会看到select * from t1,t2的语法,这种操作和INNER JOIN类似,但优先级和其他联结操作会有所区别 )
外联结:LEFT JOIN,RIGHT JOIN
LEFT JOIN的查询原理
在使用LEFT JOIN联结查询时,每次会从左表中选出一条记录,然后根据ON或USING等条件,从右表中选出所有B表中匹配的数据,假如B表中有N条数据符合LEFT JOIN的ON或USING等条件,那么最终LEFT JOIN之后,对应于A的这条数据,将会产生N条数据。(也正因为这个原因,在使用join做查询的时候,需要评估好join之后可能产生的数据量,尽量比较一对多或多对多的情况)
若检索后没有匹配数据,右表的所有列将填充为NULL。
而在这个匹配过程中,where子句不会被执行。当左右两个表匹配完成之后,执行where子句中的条件,并从匹配的数据中筛选出符合where条件的数据。
LEFT JOIN的优化
LEFT JOIN的优化针对的是加了where查询条件的情况,此时,MySQL遵循以下几个原则:
对于A LEFT JOIN B的查询
- 所有的WHERE查询条件的优化跟一般非联结操作的SQL查询保持一致
- LEFT JOIN从最左边的表做联结,也就是说,首先会拿左表的数据,根据ON或USING等或USING等限定的联结条件,依次从右表中检索符合条件的数据。那么对于左表中不存在右表中对应数据的情况,这些数据是不会出现在结果集中的。
- 左表中的数据需要依赖所有出现在LEFT JOIN条件中的表,当然,不包括LEFT JOIN右表的数据。
- LEFT JOIN中的ON或USING等条件只用来检索B表中的数据。
- 如果一条数据在A表中符合where条件,而B表中不存在符合ON或USING等条件的数据,那么join之后产生的临时表中,对应B的字段将会被填充为NULL。如果通过LEFT JOIN来查找其他表没有的数据,并且这个表中某个字段ColumnName不为NULL,可以通过在where条件中使用
ColumnName is null
来查找表中不存在的数据。通过这种方式MySQL在查找到一个符合条件的数据之后就会停止检索。 - 在执行join的查询时,被依赖的表的数据将会被首先加载,所以如果出现循环依赖的情况,此时查询会出现异常。
接下来看下具体的例子:
- join的优化器会针对对联结表的顺序做一个判断,由于LEFT JOIN和STRAIGHT JOIN已经强制规定了联结的顺序,所以这两种查询会相对其他联结操作快一些,以下三个查询SQL显示了MySQL的检索数据的顺序。
需要注意的是,表中数据量的大小会影响到索引的使用情况
当联结的字段未建立索引时:
当联结的字段建立索引后(注意当表中数据量很少时,这个时候不会使用索引做检索):
调换表的联结顺序后,a表被首先检索:
所以对于在where条件中需要做过滤的表,如果能首先被MySQL检索到的话,会对检索性能有一定程度的提高。
- 在ON或USING等条件中若出现永远为false的条件,那么右边将会全部置为NULL
对于这种情况,保险的做法是把不需要联结的字段放入到where条件中检索
建表语句
CREATE TABLE `TABLE1` (
`ID` bigint(8) unsigned NOT NULL AUTO_INCREMENT PRIMARY KEY COMMENT '主键',
`COLUMN1` varchar(16) NOT NULL COMMENT 'COLUMN1',
`COLUMN2` varchar(16) NOT NULL COMMENT 'COLUMN2',
KEY `IDX_COLUMN1` (`COLUMN1`)
)
INSERT INTO `user`.`TABLE1` (`COLUMN1`, `COLUMN2`) VALUES ('a', 'a');
INSERT INTO `user`.`TABLE1` (`COLUMN1`, `COLUMN2`) VALUES ('b', 'b');
参考: