* be considered for the index access. In the latter, only inner join expressions qualifies.
*
* @param parentNode A parent node to the node to generate paths to.
*/
private void generateInnerAccessPaths(BranchNode parentNode) {
JoinNode innerChildNode = parentNode.getRightNode();
assert(innerChildNode != null);
// In case of inner join WHERE and JOIN expressions can be merged
if (parentNode.getJoinType() == JoinType.INNER) {
parentNode.m_joinInnerOuterList.addAll(parentNode.m_whereInnerOuterList);
parentNode.m_whereInnerOuterList.clear();
parentNode.m_joinInnerList.addAll(parentNode.m_whereInnerList);
parentNode.m_whereInnerList.clear();
}
if (innerChildNode instanceof BranchNode) {
generateOuterAccessPaths((BranchNode)innerChildNode);
generateInnerAccessPaths((BranchNode)innerChildNode);
// The inner node is a join node itself. Only naive access path is possible
innerChildNode.m_accessPaths.add(
getRelevantNaivePath(parentNode.m_joinInnerOuterList, parentNode.m_joinInnerList));
return;
}
// The inner table can have multiple index access paths based on
// inner and inner-outer join expressions plus the naive one.
innerChildNode.m_accessPaths.addAll(
getRelevantAccessPathsForTable(innerChildNode.getTableScan(),
parentNode.m_joinInnerOuterList, parentNode.m_joinInnerList, null));
// If there are inner expressions AND inner-outer expressions, it could be that there
// are indexed access paths that use elements of both in the indexing expressions,
// especially in the case of a compound index.
// These access paths can not be considered for use with an NLJ because they rely on
// inner-outer expressions.
// If there is a possibility that NLIJ will not be an option due to the
// "special case" processing that puts a send/receive plan between the join node
// and its inner child node, other access paths need to be considered that use the
// same indexes as those identified so far but in a simpler, less effective way
// that does not rely on inner-outer expressions.
// The following simplistic method of finding these access paths is to force
// inner-outer expressions to be handled as NLJ-compatible post-filters and repeat
// the search for access paths.
// This will typically generate some duplicate access paths, including the naive
// sequential scan path and any indexed paths that happened to use only the inner
// expressions.
// For now, we deal with this redundancy by dropping (and re-generating) all
// access paths EXCPT those that reference the inner-outer expressions.
// TODO: implementing access path hash and equality and possibly using a "Set"
// would allow deduping as new access paths are added OR
// the simplified access path search process could be based on
// the existing indexed access paths -- for each access path that "hasInnerOuterIndexExpression"
// try to generate and add a simpler access path using the same index,
// this time with the inner-outer expressions used only as non-indexable post-filters.
// Don't bother generating these redundant or inferior access paths unless there is
// an inner-outer expression and a chance that NLIJ will be taken out of the running.
StmtTableScan innerTable = innerChildNode.getTableScan();
assert(innerTable != null);
boolean mayNeedInnerSendReceive = ( ! m_partitioning.wasSpecifiedAsSingle()) &&
(m_partitioning.getCountOfPartitionedTables() > 0) &&
(parentNode.getJoinType() != JoinType.INNER) &&
! innerTable.getIsReplicated();
// too expensive/complicated to test here? (parentNode.m_leftNode has a replicated result?) &&
if (mayNeedInnerSendReceive && ! parentNode.m_joinInnerOuterList.isEmpty()) {
List<AccessPath> innerOuterAccessPaths = new ArrayList<AccessPath>();
for (AccessPath innerAccessPath : innerChildNode.m_accessPaths) {
if ((innerAccessPath.index != null) &&
hasInnerOuterIndexExpression(innerChildNode.getTableAlias(),
innerAccessPath.indexExprs,
innerAccessPath.initialExpr,
innerAccessPath.endExprs)) {
innerOuterAccessPaths.add(innerAccessPath);
}
}
Collection<AccessPath> nljAccessPaths =
getRelevantAccessPathsForTable(innerChildNode.getTableScan(),
null,
parentNode.m_joinInnerList,
parentNode.m_joinInnerOuterList);
innerChildNode.m_accessPaths.clear();
innerChildNode.m_accessPaths.addAll(nljAccessPaths);