Slow query on “UNION ALL” view

后端 未结 7 1256
说谎
说谎 2021-02-13 06:42

I have a DB view which basically consists of two SELECT queries with UNION ALL, like this:

CREATE VIEW v AS
SELECT time, etc. FROM t1 /         


        
相关标签:
7条回答
  • 2021-02-13 07:10

    I believe your query is being executed similar to:

    (
       ( SELECT time, etc. FROM t1 // #1... )
       UNION ALL
       ( SELECT time, etc. FROM t2 // #2... )
    )
    WHERE time >= ... AND time < ...
    

    which the optimizer is having difficulty optimizing. i.e. it's doing the UNION ALL first before applying the WHERE clause but, you wish it to apply the WHERE clause before the UNION ALL.

    Couldn't you put your WHERE clause in the CREATE VIEW?

    CREATE VIEW v AS
    ( SELECT time, etc. FROM t1  WHERE time >= ... AND time < ... )
    UNION ALL
    ( SELECT time, etc. FROM t2  WHERE time >= ... AND time < ... )
    

    Alternatively if the view cannot have the WHERE clause, then, perhaps you can keep to the two views and do the UNION ALL with the WHERE clause when you need them:

    CREATE VIEW v1 AS
    SELECT time, etc. FROM t1 // #1...
    
    CREATE VIEW v2 AS
    SELECT time, etc. FROM t2 // #2...
    
    ( SELECT * FROM v1 WHERE time >= ... AND time < ... )
    UNION ALL
    ( SELECT * FROM v2 WHERE time >= ... AND time < ... )
    
    0 讨论(0)
  • 2021-02-13 07:14

    I do not know Postgres, but some RMDBs handle comparison operators worse than BETWEEN in case of indexes. I would make an attempt using BETWEEN.

    SELECT ... FROM v WHERE time BETWEEN ... AND ...
    
    0 讨论(0)
  • 2021-02-13 07:16

    Encountered same scenario on 11g:

    Scenario 1:

    CREATE VIEW v AS
      SELECT time, etc. FROM t1 // #1...
    

    The following query runs fast, plan looks okay:

    SELECT ... FROM v WHERE time >= ... AND time < ...
    

    Scenario 2:

    CREATE VIEW v AS
      SELECT time, etc. FROM t2 // #2...
    

    The following query runs fast, plan looks okay:

    SELECT ... FROM v WHERE time >= ... AND time < ...
    

    Scenario 3, with UNION ALL:

    CREATE VIEW v AS
      SELECT time, etc. FROM t1 // #1...
      UNION ALL
      SELECT time, etc. FROM t2 // #2...
    

    The following runs slow. Plan breaks apart t1 and t2 (which were also views) and assembles them as a big series of unions. The time filters are being applied properly on the individual components, but it is still very slow:

    SELECT ... FROM v WHERE time >= ... AND time < ...
    

    I would have been happy to just get a time in the ballpark of t1 plus t2, but it was more than double. Adding the parallel hint did the trick for me in this case. It re-arranged everything into a better plan:

    SELECT /*+ parallel */ ... FROM v WHERE time >= ... AND time < ...
    
    0 讨论(0)
  • 2021-02-13 07:16

    A possibility would be to issue a new SQL dynamically at each call instead of creating a view and to integrate the where clause in each SELECT of the union query

    SELECT time, etc. FROM t1
        WHERE time >= ... AND time < ...
    UNION ALL
    SELECT time, etc. FROM t2
        WHERE time >= ... AND time < ...
    

    EDIT:

    Can you use a parametrized function?

    CREATE OR REPLACE FUNCTION CallMyView(t1 date, t2 date)
    RETURNS TABLE(d date, etc.)
    AS $$
        BEGIN
            RETURN QUERY
                SELECT time, etc. FROM t1
                    WHERE time >= t1 AND time < t2
                UNION ALL
                SELECT time, etc. FROM t2
                    WHERE time >= t1 AND time < t2;
        END;
    $$ LANGUAGE plpgsql;
    

    Call

    SELECT * FROM CallMyView(..., ...);
    
    0 讨论(0)
  • 2021-02-13 07:22

    Combine the two tables. Add a column to indicate original table. If necessary, replace the original table names with views that select just the relevant part. Problem solved!

    Looking into the superclass/subclass db design pattern could be of use to you.

    0 讨论(0)
  • 2021-02-13 07:25

    Try creating your view using UNION DISTINCT instead of UNION ALL. See if it gives wrong results. See if it gives faster performance.

    If it gives wrong results, try and map your SQL operations on tables back to relational operations on relations. The elements of relations are always distinct. There may be somthing fundamentally wrong with your model.

    I am deeply suspicious of the LEFT JOINS in the query plan you showed. It shouldn't be necessary to perform LEFT JOINS in order to get the results you appear to be selecting.

    0 讨论(0)
提交回复
热议问题