Thread: BUG #18607: UNION ALL discards all foreign key relations + indexes

BUG #18607: UNION ALL discards all foreign key relations + indexes

From
PG Bug reporting form
Date:
The following bug has been logged on the website:

Bug reference:      18607
Logged by:          Sanskar Agrawal
Email address:      sanskar@flintk12.com
PostgreSQL version: 15.0
Operating system:   MacOS
Description:

Min Reproducable env :

Consider the query below -> 

"
CREATE OR REPLACE VIEW v3.temp_view AS
SELECT * FROM users WHERE id = 'e-1'
UNION ALL
SELECT * FROM users WHERE id = 'e-2';
"

groups.id is a primary key and has a unique index defined on the same.

Either way when the view is created, the indexes and the related relations
of the foreign key references are being dropped. 
(Same with "UNION").

What + Why? I am processing the result of the union in another CTE which now
is not having access to indices and so it is performing a seq scan!


PG Bug reporting form <noreply@postgresql.org> writes:
> CREATE OR REPLACE VIEW v3.temp_view AS
> SELECT * FROM users WHERE id = 'e-1'
> UNION ALL
> SELECT * FROM users WHERE id = 'e-2';

> Either way when the view is created, the indexes and the related relations
> of the foreign key references are being dropped. 

Views do not have either indexes or foreign keys.

> What + Why? I am processing the result of the union in another CTE which now
> is not having access to indices and so it is performing a seq scan!

This seems to be a performance complaint, rather than a valid bug
report.  You might find it helpful to read

https://wiki.postgresql.org/wiki/Slow_Query_Questions

            regards, tom lane



Re: BUG #18607: UNION ALL discards all foreign key relations + indexes

From
hubert depesz lubaczewski
Date:
On Mon, Sep 09, 2024 at 03:16:33PM +0000, PG Bug reporting form wrote:
> Consider the query below -> 
> 
> "
> CREATE OR REPLACE VIEW v3.temp_view AS
> SELECT * FROM users WHERE id = 'e-1'
> UNION ALL
> SELECT * FROM users WHERE id = 'e-2';
> "
> 
> groups.id is a primary key and has a unique index defined on the same.

What is groups? Your view is named "temp_view", and it's using "users",
not "groups".

> Either way when the view is created, the indexes and the related relations
> of the foreign key references are being dropped. 
> (Same with "UNION").

What do you mean dropped? You had index on column id in table users, and
after view creation you don't have anymore?

Can you please show full example, that I can run on empty database, that
exhibits the problem?

Best regards,

depesz




Re: BUG #18607: UNION ALL discards all foreign key relations + indexes

From
hubert depesz lubaczewski
Date:
On Tue, Sep 10, 2024 at 12:41:14PM +0530, Sanskar Agrawal wrote:
> Yes consider a small table as users with users.id as primary key,
> 
> took two rows from the same and ran a union all it tends to drop the
> indexes + foreign relations

Please show full example that I can run on empty DB.

Set of create table statement(s), adding indexes, foreign keys, and then
create view, that results in dropped indexes/foreign keys.

Best regards,

depesz




Re: BUG #18607: UNION ALL discards all foreign key relations + indexes

From
hubert depesz lubaczewski
Date:
On Tue, Sep 10, 2024 at 12:52:21PM +0530, Sanskar Agrawal wrote:
> Please find the below DDLS:
> 
> CREATE TABLE test_users (
>     user_id SERIAL PRIMARY KEY,
>     username VARCHAR(50) NOT NULL,
>     email VARCHAR(100) NOT NULL,
>     created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
> );
> -- Add an index on the user_id column
> CREATE INDEX idx_user_id ON test_users (user_id);
> -- Add an index on the email column
> CREATE INDEX idx_email ON test_users (email);
> INSERT INTO test_users (username, email) VALUES
> ('user1', 'user1@example.com'),
> ('user2', 'user2@example.com');
> SELECT * FROM temp_users WHERE email = 'user1@example.com'
> UNION ALL
> SELECT * FROM temp_users WHERE email = 'user2@example.com';

