Dandandan opened a new pull request, #24793:
URL: https://github.com/apache/datafusion/pull/24793

   ## Which issue does this PR close?
   
   - Closes #.
   
   ## Rationale for this change
   
   A fact table often joins a dimension purely to check that a row exists:
   
   ```sql
   SELECT ss_item_sk FROM store_sales, promotion WHERE ss_promo_sk = p_promo_sk
   ```
   
   No column of `promotion` is used and nothing filters it. `eliminate_join`
   already turns this into a semi join, because `p_promo_sk` is a primary key. 
But
   if a foreign key says every `ss_promo_sk` exists in `promotion`, the check is
   guaranteed to succeed and the join can be dropped entirely.
   
   DataFusion had no way to say that. `Constraint` had only `PrimaryKey` and
   `Unique`, and the SQL planner rejected foreign keys outright with "Foreign 
key
   constraints are not currently supported".
   
   ## What changes are included in this PR?
   
   - `Constraint::ForeignKey { columns, referenced_table, referenced_columns }`,
     taken on trust like the existing constraints, round-tripping through proto.
   - The SQL planner accepts `FOREIGN KEY (..) REFERENCES t(..)` and the inline
     `col INT REFERENCES t(c)` form.
   - `eliminate_join` drops a join the foreign key makes redundant.
   - `dfbench` declares the TPC-DS foreign keys. Its comment previously read
     "TPC-DS also defines foreign keys, but those are currently unsupported".
   
   Two details worth review:
   
   The join is replaced by its left input under a `col IS NOT NULL` filter, not
   dropped outright. A foreign key column may be nullable, and the semi join it
   replaces does drop rows whose key is NULL, so the filter preserves that. It
   also covers the case where an outer join further down padded the column.
   
   The rewrite only fires when the referenced side is an unfiltered scan of the
   referenced table. A foreign key promises the value exists in the table, not
   that it survives a predicate, so a filtered dimension keeps its join.
   
   ## Benchmarks
   
   TPC-DS SF1, primary keys declared in both runs, median of 3, plus the movers
   re-checked at 9 iterations:
   
   | query | without foreign keys | with | |
   |---|---|---|---|
   | q64 | 347 ms | 239 ms | **1.45x** |
   | q18 | 92 ms | 76 ms | **1.22x** |
   | suite | 9551 ms | 9440 ms | -1.2% |
   
   q64 loses 6 joins: `promotion` twice and `income_band` four times. q23 and 
q24
   looked like regressions at 3 iterations but their plans are unchanged, and 
at 9
   iterations they are flat.
   
   TPC-H is unaffected: all of its dimension joins carry filters.
   
   ## Are these changes tested?
   
   Yes. `functional_dependencies.slt` covers the rewrite, the results it 
produces,
   and the two cases that must keep the join: a predicate on the referenced 
side,
   and a query that uses one of its columns. Three cases in `group_by.slt` that
   asserted foreign keys were rejected now assert they are accepted.
   
   All 99 TPC-DS queries were checked to return identical results with and 
without
   the foreign keys declared. The full sqllogictest suite (504 files) and the
   workspace test suite pass.
   
   ## Are there any user-facing changes?
   
   `FOREIGN KEY` in `CREATE TABLE` is accepted instead of erroring, and joins it
   makes redundant are removed. `Constraint` gains a variant, so exhaustive 
matches
   on it need a new arm; this is an API change.
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to