github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/opt/xform/rules/select.opt (about) 1 # ============================================================================= 2 # select.opt contains exploration rules for the Select operator. 3 # ============================================================================= 4 5 # GenerateConstrainedScans generates a set of constrained Scan expressions, one 6 # for each matching index on the scanned table. The expressions consist of 7 # either a standalone Scan operator (if no remaining filter), or else a Scan 8 # wrapped by a Select (with a remaining filter). Or, if a secondary index cannot 9 # provide all the output columns, an IndexJoin is introduced to supply them. See 10 # the comment for the GenerateConstrainedScans custom method for more details 11 # and examples. 12 [GenerateConstrainedScans, Explore] 13 (Select 14 (Scan $scanPrivate:* & (IsCanonicalScan $scanPrivate)) 15 $filters:* 16 ) 17 => 18 (GenerateConstrainedScans $scanPrivate $filters) 19 20 # GenerateInvertedIndexScans creates alternate expressions for filters that can 21 # be serviced by an inverted index. 22 [GenerateInvertedIndexScans, Explore] 23 (Select 24 (Scan 25 $scanPrivate:* & 26 (IsCanonicalScan $scanPrivate) & 27 (HasInvertedIndexes $scanPrivate) 28 ) 29 $filters:* 30 ) 31 => 32 (GenerateInvertedIndexScans $scanPrivate $filters) 33 34 # SplitDisjunction splits disjunctions (Or expressions) into a Union of two 35 # Select expressions, the first containing the left sub-expression of the Or 36 # expression and the second containing the right sub-expression. All other 37 # filter items in the original expression are preserved in the new Select 38 # expressions. 39 # 40 # This can produce better query plans in cases where indexes cover both sides of 41 # the Or expression. The execution plan can use both indexes to satisfy both 42 # sides of the disjunction and union the results together. 43 # 44 # Note that this rule only matches Selects with canonical scans. Therefore scan 45 # constraints do not need to be duplicated in the left and right scans of the 46 # union. 47 # 48 # Also note that this rule only matches Selects that have strict keys. See 49 # SplitDisjunctionAddKey which handles Selects that do not have strict keys. 50 [SplitDisjunction, Explore] 51 (Select 52 $input:(Scan 53 $scanPrivate:* & (IsCanonicalScan $scanPrivate) 54 ) & 55 (HasStrictKey $input) 56 $filters:* & 57 (ExprPairSucceeded 58 $pair:(ExprPairForSplitDisjunction 59 $scanPrivate 60 $filters 61 ) 62 ) 63 ) 64 => 65 (DistinctOn 66 (UnionAll 67 (Select 68 $input 69 (ReplaceFiltersItem 70 $filters 71 (ExprPairFiltersItemToReplace $pair) 72 (ExprPairLeft $pair) 73 ) 74 ) 75 (Select 76 (Scan 77 $rightScanPrivate:(DuplicateScanPrivate 78 $scanPrivate 79 ) 80 ) 81 (MapScanFilterCols 82 (ReplaceFiltersItem 83 $filters 84 (ExprPairFiltersItemToReplace $pair) 85 (ExprPairRight $pair) 86 ) 87 $scanPrivate 88 $rightScanPrivate 89 ) 90 ) 91 (MakeSetPrivateForSplitDisjunction 92 $scanPrivate 93 $rightScanPrivate 94 ) 95 ) 96 (MakeAggCols ConstAgg (NonKeyCols $input)) 97 (MakeGrouping (KeyCols $input) (EmptyOrdering)) 98 ) 99 100 # SplitDisjunctionAddKey performs a transformation similar to 101 # SplitDisjunction, but it handles the special case when the original Scan 102 # does not have a strict key in its ColSet. 103 # 104 # For this special case, the replace pattern adds primary key columns to the 105 # original Scan ColSet. It also adds a Project to remove those columns after the 106 # Union operation. Inclusion of the primary keys is required to prevent the 107 # generated Union from de-duplicating rows that have the same selected values. 108 # 109 # To understand why the addition of the primary key columns to the Scans is 110 # necessary, consider the following: 111 # 112 # CREATE TABLE t (k INT PRIMARY KEY, a INT, b INT) 113 # INSERT INTO t VALUES (1, 1, 3) 114 # INSERT INTO t VALUES (2, 1, 3) 115 # SELECT a, b FROM t WHERE a = 1 OR b = 3 116 # 117 # The expected result of the Select query is 2 rows, with values (1, 3). Now 118 # consider the following query: 119 # 120 # SELECT a, b FROM t WHERE a = 1 121 # UNION 122 # SELECT a, b FROM t WHERE b = 3 123 # 124 # Union de-duplicates all tuples with the same set of values. So, this 125 # query returns only a single row. 126 # 127 # By adding a primary key in the output columns, each input row to the Union is 128 # guaranteed to be unique. This prevents incorrect de-duplication and guarantees 129 # that the newly generated plan is equivalent to the original plan. 130 [SplitDisjunctionAddKey, Explore] 131 (Select 132 $input:(Scan 133 $scanPrivate:* & (IsCanonicalScan $scanPrivate) 134 ) & 135 ^(HasStrictKey $input) 136 $filters:* & 137 (ExprPairSucceeded 138 $pair:(ExprPairForSplitDisjunction 139 $scanPrivate 140 $filters 141 ) 142 ) 143 ) 144 => 145 (Project 146 (DistinctOn 147 (UnionAll 148 (Select 149 $leftScan:(Scan 150 $leftScanPrivate:(AddPrimaryKeyColsToScanPrivate 151 $scanPrivate 152 ) 153 ) 154 (ReplaceFiltersItem 155 $filters 156 (ExprPairFiltersItemToReplace $pair) 157 (ExprPairLeft $pair) 158 ) 159 ) 160 (Select 161 (Scan 162 $rightScanPrivate:(DuplicateScanPrivate 163 $leftScanPrivate 164 ) 165 ) 166 (MapScanFilterCols 167 (ReplaceFiltersItem 168 $filters 169 (ExprPairFiltersItemToReplace $pair) 170 (ExprPairRight $pair) 171 ) 172 $leftScanPrivate 173 $rightScanPrivate 174 ) 175 ) 176 (MakeSetPrivateForSplitDisjunction 177 $leftScanPrivate 178 $rightScanPrivate 179 ) 180 ) 181 (MakeAggCols ConstAgg (NonKeyCols $leftScan)) 182 (MakeGrouping (KeyCols $leftScan) (EmptyOrdering)) 183 ) 184 [] 185 (OutputCols $input) 186 )