Skip to content

Excessive predicate evaluation in multi-level LEFT JOINs #8995

@dyemanov

Description

@dyemanov

Simplified test case:

select count(*)
from employee e1
left join employee e2 on e1.emp_no = e2.emp_no
left join employee e3 on e2.emp_no = e3.emp_no
left join employee e4 on e3.emp_no = e4.emp_no
left join employee e5 on e4.emp_no = e5.emp_no
where e1.salary > 0;

Predicate in the WHERE clause is pushed into the join stack and applied to the E1 data source which is correct. However, it still remains at the upper level and applied again. Prior to v5.0, it was redundantly applied only once, at the top-most level, see Filter in the plan marked with an asterisk:

Select Expression
    -> Aggregate
*       -> Filter
            -> Nested Loop Join (outer)
                -> Nested Loop Join (outer)
                    -> Nested Loop Join (outer)
                        -> Nested Loop Join (outer)
                            -> Filter
                                -> Table "EMPLOYEE" as "E1" Full Scan
                            -> Filter
                                -> Table "EMPLOYEE" as "E2" Access By ID
                                    -> Bitmap
                                        -> Index "RDB$PRIMARY7" Unique Scan
                        -> Filter
                            -> Table "EMPLOYEE" as "E3" Access By ID
                                -> Bitmap
                                    -> Index "RDB$PRIMARY7" Unique Scan
                    -> Filter
                        -> Table "EMPLOYEE" as "E4" Access By ID
                            -> Bitmap
                                -> Index "RDB$PRIMARY7" Unique Scan
                -> Filter
                    -> Table "EMPLOYEE" as "E5" Access By ID
                        -> Bitmap
                            -> Index "RDB$PRIMARY7" Unique Scan

However, after #3218, Firebird 5.0 redundantly evaluates this predicate at the every join level, see:

Select Expression
    -> Aggregate
*       -> Filter
            -> Nested Loop Join (outer)
*               -> Filter
                    -> Nested Loop Join (outer)
*                       -> Filter
                            -> Nested Loop Join (outer)
*                               -> Filter
                                    -> Nested Loop Join (outer)
                                        -> Filter
                                            -> Table "EMPLOYEE" as "E1" Full Scan
                                        -> Filter
                                            -> Table "EMPLOYEE" as "E2" Access By ID
                                                -> Bitmap
                                                    -> Index "RDB$PRIMARY7" Unique Scan
                                -> Filter
                                    -> Table "EMPLOYEE" as "E3" Access By ID
                                        -> Bitmap
                                            -> Index "RDB$PRIMARY7" Unique Scan
                        -> Filter
                            -> Table "EMPLOYEE" as "E4" Access By ID
                                -> Bitmap
                                    -> Index "RDB$PRIMARY7" Unique Scan
                -> Filter
                    -> Table "EMPLOYEE" as "E5" Access By ID
                        -> Bitmap
                            -> Index "RDB$PRIMARY7" Unique Scan

thus negatively affecting the query performance.

Metadata

Metadata

Assignees

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions