SQL查询性能优化 之 LEFT JOIN 替换 NOT IN

       今天工作的时候遇到一个需求,如下:

      
       有体育赛事信息实体Game,Game可以在后台管理系统中被指定为APP或者PC网站的首页推荐,当一个赛事(Game)被指定为首页推荐后,在客户端看到的效果是,被推荐赛事的一张大图加入到首页轮播(HomeSlideShow)中,点击图片,即可跳转到相对应的赛事详情页。


       客户要求每个赛事赛事(Game)只能被推荐一次,不能重复推荐。


       现有赛事信息表game, 和首页推荐表slideshow,字段如下


Game  
ID varchar(50)
NAME varchar(50)

SlideShow  
ID varchar(50)
GID varchar(50)
TITLE varchar(100)



       在组织SQL语句,查询未添加过首页推荐的赛事(Game)时,很容易写成:

      

   SELECT ID, NAME FROM Game WHERE ID NOT IN (SELECT GID FROM SlideShow);

       我们知道NOT IN的查询效率是非常低的,因为它不能使用索引,大大降低查询效率。


       那么,在需要NOT IN的时候如何用什么替代它能?


       常见的可以使用LEFT JOIN...IS NULL的方式达到同样的目的。


       例如上面的SQL可以改成:


   SELECT ID, NAME FROM (SELECT g.ID, g.NAME s.GID FROM Game g LEFT JOIN SlideShow s ON(g.ID = s.GID)) c WHERE c.GID IS NULL;

       这里主要用到了左向外联接的结果集包括  LEFT (OUTER)子句中指定的左表(这里指Game)的所有行,而不仅仅是联接列(Game.ID和SlideShow.GID)所匹配的行。如果左表(Game)的某行在右表(SlideShow)中没有匹配行,则在相关联的结果集行中右表的所有选择列表列均为空值。


       也就是说,我们把Game表和SlideShow两张表拿出来按照Game.ID = SlideShow.GID的规则对比一下,生成一个临时表c(也可以理解成把两张表按照上述规则合并一下,合并后的表是c,这里并没有真正生成物理上的表c)。理论上SlideShow中GID都可以在Game表的ID列找到对应的值,反之在SlideShow的GID的列并不一定能找到Game表中ID列上的所有值,所以,我们通过左联接查询,发现c.GID的为空,那么就意味着该行的c.ID就是我们需要的Game的ID。


       虽然这篇文章的标题是用LEFT JOIN 代替 NOT IN,但在上面的解释中,我并没有说一定要用左外连接代替NOT IN,而不能用RIGHT JOIN。因为RIGHT JOIN也是可以的,道理都是一样的。例如你也可以把上面的左外联接改成下面的右外连接查询:


   SELECT ID, NAME FROM (SELECT g.ID, g.NAME s.GID FROM SlideShow s RIGHT JOIN Game g ON(g.ID = s.GID)) c WHERE c.GID IS NULL;


       具体NOT IN如何影响SQL性能、以及上述方法为什么比用NOT IN效率更高,除了和使用索引有关外,更深入的我也在学习中。也希望能得到各位前辈的指点!

你可能感兴趣的:(数据库)