I currently have four tables that need to be joined with a left join. There are about 400_000 (400 thousand) of data records (which will grow in the future).
In addition to the left join, the following things must be able to be executed performantly:
I myself had several ideas to optimise this requirement.
full text search:
p.client_id::text || ' '::text || pmn.name::text
) and additionally contains the id for purchasing with a gin index (gin_trgm_ops)offset, limit:
count
Adding columns or tables to help is possible. Changing the structure is also possible as long as all data is retained.
It is also possible to change the database system if postgres does not have the required functions.
the tables:
CREATE TABLE company_codes (
id int2 NOT NULL,
name varchar(20) NOT NULL,
CONSTRAINT company_codes_pk PRIMARY KEY (id)
);
CREATE TABLE purchasing_mandant_names (
id int2 NOT NULL,
"name" varchar(50) NOT NULL,
CONSTRAINT archiving_coding_keys_pkey PRIMARY KEY (id),
CONSTRAINT purchasing_mandant_names_un UNIQUE (name)
);
CREATE TABLE purchasing (
id int4 NOT NULL GENERATED BY DEFAULT AS IDENTITY,
mandant_id int2 NOT NULL,
company_code int4 NOT NULL,
sequence_number int8 NOT NULL,
"year" int2 NOT NULL,
"month" int2 NOT NULL,
CONSTRAINT purchasing_check_month CHECK (((month >= 1) AND (month <= 12))),
CONSTRAINT purchasing_check_year CHECK (((year >= 2000) AND (year <= 2100))),
CONSTRAINT purchasing_client_plant_sequence_number_key UNIQUE (mandant_id, company_code, sequence_number),
CONSTRAINT purchasing_pkey PRIMARY KEY (id)
);
ALTER TABLE purchasing ADD CONSTRAINT purchasing_company_code_fk FOREIGN KEY (company_code) REFERENCES company_codes(id);
ALTER TABLE purchasing ADD CONSTRAINT purchasing_mandant_id_fkey FOREIGN KEY (mandant_id) REFERENCES purchasing_mandant_names(id) NOT VALID;
CREATE TABLE purchasing_pages (
purchasing_id int8 NOT NULL,
page_path varchar(255) NOT NULL,
CONSTRAINT purchasing_pages_check_page_path CHECK (((page_path)::text ~ '^([a-zA-Z0-9\-_ ]+\/)+[a-zA-Z0-9\-_ ~]+\.[tT][iI][fF]'::text)),
CONSTRAINT purchasing_pages_purchasing_id_page_path_key UNIQUE (purchasing_id, page_path)
);
ALTER TABLE purchasing_pages ADD CONSTRAINT purchasing_pages_id_fkey FOREIGN KEY (purchasing_id) REFERENCES purchasing(id) ON UPDATE CASCADE ON DELETE RESTRICT;
the current slow search
SELECT p.id,
p.mandant_id AS mandant_code,
pmn.name AS mandant_name,
p.company_code,
cc.name AS company_name,
p.sequence_number,
p.year,
p.month,
pp.page_path
FROM purchasing p
LEFT JOIN purchasing_pages pp ON p.id = pp.purchasing_id
LEFT JOIN purchasing_mandant_names pmn ON p.mandant_id = pmn.id
LEFT JOIN company_codes cc ON p.company_code = cc.id
where p.mandant_id::text like '%32%'
or pmn.name::text like '%32%'
or p.company_code::text like '%32%'
or cc.name::text like '%32%'
or p.sequence_number::text like '%32%'
or p.year::text like '%32%'
or p.month::text like '%32%'
order by p.id desc
offset 10 fetch first 10 rows only
My solution: (I think there will be better options, but these are the only ones I have found myself)
full text search:
I created a gin_trgm_ops for a each column.
I was also interested in wildspeed. Unfortunately, this extension is no longer supported.
wildspeed would also have had the advantage of using smaller lengths < 3
.
Maybe I would look in this direction again in the future to see if there is a similar extension.
offset, limit:
Unfortunately, there are no optimisation options when a filter is applied. To optimise the performance, I have built several options into the application itself. If you get a direct link to a page, offset, limit must be used, because there is no other possibility. Besides this possibility, there is now an offset - previous offset and the last id. This way, the index is at least used a little for further navigation. But just for the direct jump there are no optimnierungsmöglichkeiten, because the data are also filtered.
count
I use a count(*) OVER() directly in the combination with the offset limit search filter, so only one query needs to be executed. It is the only optimization I have found for this.