Skip to content

Different invariants optimization between views and CTEs #7388

@chrpos

Description

@chrpos

Hi,

I am using Firebird Version: 4.0.2 (issue is there also with Firebird 3.0.7)
Due to performance issues I was facing with an sql query on a database, I generated a simple reproducible example, based on the "employee" sample database of firebird.

The issue in short: The query in question uses a view. When I replace the view, that is referenced in the query, with a common table expression (CTE), using the same SQL for the CTE as for the view, the query executes in fact very differently. See the comparison of the performance analysis. Interestingly enough, the execution plans of both queries are the same, though execute differently.

In the following example, Query A references the view "EMP_DEPT_TEAM". Query B uses the content of the view's query as CTE. Query A and B produce the same execution plans. I would expect query A and B performing just the same, but query A performs less good than query B.

How to reproduce (use the database "employee.fdb"):
Create a view:

create view EMP_DEPT_TEAM
as
select
    EMP_NO,
    DEPARTMENT.DEPT_NO,
    iif(PROJECT.TEAM_LEADER is not null, 'yes', 'no') as IS_TEAMLEADER
from EMPLOYEE
    inner join DEPARTMENT on EMPLOYEE.DEPT_NO = DEPARTMENT.DEPT_NO
    left join PROJECT on EMPLOYEE.EMP_NO = PROJECT.TEAM_LEADER;

Query A (using the view):

select
    EMP_NO,
    DEPT_NO,
    IS_TEAMLEADER
from EMP_DEPT_TEAM
    where EMP_DEPT_TEAM.EMP_NO = (select max(EMP_NO) from EMP_DEPT_TEAM);

Query B (not using the view, but a CTE):

with EMP_DEPT_TEAM_ as (select
    EMP_NO,
    DEPARTMENT.DEPT_NO,
    iif(PROJECT.TEAM_LEADER is not null, 'yes', 'no') as IS_TEAMLEADER
from EMPLOYEE
    inner join DEPARTMENT on EMPLOYEE.DEPT_NO = DEPARTMENT.DEPT_NO
    left join PROJECT on EMPLOYEE.EMP_NO = PROJECT.TEAM_LEADER
)
select
    EMP_NO,
    DEPT_NO,
    IS_TEAMLEADER
from EMP_DEPT_TEAM_
    where EMP_NO = (select max(EMP_NO) from EMP_DEPT_TEAM_);

Execution plan for Query A (see also attached screenshots):

PLAN JOIN (JOIN (EMP_DEPT_TEAM DEPARTMENT NATURAL, EMP_DEPT_TEAM EMPLOYEE INDEX (RDB$FOREIGN8)), EMP_DEPT_TEAM PROJECT INDEX (RDB$FOREIGN13))
PLAN JOIN (JOIN (EMP_DEPT_TEAM EMPLOYEE INDEX (RDB$PRIMARY7), EMP_DEPT_TEAM DEPARTMENT INDEX (RDB$PRIMARY5)), EMP_DEPT_TEAM PROJECT INDEX (RDB$FOREIGN13))

Details:
Execution-Plan-Query-A-View

Execution plan for Query B (see also attached screenshots):

PLAN JOIN (JOIN (EMP_DEPT_TEAM_ DEPARTMENT NATURAL, EMP_DEPT_TEAM_ EMPLOYEE INDEX (RDB$FOREIGN8)), EMP_DEPT_TEAM_ PROJECT INDEX (RDB$FOREIGN13))
PLAN JOIN (JOIN (EMP_DEPT_TEAM_ EMPLOYEE INDEX (RDB$PRIMARY7), EMP_DEPT_TEAM_ DEPARTMENT INDEX (RDB$PRIMARY5)), EMP_DEPT_TEAM_ PROJECT INDEX (RDB$FOREIGN13))

Details:
Execution-Plan-Query-B-CTE

Performance Analysis:
Compare number of reads!

Query A (View):
Performance-Query-A-View

Query B (CTE):
Performance-Query-B-CTE

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions