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  )