First, please note that your queries run with error:

#v+
=$ psql -aX -f z.sql
CREATE TABLE test_users (
    user_id SERIAL PRIMARY KEY,
    username VARCHAR(50) NOT NULL,
    email VARCHAR(100) NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE
-- Add an index on the user_id column
CREATE INDEX idx_user_id ON test_users (user_id);
CREATE INDEX
-- Add an index on the email column
CREATE INDEX idx_email ON test_users (email);
CREATE INDEX
INSERT INTO test_users (username, email) VALUES
('user1', 'user1@example.com'),
('user2', 'user2@example.com');
INSERT 0 2
SELECT * FROM temp_users WHERE email = 'user1@example.com'
UNION ALL
SELECT * FROM temp_users WHERE email = 'user2@example.com';
psql:z.sql:16: ERROR:  relation "temp_users" does not exist
LINE 1: SELECT * FROM temp_users WHERE email = 'user1@example.com'
                      ^
#v-

You meant test_users, but had temp_users. Fixed that, re-ran:

#v+
=$ psql -aX -f z.sql
CREATE TABLE test_users (
    user_id SERIAL PRIMARY KEY,
    username VARCHAR(50) NOT NULL,
    email VARCHAR(100) NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE
-- Add an index on the user_id column
CREATE INDEX idx_user_id ON test_users (user_id);
CREATE INDEX
-- Add an index on the email column
CREATE INDEX idx_email ON test_users (email);
CREATE INDEX
INSERT INTO test_users (username, email) VALUES
('user1', 'user1@example.com'),
('user2', 'user2@example.com');
INSERT 0 2
SELECT * FROM test_users WHERE email = 'user1@example.com'
UNION ALL
SELECT * FROM test_users WHERE email = 'user2@example.com';
 user_id | username |       email       |        created_at
---------+----------+-------------------+---------------------------
       1 | user1    | user1@example.com | 2024-09-10 09:43:05.72212
       2 | user2    | user2@example.com | 2024-09-10 09:43:05.72212
(2 rows)
#v-

So, the queries work.

Now, let's see the table:

#v+
=$ psql -aX <<< '\d test_users'
\d test_users
                                           Table "public.test_users"
   Column   |            Type             | Collation | Nullable |                   Default
------------+-----------------------------+-----------+----------+---------------------------------------------
 user_id    | integer                     |           | not null | nextval('test_users_user_id_seq'::regclass)
 username   | character varying(50)       |           | not null |
 email      | character varying(100)      |           | not null |
 created_at | timestamp without time zone |           |          | CURRENT_TIMESTAMP
Indexes:
    "test_users_pkey" PRIMARY KEY, btree (user_id)
    "idx_email" btree (email)
    "idx_user_id" btree (user_id)
#v-

The index is there. So nothing got dropped.

Can you explain what you're seeing, preferably using tested queries that
show the problem?

Best regards,

depesz




Re: BUG #18607: UNION ALL discards all foreign key relations + indexes

From
hubert depesz lubaczewski
Date:
On Tue, Sep 10, 2024 at 01:20:22PM +0530, Sanskar Agrawal wrote:
> As you can see in the below screenshot if the view is defined with a UNION
> ALL it tends to drop the index + relations.
> 
> [image: Screenshot 2024-09-10 at 1.17.27 PM.png]
> 
> But if the same query is replaced with below, the constraints stay.
> 
> [image: Screenshot 2024-09-10 at 1.18.59 PM.png]
> 
> What I want to emphasize is after a "UNION ALL",
> if I want to further process on the unioned set -> it loses its indexes +
> relations which then makes the query planner opt in for a seq scan and
> table scans.

UNION ALL is irrelevant. There is no such thing as index on view. There
are indexes on materialized views, but not on plain, standard views.

View is just a rule to change query - there is nothing to index. When
you query view, pg will change your query to get data from underlying
table(s), and if there are suitable views *ON THE TABLE(S)* - they will
be used.

Best regards,

depesz