[SNAP-1194] Optimization for single dictionary column group by and join #437
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Changes proposed in this pull request
Single column dictionary optimization to make use of dictionary indexes for a column batch instead of strings. This one is the simpler variant where an array of the dictionary size is created. This array is populated with the corresponding MapEntry object of the main HashMap on demand (i.e. lookup and fill in if found else put an EMPTY marker if not found) so other columns can be updated/fetched directly from array skipping the map completely after first miss (update for GROUP BY and fetch for JOIN). Some more details can be found in class comments of DictionaryOptimizedMapAccessor.
new DictionaryOptimizedMapAccessor to check for single column dictionary key case and generated code for the same (array creation, fetch from map on miss and return the other columns)
refactored the map lookup code both in the code generator ObjectMapAccessor as well as in actual generated code to enable invocation for both dictionary case or other cases; this introduces no overhead rather it is slightly more efficient in some cases where JVM can dynamically decide whether or not to inline the method call as per CPU instruction cache size
Changed the pattern in join consume. Earlier it used to invoke a "moveNext" at the start assuming iterator is placed before first row. Now generated code does not make this assumption rather than iterator is placed at first row (with above changes it difficult to fit in the "before first row" pattern). To circumvent the problem of consume code calling "continue" and expecting to move to next row (now it will go into infinite loop), it is surrounded with an otherwise useless "do { consume } while(false);" so that a continue will break out and then go on to moveNext -- looks like "while (true) { do { consume } while(false); moveNext }"
Use a generic map in SnappySession to keep track of any addition "context" objects during code generation. Used to pass around dictionary variable names and a new "finallyCode" block which is used to combine multiple "try{} finally {}" in generated code into a single block.
Added a HashedObjectCache for LocalJoin map that is shared by multiple partitions on the same node. This helps both in reduction of effort to create the map as well as lesser memory overhead hence better CPU cache behaviour. It is created on first get and removed when the last reference is removed (so could be created multiple times in single query for each set of scheduled partitions on a node). This behaviour helps avoid the invalidation complexity while adding minimal overhead.
Handle StartsWith predicate for MAX/MIN by treating it like a range. 'ABC%' is treated as ">= 'ABC' and < 'ABD'"
Skip creation of SnappyHashAggregateExec completely if code generation is not possible (due to an ImperativeAggregate). This allows the doExecute of SnappyHashAggregateExec to simply fallback to code-generation assuming it will never fail.
Added Utils.metricsMethods and call it from all Snappy optimized plans to allow invoking optimized primitive methods avoiding boxing/unboxing overhead for SQLMetrics (see snappy-spark PR linked below)
Remove the opt=F case that skipped optimized implementation for LocalJoin and HashAggregate. It is no longer useful for comparison and does not work for LocalJoin with the changes in this PR. Removed from both TPCETrade as well as disabled in LocalJoin.
Patch testing
precheckin
ReleaseNotes.txt changes
NA
Other PRs
TIBCOSoftware/snappy-spark#33