-
Notifications
You must be signed in to change notification settings - Fork 3.8k
/
join.opt
126 lines (119 loc) · 4.1 KB
/
join.opt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
# =============================================================================
# join.opt contains normalization rules for Join operators.
# =============================================================================
# EnsureJoinFiltersAnd replaces an And operator in a Join's On condition with
# the Filters operator. This allows other rules to rely upon the presence of
# the Filters when matching. See comment at top of bool.opt for more details.
# This rule is a special-case of the EnsureJoinFilters rule, for performance
# reasons (no need to construct a new conditions list) in a common case.
[EnsureJoinFiltersAnd, Normalize]
(Join
$left:*
$right:*
(And $conditions:*)
)
=>
((OpName)
$left
$right
(Filters $conditions)
)
# EnsureJoinFilters adds a Filters operator to a Join's On condition if it does
# not already exist. This allows other rules to rely upon the presence of the
# Filters when matching. See comment at top of bool.opt for more details.
[EnsureJoinFilters, Normalize]
(Join
$left:*
$right:*
$filter:^(Filters | And | True | False)
)
=>
((OpName)
$left
$right
(Filters [ $filter ])
)
# PushFilterIntoJoinLeft pushes Join filter conditions into the left side of the
# join. This is possible in the case of InnerJoin and RightJoin, as long as the
# condition has no dependencies on the right side of the join. Left and Full
# joins are not eligible, since filtering left rows will change the number of
# rows in the result for those types of joins:
#
# -- A row with nulls on the right side is returned for a.x=1, a.y=2, b.x=1.
# SELECT * FROM a LEFT JOIN b ON a.x=b.x AND a.y < 0
#
# -- But if the filter is incorrectly pushed down, then no row is returned.
# SELECT * FROM (SELECT * FROM a WHERE a.y < 0) a LEFT JOIN b ON a.x=b.x
#
# Citations: [1]
[PushFilterIntoJoinLeft, Normalize]
(InnerJoin | InnerJoinApply | RightJoin | RightJoinApply
$left:*
$right:*
$on:(Filters $list:[ ... $condition:* & ^(IsCorrelated $condition $right) ... ])
)
=>
((OpName)
(Select
$left
(Filters (ExtractUncorrelatedConditions $list (OutputCols $right)))
)
$right
(Filters (ExtractCorrelatedConditions $list (OutputCols $right)))
)
# PushFilterIntoJoinRight is symmetric with PushFilterIntoJoinLeft. It pushes
# Join filter conditions into the right side of the join rather than into the
# left side. See that rule's comments for more details.
[PushFilterIntoJoinRight, Normalize]
(InnerJoin | InnerJoinApply | LeftJoin | LeftJoinApply
$left:*
$right:*
$on:(Filters $list:[ ... $condition:* & ^(IsCorrelated $condition $left) ... ])
)
=>
((OpName)
$left
(Select
$right
(Filters (ExtractUncorrelatedConditions $list (OutputCols $left)))
)
(Filters (ExtractCorrelatedConditions $list (OutputCols $left)))
)
# DecorrelateJoin maps an apply join into the corresponding join without an
# apply if the right side of the join is not correlated with the left side.
# This allows the optimizer to consider additional physical join operators that
# are unable to handle correlated inputs.
#
# NOTE: Keep this before other decorrelation patterns, as if the correlated
# join can be removed first, it avoids unnecessarily matching other
# patterns that only exist to get to this pattern.
#
# Citations: [3]
[DecorrelateJoin, Normalize]
(JoinApply
$left:*
$right:* & ^(IsCorrelated $right $left)
$on:*
)
=>
(RemoveApply (OpName) $left $right $on)
# TryDecorrelateSelect "pushes down" the join apply into the select operator,
# in order to eliminate any correlation between the select filter list and the
# left side of the join, and also to keep "digging" down to find and eliminate
# other unnecessary correlation. Eventually, the hope is to trigger the
# DecorrelateJoin pattern to turn the JoinApply operator into a non-apply Join
# operator.
#
# Citations: [3]
[TryDecorrelateSelect, Normalize]
(InnerJoinApply | LeftJoinApply | SemiJoinApply | AntiJoinApply
$left:*
$right:(Select $input:* $filter:*) & (IsCorrelated $right $left)
$on:*
)
=>
((OpName)
$left
$input
(ConcatFilters $on $filter)
)