PostgreSQL query taking too long
performance, postgresql, postgresql-performance
Solution
Finally successful attempt
My other idea - as per comment: What happens if you remove the `LIMIT` clause for the case where no role is found? I have a suspicion that it will result in the fast plan - making `LIMIT` the culprit here.
You may be able to solve your problem by pushing down your query into a subquery and applying the `LIMIT` only to the outer query (untested):
SELECT *
FROM (
SELECT *
FROM "Roles" AS r
JOIN "Users" AS u ON u."RoleId" = r."Id"
JOIN "PaymentOrders" AS po ON po."UserId" = u."Id"
JOIN "Payments" AS p ON p."PaymentOrderId" = po."Id"
WHERE r."Name" = 'Moses'
) x
LIMIT 1000;
As per comment: @Davita tested and ruled out this workaround. @Kevin's answer later clarified why the workaround failed: use a CTE instead of the subquery. Or check for existence of a role, before you employ the big query to eliminate the bad case.
This leaves questions for PostgreSQL concerning the optimization of queries with `LIMIT`.
There have been a number of recent bug reports concerning query plans with `LIMIT`. I quote Simon Riggs commenting on one of these reports here:
Very bad plans with LIMIT are frequent. This is bad for us because adding LIMIT usually/is supposed to make queries faster, not slower.
We need to do something.
First attempt with no success
I missed that @Craig already mentioned `join_collapse_limit` in the comments. So that was of limited use:
Does reordering the `JOIN` clauses have any effect?
SELECT *
FROM "Roles" AS r
JOIN "Users" AS u ON u."RoleId" = r."Id"
JOIN "PaymentOrders" AS po ON po."UserId" = u."Id"
JOIN "Payments" AS p ON p."PaymentOrderId" = po."Id"
WHERE r."Name" = 'Moses'
LIMIT 1000
Related: you did not by chance mess with the setting of `join_collapse_limit` or `geqo_threshold`? Very low setting might prevent the planner from reordering your `JOIN` clauses, which might explain your problem.
If that does not solve the case, I would try to create an index on `"Roles"(Name)`. Not that this makes any sense with only 15 rows, but I would try to eliminate the suspicion that invalid statistics or cost parameters (or even a bug) make the planner believe the sequential scan on "Roles" to be more expensive than it is.
Problem
I have database with few hundred millions of rows. I'm running the following query: ``` select * from "Payments" as p inner join "PaymentOrders" as po on po."Id" = p."PaymentOrderId" inner join "Users" as u On u."Id" = po."UserId" INNER JOIN "Roles" as r on u."RoleId" = r."Id" Where r."Name" = 'Moses' LIMIT 1000 ``` When the where clause finds a match in database, I get the result in several milliseconds, but if I modify the query and specify a non-existent `r."Name"` in where clause, it takes too much time to complete. I guess that PostgreSQL is doing a sequential scan on the `Payments` table (which contains the most rows), comparing each row one by one. Isn't postgresql smart enough to check first if `Roles` table contains any row with `Name` `'Moses'`? Roles table contains only 15 row, while Payments contains ~350 million. I'm running PostgreSQL 9.2.1. BTW, this same query on the same schema/data takes 0.024ms to complete on MS SQL Server. I'll update the question and post EXPLAIN ANALYSE data in a few hours. Here'e explain analyse results: http://explain.depesz.com/s/7e7 And here's server configuration: ``` version PostgreSQL 9.2.1, compiled by Visual C++ build 1600, 64-bit client_encoding UNICODE effective_cache_size 4500MB fsync on lc_collate English_United States.1252 lc_ctype English_United States.1252 listen_addresses * log_destination stderr log_line_prefix %t logging_collector on max_connections 100 max_stack_depth 2MB port 5432 search_path dbo, "$user", public server_encoding UTF8 shared_buffers 1500MB TimeZone Asia/Tbilisi wal_buffers 16MB work_mem 10MB ``` I'm running postgresql on a i5 cpu (4 core, 3.3 GHz), 8 GB of RAM and Crucial m4 SSD 128GB UPDATE This looks like a bug in query planner. With the recomendation of Erwin Brandstetter I reported it to Postgresql bugs mailing list.