那么谓词下推第二层含义,即何时完成数据过滤则一般是在指连接查询中,是先对单表数据进行过滤再和其他表连接还是在先把多表进行连接再对连接后的临时表进行过滤,则是本系列文章要分析和讨论的重点。
4.内连接查询中的谓词下推规则假设我们有两张表,表结构很简单,数据也都只有两条,但是足以讲清楚我们的下推规则,两表如下,一个lefttable,一个righttable:
4.1.Join后条件通过AND连接先来看一条查询语句:
这个查询是一个内连接查询,join后条件是用and连接的两个表的过滤条件,假设我们不下推,而是先做内连接判断,这时是可以得到正确结果的,步骤如下:
左表id为1的行在右表中可以找到,即这两行数据可以"join"在一起
左表id为2的行在右表中可以找到,这两行也可以"join"在一起
至此,join的临时结果表(之所以是临时表,因为还没有进行过滤)如下:
然后使用where条件进行过滤,显然临时表中的第一行不满足条件,被过滤掉,最后结果如下:
来看看先进行谓词下推的情况。先对两表进行过滤,过滤的结果分别如下:
然后再对这两个过滤后的表进行内连接处理,结果如下:
可见,这和先进行join再过滤得到的结果一致。
4.2.Join后条件通过OR连接再来看一条查询语句:
我们先进行join处理,临时表的结果如下:
然后使用where条件进行过滤,最终查询结果如下:
如果我们先使用where条件后每个表各自的过滤条件进行过滤,那么两表的过滤结果如下:
然后对这两个临时表进行内连接处理,结果如下:
表格有问题吧,只有字段名,没有字段值,怎么回事?是的,你没看错,确实没有值,因为左表过滤结果只有id为1的行,右表过滤结果只有id为2的行,这两行是不能内连接上的,所以没有结果。
那么为什么where条件中两表的条件被or连接就会出现错误的查询结果呢?分析原因主要是因为,对于or两侧的过滤条件,任何一个满足条件即可以返回TRUE,那么对于"LT.value = 'two' OR RT.value = 'two' "这个查询条件,如果使用LT.value='two'把只有LT.value为'two'的左表记录过滤出来,那么对于左表中LT.value不为two的行,他们可能在跟右表使用id字段连接上之后,右表的RT.value恰好为two,也满足"LT.value = 'two' OR RT.value = 'two' ",但是可惜呀可惜,这行记录因为之前的粗暴处理,已经被过滤掉,结果就是得到了错误的查询结果。所以这种情况下谓词是不能下推的。大数据技术答疑扣扣群:606加+八五九+705,无论你是初学者小白还是大牛都欢迎,资料分享一起学习进步。
但是OR连接两表join后条件也有两个例外,这里顺便分析第一个例外。第一个例外是过滤条件字段恰好为Join字段,比如如下的查询:
在这个查询中,join后条件依然是使用OR连接两表的过滤条件,不同的是,join中条件不再是id相等,而是value字段相等,也就是说过滤条件字段恰好就是join条件字段。大家可以自行采用上边的分步法分析谓词下推和不下推时的查询结果,得到的结果是相同的。
我们来看看上边不能下推时出现的情况在这种查询里会不会出现。对于左表,如果使用LT.value='two'过滤掉不符合条件的其他行,那么因为join条件字段也是value字段,说明在左表中LT.value不等于two的行,在右表中也不能等于two,否则就不满足"LT.value=RT.value"了。这里其实有一个条件传递的过程,通过join中条件,已经在逻辑上提前把两表整合成了一张表。
至于第二个例外,则涉及了SparkSql中的一个优化,所以需要单独介绍。
4.3.分区表使用OR连接过滤条件如果两个表都是分区表,会出现什么情况呢?我们先来看如下的查询: