Zoltán Borók-Nagy created IMPALA-10681:
------------------------------------------

             Summary: JOIN cardinality is wrong for INNER joins when combined 
with aggregations
                 Key: IMPALA-10681
                 URL: https://issues.apache.org/jira/browse/IMPALA-10681
             Project: IMPALA
          Issue Type: Bug
          Components: Frontend
            Reporter: Zoltán Borók-Nagy


JOIN cardinality estimate can be off for INNER joins. Consider the following 
LEFT SEMI JOIN which estimates the cardinalities well:

{noformat}
[localhost:21050] tpcds_parquet> explain select * from store_sales left semi 
join (select max(s_store_sk) as max_store_sk from store) v on ss_store_sk = 
max_store_sk;
Query: explain select * from store_sales left semi join (select max(s_store_sk) 
as max_store_sk from store) v on ss_store_sk = max_store_sk
+-------------------------------------------------------------+
| Explain String                                              |
+-------------------------------------------------------------+
| Max Per-Host Resource Reservation: Memory=14.95MB Threads=6 |
| Per-Host Resource Estimates: Memory=139MB                   |
|                                                             |
| PLAN-ROOT SINK                                              |
| |                                                           |
| 07:EXCHANGE [UNPARTITIONED]                                 |
| |                                                           |
| 03:HASH JOIN [LEFT SEMI JOIN, BROADCAST]                    |
| |  hash predicates: ss_store_sk = max(s_store_sk)           |
| |  runtime filters: RF000 <- max(s_store_sk)                |
| |  row-size=100B cardinality=480.07K                        |
| |                                                           |
| |--06:EXCHANGE [BROADCAST]                                  |
| |  |                                                        |
| |  05:AGGREGATE [FINALIZE]                                  |
| |  |  output: max:merge(s_store_sk)                         |
| |  |  row-size=4B cardinality=1                             |
| |  |                                                        |
| |  04:EXCHANGE [UNPARTITIONED]                              |
| |  |                                                        |
| |  02:AGGREGATE                                             |
| |  |  output: max(s_store_sk)                               |
| |  |  row-size=4B cardinality=1                             |
| |  |                                                        |
| |  01:SCAN HDFS [tpcds_parquet.store]                       |
| |     HDFS partitions=1/1 files=1 size=9.93KB               |
| |     row-size=4B cardinality=12                            |
| |                                                           |
| 00:SCAN HDFS [tpcds_parquet.store_sales]                    |
|    HDFS partitions=1824/1824 files=1824 size=200.93MB       |
|    runtime filters: RF000 -> ss_store_sk                    |
|    row-size=100B cardinality=2.88M                          |
+-------------------------------------------------------------+
{noformat}

JOIN cardinality is 1/6 of LHS scan node cardinality which seems reasonable, 
since LHS NDV is 6, and the right side only has one row.

Now let's switch to an INNER join:

{noformat}
[localhost:21050] tpcds_parquet> explain select * from store_sales inner join 
(select max(s_store_sk) as max_store_sk from store) v on ss_store_sk = 
max_store_sk;
Query: explain select * from store_sales inner join (select max(s_store_sk) as 
max_store_sk from store) v on ss_store_sk = max_store_sk
+-------------------------------------------------------------+
| Explain String                                              |
+-------------------------------------------------------------+
| Max Per-Host Resource Reservation: Memory=14.95MB Threads=6 |
| Per-Host Resource Estimates: Memory=193MB                   |
|                                                             |
| PLAN-ROOT SINK                                              |
| |                                                           |
| 07:EXCHANGE [UNPARTITIONED]                                 |
| |                                                           |
| 03:HASH JOIN [INNER JOIN, BROADCAST]                        |
| |  hash predicates: ss_store_sk = max(s_store_sk)           |
| |  runtime filters: RF000 <- max(s_store_sk)                |
| |  row-size=104B cardinality=2.88M                          |
| |                                                           |
| |--06:EXCHANGE [BROADCAST]                                  |
| |  |                                                        |
| |  05:AGGREGATE [FINALIZE]                                  |
| |  |  output: max:merge(s_store_sk)                         |
| |  |  row-size=4B cardinality=1                             |
| |  |                                                        |
| |  04:EXCHANGE [UNPARTITIONED]                              |
| |  |                                                        |
| |  02:AGGREGATE                                             |
| |  |  output: max(s_store_sk)                               |
| |  |  row-size=4B cardinality=1                             |
| |  |                                                        |
| |  01:SCAN HDFS [tpcds_parquet.store]                       |
| |     HDFS partitions=1/1 files=1 size=9.93KB               |
| |     row-size=4B cardinality=12                            |
| |                                                           |
| 00:SCAN HDFS [tpcds_parquet.store_sales]                    |
|    HDFS partitions=1824/1824 files=1824 size=200.93MB       |
|    runtime filters: RF000 -> ss_store_sk                    |
|    row-size=100B cardinality=2.88M                          |
+-------------------------------------------------------------+
{noformat}

The JOIN cardinality equals to the lhs cardinality even when the rhs 
cardinality is only one.

SEMI JOIN cardinality is calculated differently than INNER join cardinality.
SEMI JOIN cardinality:
https://github.com/apache/impala/blob/c65d7861d9ae28f6fc592727ff699a8155dcda2c/fe/src/main/java/org/apache/impala/planner/JoinNode.java#L486-L562

INNER JOIN cardinality:
https://github.com/apache/impala/blob/c65d7861d9ae28f6fc592727ff699a8155dcda2c/fe/src/main/java/org/apache/impala/planner/JoinNode.java#L242-L308

The problem is that the latter doesn't find the equi join conjunct "ss_store_sk 
= max(s_store_sk)" eligible, so it returns lhs cardinality:
https://github.com/apache/impala/blob/c65d7861d9ae28f6fc592727ff699a8155dcda2c/fe/src/main/java/org/apache/impala/planner/JoinNode.java#L296-L300

ss_store_sk = max(s_store_sk) is not eligible because Expr.findSrcScanSlot() 
returns NULL for "max(s_store_sk)."
https://github.com/apache/impala/blob/c65d7861d9ae28f6fc592727ff699a8155dcda2c/fe/src/main/java/org/apache/impala/planner/JoinNode.java#L449

I think the solution should be to either change Expr.findSrcScanSlot() to 
return the scan slot. Or, change getJoinCardinality() to return an estimation 
similar to the SEMI JOIN. Or fix both.



--
This message was sent by Atlassian Jira
(v8.3.4#803005)

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

Reply via email to