Background
We're running this query:
SELECT COUNT(*) AS "__count"
FROM "xfiler_document"
INNER JOIN "xfiler_tx" ON ("xfiler_document"."tx_id" = "xfiler_tx"."id")
WHERE (
"xfiler_document"."added_on" <= '2015-06-28T23:59:59.999999-04:00'::timestamptz
AND "xfiler_tx"."company_id" = 1
AND "xfiler_document"."added_on" >= '2015-06-01T00:00:00-04:00'::timestamptz
)
The result of EXPLAIN ANALYZE
is @ https://explain.depesz.com/s/voMo
The table is large (+30 million records), so we've run into a performance problem with a report we're running (this can be seen at the URL above; +25 second query).
Question
It seems to me, based on the analyze results, that the performance issue here is due to the fact that Postgres is comparing the added_on
values (step 4), and then re-checking them for some reason (step 3) for every row from the query's added_on
time frame, rather than only checking the 18,515 rows that apparently match the company_id
comparison in step 7.
Firstly, am I understanding / explaining the performance issue correctly?
Secondly, is there a way to solve this (other than denormalizing company_id
)?
Database
- Postgres 9.6.1
xfiler_document
Column | Type | Modifiers
---------------------+-----------------------------+--------------------------------------------------------------
id | integer | not null default nextval('xfiler_document_id_seq'::regclass)
tx_id | integer | not null
doc | character varying(255) |
added_on | timestamp with time zone | not null
Indexes:
"xfiler_document_pkey" PRIMARY KEY, btree (id)
"xfiler_document_tx_id" btree (tx_id)
"xfiler_document_added_on" btree (added_on)
Foreign-key constraints:
"xfiler_document_tx_id_fkey" FOREIGN KEY (tx_id) REFERENCES xfiler_tx(id) DEFERRABLE INITIALLY DEFERRED
xfiler_tx
Column | Type | Modifiers
----------------------------+--------------------------+--------------------------------------------------------
id | integer | not null default nextval('xfiler_tx_id_seq'::regclass)
name | character varying(255) | not null
company_id | integer | not null
Indexes:
"xfiler_tx_pkey" PRIMARY KEY, btree (id)
"xfiler_tx_company_id" btree (company_id)
"xfiler_tx_name" btree (name)
Foreign-key constraints:
"xfiler_tx_company_id_fkey" FOREIGN KEY (company_id) REFERENCES company_company(id) DEFERRABLE INITIALLY DEFERRED
Referenced by:
TABLE "xfiler_document" CONSTRAINT "xfiler_document_tx_id_fkey" FOREIGN KEY (tx_id) REFERENCES xfiler_tx(id) DEFERRABLE INITIALLY DEFERRED
(tx_id, added_on)
CREATE TABLE
statements in the question.xfiler_tx
table, right? And the rows that it is finding by applying theadded_on
predicate are in thexfiler_document
table. Then it matches the remaining rows from the two tables together after applying an initial filter to each of them.UNIQUE CONSTRAINT
sUNIQUE document (tx_id)
seemed fishy. I suggest you edit the q and add theCREATE TABLE
statements, including the indexes or the output of\d tablename
, for both tables. And the version of Postgres.