Skip to content

HIVE-23006 ProbeDecode compiler support#952

Closed
pgaref wants to merge 7 commits intoapache:masterfrom
pgaref:HIVE-23006
Closed

HIVE-23006 ProbeDecode compiler support#952
pgaref wants to merge 7 commits intoapache:masterfrom
pgaref:HIVE-23006

Conversation

@pgaref
Copy link
Contributor

@pgaref pgaref commented Mar 12, 2020

This patch adds an extra optimisation step with the goal of finding Table Scan operators that could reduce the number of rows decoded at runtime using extra available information.

It currently looks for all the available MapJoin operators that could use the smaller HashTable on the probing side (where TS is) to filter-out rows that would never match.
To do so the HashTable information is pushed down to the TS properties and then propagated as part of MapWork.
If the a single TS is used by multiple operators (shared-word), this rule can not be applied.

Copy link
Contributor

@jcamachor jcamachor left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I started taking a look at your patch as well as code in master.
I believe following approach would be easier since you could rely on existing SJ logic.
You could modify method removeSemijoinsParallelToMapJoin in TezCompiler. In particular, findParallelSemiJoinBranch already finds all semijoins originating in a MapJoin input (note that you may need small modification in this block to not skip adding them to the map). After calling that method, semijoins will contain pairs (RS, TS). You will enter this block if TEZ_DYNAMIC_SEMIJOIN_REDUCTION_FOR_MAPJOIN is true (note that you have to remove this condition from L1450). Else, if HIVE_MAPJOIN_PROBEDECODE_ENABLED is true, you will need to remove the SJs (same as the block is doing) and create your optimization data structures, i.e., your context in the TS as you are currently doing. You may end up with multiple MJ targeting a single TS; you can generate a context for each of them, store these in the TS, and decide later on a strategy to apply the filtering based on a config parameter. Let me know if this makes sense.

Cc @t3rmin4t0r

@pgaref
Copy link
Contributor Author

pgaref commented Mar 24, 2020

I started taking a look at your patch as well as code in master.
I believe following approach would be easier since you could rely on existing SJ logic.
You could modify method removeSemijoinsParallelToMapJoin in TezCompiler. In particular, findParallelSemiJoinBranch already finds all semijoins originating in a MapJoin input (note that you may need small modification in this block to not skip adding them to the map). After calling that method, semijoins will contain pairs (RS, TS). You will enter this block if TEZ_DYNAMIC_SEMIJOIN_REDUCTION_FOR_MAPJOIN is true (note that you have to remove this condition from L1450). Else, if HIVE_MAPJOIN_PROBEDECODE_ENABLED is true, you will need to remove the SJs (same as the block is doing) and create your optimization data structures, i.e., your context in the TS as you are currently doing. You may end up with multiple MJ targeting a single TS; you can generate a context for each of them, store these in the TS, and decide later on a strategy to apply the filtering based on a config parameter. Let me know if this makes sense.

Cc @t3rmin4t0r

Hey @jcamachor , thanks for the comments!
I updated the patch to capture all (MJ, TS) pairs as part of semijoinRemovalBasedTransformations https://github.com/apache/hive/pull/952/files#diff-228178321e4c1df7f045fe181de2fffaR1453

I believe the TEZ_DYNAMIC_SEMIJOIN_REDUCTION_FOR_MAPJOIN flag should be false for semijoin removal to kick in (if true the whole method returned in the clean version)
https://github.com/apache/hive/pull/952/files#diff-228178321e4c1df7f045fe181de2fffaR1455

The idea of storing multiple MJ targets as part of a TS also makes sense to me -- I guess the decision could be part of GenTezUtils or earlier optimisation rules -- what do you think? https://github.com/apache/hive/pull/952/files#diff-4a039ee6b13e42df6ff51e85db691132R199

PS: Was also thinking that the naming of this is a bit off (HIVE_MAPJOIN_PROBEDECODE) -- as this can also be used for static expression.

@jcamachor
Copy link
Contributor

jcamachor commented Apr 3, 2020

@pgaref , thanks for changes. Patch looks good. About the name, I think it is fine (probe side for the filtering generated statically in case of expressions or dynamically for joins).

I think main remaining issue is related to selection in case of multiple MJ operators. I was thinking that for the time being, we could make the policy pluggable via config and have two very simple ones: 1) keep the one with lowest ndv_JOIN_probe_key_column / ndv_TS_target_column ratio, or 2) keep those with ratio below a certain threshold specified through a config value. Alternatively, in this patch you could maybe go only with option 1 and tackle other in follow-up.

You have the information about the stats in the operators themselves (follow op.getStatistics() calls to see how it is retrieved per column basis). Thus, I would make that decision in the TezCompiler (once we gather all the context information) rather than GenTezUtils.

@pgaref
Copy link
Contributor Author

pgaref commented Apr 6, 2020

@pgaref , thanks for changes. Patch looks good. About the name, I think it is fine (probe side for the filtering generated statically in case of expressions or dynamically for joins).

I think main remaining issue is related to selection in case of multiple MJ operators. I was thinking that for the time being, we could make the policy pluggable via config and have two very simple ones: 1) keep the one with lowest ndv_JOIN_probe_key_column / ndv_TS_target_column ratio, or 2) keep those with ratio below a certain threshold specified through a config value. Alternatively, in this patch you could maybe go only with option 1 and tackle other in follow-up.

You have the information about the stats in the operators themselves (follow op.getStatistics() calls to see how it is retrieved per column basis). Thus, I would make that decision in the TezCompiler (once we gather all the context information) rather than GenTezUtils.

@jcamachor thanks for the review, I appreciate it!

Please check the latest changes with:

  • More generic probeDecode name for HiveConf

  • TezCompiler with configurable logic to select a MJ when we have multiple per TS -- currently picking the one with the lowest MJ/TS key Ratio

  • SharedWork using a TS on multiple branches clears probeContext that would result in wrong results

  • probeContextDetails as part of the explained plan

  • ProbeDecode Test cases with and without table stats

Thoughts?

My last concern is some operators like VectorPTFEvaluatorDecimalAvg that do not allow the use of Selected (which is what probedecode is doing) and whether we should take that into account as part of the optimizations.

Panos Garefalakis added 7 commits April 12, 2020 10:22
…MapJoin in semijoinRemovalBasedTransformations.

TODO: make sure to add some logic (maybe configurable) deciding which TS filtering to select when we have multiple.
Extend TezCompiler to use configurable logic to select a MJ when we have multiple per TS -- currently picking the one with the lowest MJ/TS key Ratio.
Making sure that SharedWork TS does not contain a probeContext as it would result in wrong results.
Extending TSDesc to include probeContext as part of the explained plan.

Change-Id: I90f5ebd8e4f90990c17f89ef75af39bc335f8e7c
Change-Id: I995ba97355ab1a29bf2e23f21ab641cffba19ce3
Change-Id: If67f3d29c727f887cc2cf11c29ea855c6ea315d7
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants