Simple POSTGRESQL SELECT query too slow - postgresql

I have a table that stores logs from an Electronic Invoicing System webservice, this is my SQL Structure
CREATE TABLE public.eis_transactions
(
id bigint NOT NULL DEFAULT nextval('eis_transactions_id_seq'::regclass),
operation_type character varying COLLATE pg_catalog."default",
sale_id integer,
delivery_note_id integer,
sale_credit_note_id integer,
debit_note_id integer,
cdc text COLLATE pg_catalog."default",
transaction_id text COLLATE pg_catalog."default",
response_code character varying COLLATE pg_catalog."default",
response_description text COLLATE pg_catalog."default",
xml text COLLATE pg_catalog."default",
response_xml text COLLATE pg_catalog."default",
response_datetime timestamp without time zone,
created timestamp without time zone,
modified timestamp without time zone,
user_id integer,
async boolean DEFAULT false,
url character varying COLLATE pg_catalog."default",
final_xml text COLLATE pg_catalog."default",
CONSTRAINT eis_transactions_pkey PRIMARY KEY (id),
CONSTRAINT eis_transactions_debit_note_id_fkey FOREIGN KEY (debit_note_id)
REFERENCES public.debit_notes (id) MATCH SIMPLE
ON UPDATE RESTRICT
ON DELETE RESTRICT,
CONSTRAINT eis_transactions_delivery_note_id_fkey FOREIGN KEY (delivery_note_id)
REFERENCES public.delivery_notes (id) MATCH SIMPLE
ON UPDATE RESTRICT
ON DELETE RESTRICT,
CONSTRAINT eis_transactions_sale_credit_note_id_fkey FOREIGN KEY (sale_credit_note_id)
REFERENCES public.sale_credit_notes (id) MATCH SIMPLE
ON UPDATE RESTRICT
ON DELETE RESTRICT,
CONSTRAINT eis_transactions_sale_id_fkey FOREIGN KEY (sale_id)
REFERENCES public.sales (id) MATCH SIMPLE
ON UPDATE RESTRICT
ON DELETE RESTRICT,
CONSTRAINT eis_transactions_user_id_fkey FOREIGN KEY (user_id)
REFERENCES public.users (id) MATCH SIMPLE
ON UPDATE RESTRICT
ON DELETE RESTRICT
)
WITH (
OIDS = FALSE
)
TABLESPACE pg_default;
ALTER TABLE public.eis_transactions
OWNER to postgres;
-- Index: eis_transactions_id_idx
-- DROP INDEX public.eis_transactions_id_idx;
CREATE INDEX eis_transactions_id_idx
ON public.eis_transactions USING btree
(id ASC NULLS LAST)
TABLESPACE pg_default;
-- Index: eis_transactions_id_idx1
-- DROP INDEX public.eis_transactions_id_idx1;
CREATE INDEX eis_transactions_id_idx1
ON public.eis_transactions USING btree
(id ASC NULLS FIRST)
TABLESPACE pg_default;
-- Index: eis_transactions_id_idx2
-- DROP INDEX public.eis_transactions_id_idx2;
CREATE INDEX eis_transactions_id_idx2
ON public.eis_transactions USING btree
(id DESC NULLS FIRST)
TABLESPACE pg_default;
-- Index: eis_transactions_sale_id_delivery_note_id_sale_credit_note__idx
-- DROP INDEX public.eis_transactions_sale_id_delivery_note_id_sale_credit_note__idx;
CREATE INDEX eis_transactions_sale_id_delivery_note_id_sale_credit_note__idx
ON public.eis_transactions USING btree
(sale_id ASC NULLS LAST, delivery_note_id ASC NULLS LAST, sale_credit_note_id ASC NULLS LAST, debit_note_id ASC NULLS LAST, user_id ASC NULLS LAST)
TABLESPACE pg_default;
Cointains ~800 rows, this is the query:
SELECT * FROM eis_transactions LIMIT 1000;
It takes more than 60 seconds to complete the query.
And this is the EXPLAIN ANALYZE result i got:
EXPLAIN (ANALYZE, BUFFERS) SELECT * FROM eis_transactions LIMIT 100;
Limit (cost=0.00..15.94 rows=100 width=1108) (actual time=0.013..0.121 rows=100 loops=1)
Buffers: shared read=15
-> Seq Scan on eis_transactions (cost=0.00..128.03 rows=803 width=1108) (actual time=0.012..0.106 rows=100 loops=1)
Buffers: shared read=15
Total runtime: 0.180 ms
But doing a SELECT * FROM eis_transactions (With or without LIMIT) will take more than 60 seconds. While i have other tables with more than 1000 and they don't take so long as this particular table.
What could be wrong ?
Thank you !

Related

pg_restore into a different table structure?

I have two different databases containing a table called feed_items
Lets call them source and destination.
I want to copy some 250k rows from the source feed_items table to the destination feed_items table
Structure of source feed_items table
CREATE TABLE IF NOT EXISTS public.feed_items
(
feed_item_id uuid NOT NULL,
pubdate timestamp with time zone NOT NULL DEFAULT CURRENT_TIMESTAMP,
link character varying COLLATE pg_catalog."default" NOT NULL,
guid character varying COLLATE pg_catalog."default",
title text COLLATE pg_catalog."default" NOT NULL,
summary text COLLATE pg_catalog."default",
content text COLLATE pg_catalog."default",
author character varying(63) COLLATE pg_catalog."default",
feed_id integer NOT NULL,
tags character varying(127)[] COLLATE pg_catalog."default" DEFAULT '{}'::character varying[],
title_vector tsvector,
summary_vector tsvector,
CONSTRAINT feed_items_pkey PRIMARY KEY (feed_item_id),
CONSTRAINT fkey_feed_item_feed FOREIGN KEY (feed_id)
REFERENCES public.feeds (feed_id) MATCH SIMPLE
ON UPDATE CASCADE
ON DELETE CASCADE
)
TABLESPACE pg_default;
ALTER TABLE IF EXISTS public.feed_items
OWNER to ch_v3_root;
CREATE INDEX IF NOT EXISTS idx_feed_items_pubdate_feed_item_id_desc
ON public.feed_items USING btree
(pubdate DESC NULLS FIRST, feed_item_id DESC NULLS FIRST)
TABLESPACE pg_default;
CREATE INDEX IF NOT EXISTS idx_summary_vector
ON public.feed_items USING gin
(summary_vector)
TABLESPACE pg_default;
CREATE INDEX IF NOT EXISTS idx_tags_array
ON public.feed_items USING gin
(tags COLLATE pg_catalog."default")
TABLESPACE pg_default;
CREATE INDEX IF NOT EXISTS idx_title_vector
ON public.feed_items USING gin
(title_vector)
TABLESPACE pg_default;
CREATE TRIGGER on_insert_feed_items
AFTER INSERT
ON public.feed_items
FOR EACH ROW
EXECUTE FUNCTION public.notify_change_feed_items();
CREATE TRIGGER on_update_feed_items
AFTER UPDATE
ON public.feed_items
FOR EACH ROW
WHEN (new.title <> old.title OR new.summary <> old.summary OR new.content <> old.content)
EXECUTE FUNCTION public.notify_change_feed_items();
CREATE TRIGGER trigger_update_summary_vector
BEFORE INSERT OR UPDATE
ON public.feed_items
FOR EACH ROW
EXECUTE FUNCTION tsvector_update_trigger('summary_vector', 'pg_catalog.english', 'summary');
CREATE TRIGGER trigger_update_title_vector
BEFORE INSERT OR UPDATE
ON public.feed_items
FOR EACH ROW
EXECUTE FUNCTION tsvector_update_trigger('title_vector', 'pg_catalog.english', 'title');
Structure of the destination feed_items table
CREATE TABLE IF NOT EXISTS public.feed_items
(
id uuid NOT NULL,
author character varying(255) COLLATE pg_catalog."default",
content text COLLATE pg_catalog."default",
guid character varying(2047) COLLATE pg_catalog."default",
link character varying(2047) COLLATE pg_catalog."default" NOT NULL,
pubdate timestamp with time zone NOT NULL DEFAULT now(),
searchable tsvector GENERATED ALWAYS AS (((setweight(to_tsvector('english'::regconfig, COALESCE(title, (''::character varying)::text)), 'A'::"char") || setweight(to_tsvector('english'::regconfig, COALESCE(summary, ''::text)), 'B'::"char")) || setweight(to_tsvector('english'::regconfig, COALESCE(content, (''::character varying)::text)), 'C'::"char"))) STORED,
summary text COLLATE pg_catalog."default",
tags character varying(255)[] COLLATE pg_catalog."default" NOT NULL DEFAULT (ARRAY[]::character varying[])::character varying(255)[],
title text COLLATE pg_catalog."default" NOT NULL,
feed integer NOT NULL,
CONSTRAINT feed_items_pkey PRIMARY KEY (id),
CONSTRAINT feed_items_link_key UNIQUE (link),
CONSTRAINT feed_items_feed_fkey FOREIGN KEY (feed)
REFERENCES public.feeds (id) MATCH SIMPLE
ON UPDATE CASCADE
ON DELETE CASCADE
)
TABLESPACE pg_default;
ALTER TABLE IF EXISTS public.feed_items
OWNER to ch_api_user;
CREATE INDEX IF NOT EXISTS feed_items_pubdate_id
ON public.feed_items USING btree
(pubdate DESC NULLS FIRST, id DESC NULLS FIRST)
TABLESPACE pg_default;
CREATE INDEX IF NOT EXISTS feed_items_searchable
ON public.feed_items USING gin
(searchable)
TABLESPACE pg_default;
CREATE INDEX IF NOT EXISTS feed_items_tags
ON public.feed_items USING gin
(tags COLLATE pg_catalog."default")
TABLESPACE pg_default;
The names of a few columns have changed, the order of columns has changed and the table is assigned to a different database user. How do I pg_restore from source to destination?

Why isn't PostgreSQL using index for this join query

explain (analyze) select
event_user_detail.*
from event_user_detail
inner join guest_list on event_user_detail.guest_list_id = guest_list.id
where
guest_list.event_id=2985739029
Results in the following query plan:
Gather (cost=1052.56..43408.58 rows=244 width=97) (actual time=66.570..67.810 rows=0 loops=1)
Workers Planned: 2
Workers Launched: 2
-> Nested Loop (cost=52.56..42384.18 rows=102 width=97) (actual time=57.183..57.183 rows=0 loops=3)
-> Parallel Seq Scan on guest_list (cost=0.00..13151.33 rows=5 width=8) (actual time=56.941..57.169 rows=2 loops=3)
Filter: (event_id = '2985739029'::bigint)
Rows Removed by Filter: 254489
-> Bitmap Heap Scan on event_user_detail (cost=52.56..5830.93 rows=1564 width=97) (actual time=0.007..0.007 rows=0 loops=5)
Recheck Cond: (guest_list_id = guest_list.id)
-> Bitmap Index Scan on idx_event_user_detail_guest_list_id (cost=0.00..52.17 rows=1564 width=0) (actual time=0.005..0.005 rows=0 loops=5)
Index Cond: (guest_list_id = guest_list.id)
Planning time: 0.252 ms
Execution time: 67.838 ms
Even tho there is an index on guest_list(event_id). Can someone explain why this is happening and if there is some way to fix it?
If I split this up in 2 queries, of which one is just to get the guest_list ids, and then do a simple in (...ids) then the query is super quick. I tried doing the same with a subquery, but I think the optimiser made it into a join.
-- ----------------------------
-- Table structure for guest_list
-- ----------------------------
DROP TABLE IF EXISTS "public"."guest_list";
CREATE TABLE "public"."guest_list" (
"id" int8 NOT NULL,
"creation_date" timestamp(6),
"last_modification_date" timestamp(6),
"uuid" uuid,
"deleted" bool NOT NULL,
"name" varchar(255) COLLATE "pg_catalog"."default",
"version" int4,
"event_id" int8,
"permanent_guest_list_id" int8,
"color" varchar(255) COLLATE "pg_catalog"."default"
)
;
-- ----------------------------
-- Indexes structure for table guest_list
-- ----------------------------
CREATE INDEX "idx_guest_list_event_id" ON "public"."guest_list" USING btree (
"event_id" "pg_catalog"."int8_ops" ASC NULLS LAST
);
CREATE INDEX "idx_guest_list_permanent_guest_list_id" ON "public"."guest_list" USING btree (
"permanent_guest_list_id" "pg_catalog"."int8_ops" ASC NULLS LAST
);
-- ----------------------------
-- Uniques structure for table guest_list
-- ----------------------------
ALTER TABLE "public"."guest_list" ADD CONSTRAINT "uk_o4sa0dw6lcdjv96gl2p96xwki" UNIQUE ("uuid");
-- ----------------------------
-- Primary Key structure for table guest_list
-- ----------------------------
ALTER TABLE "public"."guest_list" ADD CONSTRAINT "guest_list_pkey" PRIMARY KEY ("id");
-- ----------------------------
-- Foreign Keys structure for table guest_list
-- ----------------------------
ALTER TABLE "public"."guest_list" ADD CONSTRAINT "fk7tk6fxgyo4h7ykelb9c0pe5ap" FOREIGN KEY ("event_id") REFERENCES "public"."event" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION;
ALTER TABLE "public"."guest_list" ADD CONSTRAINT "guest_list_permanent_guest_list_id_fkey" FOREIGN KEY ("permanent_guest_list_id") REFERENCES "public"."permanent_guest_list" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION;
-- ----------------------------
-- Table structure for event_user_detail
-- ----------------------------
DROP TABLE IF EXISTS "public"."event_user_detail";
CREATE TABLE "public"."event_user_detail" (
"id" int8 NOT NULL,
"creation_date" timestamp(6),
"last_modification_date" timestamp(6),
"uuid" uuid,
"deleted" bool NOT NULL,
"name" varchar(255) COLLATE "pg_catalog"."default",
"value" text COLLATE "pg_catalog"."default",
"version" int4,
"event_id" int8,
"user_id" int8,
"guest_list_id" int8,
"reference_user_id" int8
)
;
-- ----------------------------
-- Indexes structure for table event_user_detail
-- ----------------------------
CREATE INDEX "idx_event_user_detail_deleted" ON "public"."event_user_detail" USING btree (
"deleted" "pg_catalog"."bool_ops" ASC NULLS LAST
);
CREATE INDEX "idx_event_user_detail_event_id" ON "public"."event_user_detail" USING btree (
"event_id" "pg_catalog"."int8_ops" ASC NULLS LAST
);
CREATE INDEX "idx_event_user_detail_guest_list_id" ON "public"."event_user_detail" USING btree (
"guest_list_id" "pg_catalog"."int8_ops" ASC NULLS LAST
);
CREATE INDEX "idx_event_user_detail_user_id" ON "public"."event_user_detail" USING btree (
"user_id" "pg_catalog"."int8_ops" ASC NULLS LAST
);
-- ----------------------------
-- Uniques structure for table event_user_detail
-- ----------------------------
ALTER TABLE "public"."event_user_detail" ADD CONSTRAINT "uk_orfh8fkwtk681af38a65everr" UNIQUE ("uuid");
-- ----------------------------
-- Primary Key structure for table event_user_detail
-- ----------------------------
ALTER TABLE "public"."event_user_detail" ADD CONSTRAINT "event_user_detail_pkey" PRIMARY KEY ("id");
-- ----------------------------
-- Foreign Keys structure for table event_user_detail
-- ----------------------------
ALTER TABLE "public"."event_user_detail" ADD CONSTRAINT "fk8bffonom9l1fgcanegl9nm641" FOREIGN KEY ("user_id") REFERENCES "public"."user" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION;
ALTER TABLE "public"."event_user_detail" ADD CONSTRAINT "fk_event_user_detail_guest_list_id" FOREIGN KEY ("guest_list_id") REFERENCES "public"."guest_list" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION;
ALTER TABLE "public"."event_user_detail" ADD CONSTRAINT "fk_event_user_detail_reference_user_id" FOREIGN KEY ("reference_user_id") REFERENCES "public"."user" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION;
ALTER TABLE "public"."event_user_detail" ADD CONSTRAINT "fkisr2ccpapw537ntw4c0mlytcw" FOREIGN KEY ("event_id") REFERENCES "public"."event" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION;
It vastly overestimates how many rows in event_user_detail it is going to find for each row in guest_list (probably because there is some row(s) in guest_list which does have a lot of entries in event_user_detail, just not the ones you are selecting here). The large number of rows it thinks it is going to find makes parallel query look attractive, but the way to get that parallel query is by using the seq scan on guest_list. So that is what it does.
You can disable parallel queries by setting max_parallel_workers_per_gather to 0. If you don't get much benefit from parallel query anyway, this may be a good "real" solution for you. If you do get a benefit from it and don't want to disable it, then you can at least do this just in the current session to see if my theory is correct.
I concur with jjanes' answer, but I want to suggest these additional experiments:
Try to ANALYZE event_user_detail; and see if that improves the estimate.
It could be that random_page_cost is set too high: it is designed for spinning disks and estimates index scans as comparatively expensive. If you lower that parameter, PostgreSQL will be more ready to use index scans.
You can do using CTE:
WITH guest AS (
SELECT id FROM guest_list WHERE event_id=2985739029 LIMIT 1
)
SELECT * FROM event_user_detail WHERE guest_list_id IN (SELECT id FROM guest)
CTE in older versions of postgresql runs like separate queries in one transactions and planned independently but doesn't send results from CTE to client.
You can read about them in the docs. Beware that this behaviour changed since 12 version of postgres and if you want to preserve old you should write it like:
WITH guest AS MATERIALIZED (
SELECT id FROM guest_list WHERE event_id=2985739029 LIMIT 1
)
SELECT * FROM event_user_detail WHERE guest_list_id IN (SELECT id FROM guest)
Also they are very useful to avoid deadlocks in updates:
WITH to_update AS (
SELECT * FROM my_table WHERE condition
ORDER BY id ASC FOR UPDATE
)
UPDATE my_table SET ... WHERE condition;
This would make all rows lock in certain order which prevents deadlocks which possible with plain update queries (e.g. both queries need to modify ids 1 and 2, and with this CTE there cannot be that first lock 1 and wait 2 while second lock 2 and wait for 1).

PostgreSQL does not choose my indexes well

create table public.tabla
(
cod_tabla bigint not null,
tabla varchar(31) not null,
constraint pk_tabla primary key (cod_tabla)
);
create table public.entidad
(
cod_entidad bigint not null,
cod_tabla bigint not null,
cod_entidad_tabla bigint not null,
constraint pk_entidad primary key (cod_entidad),
constraint fk_tabla_entidad foreign key (cod_tabla)
references public.tabla (cod_tabla) match simple
on update cascade
on delete cascade
);
CREATE INDEX idx_tabla_entidad
ON public.entidad USING btree
(cod_tabla ASC NULLS LAST);
CREATE INDEX idx_entidad_tabla_4
ON public.entidad USING btree
(cod_entidad_tabla ASC NULLS LAST)
INCLUDE(cod_entidad, cod_tabla, cod_entidad_tabla)
WHERE cod_tabla::bigint = 4;
I think postgresql doesn't use the index idx_entidad_tabla_4,
Postgresql is sequentially scanning the entire table applying the where condition
explain (analyze, buffers, format text) select * from entidad where cod_tabla = 4
Index Scan using idx_tabla_entidad on entidad (cost=0.56..51121.41 rows=1405216 width=20) (actual time=0.037..242.609 rows=1409985 loops=1)
Index Cond: ((cod_tabla)::bigint = 4)
Buffers: shared hit=12839
Planning Time: 0.158 ms
Execution Time: 311.828 ms
SELECT count(*) from entidad;
34.413.354
SELECT count(*) from entidad where cod_tabla = 4;
1.409.985
My questions are:
Why doesn't it use the index idx_entidad_tabla_4?
How could I force its use?

Postgres date search slower for less than vs greater than

I am dealing with a weird issue where a date based query runs much slower when using >= vs <=. The execution plans are here:
Slow
Fast
It looks like when it is doing the slow one, it does 3 nested loops and when it is doing the fast one it does a join but I don't get why. I've done vacuum, analyze etc to no result.
Here are the SQLs too
-- Table: public.hfj_spidx_date
-- DROP TABLE public.hfj_spidx_date;
CREATE TABLE public.hfj_spidx_date
(
sp_id bigint NOT NULL,
sp_missing boolean,
sp_name character varying(100) COLLATE pg_catalog."default" NOT NULL,
res_id bigint,
res_type character varying(255) COLLATE pg_catalog."default" NOT NULL,
sp_updated timestamp without time zone,
hash_identity bigint,
sp_value_high timestamp without time zone,
sp_value_low timestamp without time zone,
CONSTRAINT hfj_spidx_date_pkey PRIMARY KEY (sp_id),
CONSTRAINT fk17s70oa59rm9n61k9thjqrsqm FOREIGN KEY (res_id)
REFERENCES public.hfj_resource (res_id) MATCH SIMPLE
ON UPDATE NO ACTION
ON DELETE NO ACTION
)
WITH (
OIDS = FALSE
)
TABLESPACE pg_default;
ALTER TABLE public.hfj_spidx_date
OWNER to dbadmin;
-- Index: idx_sp_date_hash
-- DROP INDEX public.idx_sp_date_hash;
CREATE INDEX idx_sp_date_hash
ON public.hfj_spidx_date USING btree
(hash_identity, sp_value_low, sp_value_high)
TABLESPACE pg_default;
-- Index: idx_sp_date_resid
-- DROP INDEX public.idx_sp_date_resid;
CREATE INDEX idx_sp_date_resid
ON public.hfj_spidx_date USING btree
(res_id)
TABLESPACE pg_default;
-- Index: idx_sp_date_updated
-- DROP INDEX public.idx_sp_date_updated;
CREATE INDEX idx_sp_date_updated
ON public.hfj_spidx_date USING btree
(sp_updated)
TABLESPACE pg_default;
-------------------------------------
-- Table: public.hfj_res_link
-- DROP TABLE public.hfj_res_link;
CREATE TABLE public.hfj_res_link
(
pid bigint NOT NULL,
src_path character varying(200) COLLATE pg_catalog."default" NOT NULL,
src_resource_id bigint NOT NULL,
source_resource_type character varying(30) COLLATE pg_catalog."default" NOT NULL,
target_resource_id bigint,
target_resource_type character varying(30) COLLATE pg_catalog."default" NOT NULL,
target_resource_url character varying(200) COLLATE pg_catalog."default",
sp_updated timestamp without time zone,
CONSTRAINT hfj_res_link_pkey PRIMARY KEY (pid),
CONSTRAINT fk_reslink_source FOREIGN KEY (src_resource_id)
REFERENCES public.hfj_resource (res_id) MATCH SIMPLE
ON UPDATE NO ACTION
ON DELETE NO ACTION,
CONSTRAINT fk_reslink_target FOREIGN KEY (target_resource_id)
REFERENCES public.hfj_resource (res_id) MATCH SIMPLE
ON UPDATE NO ACTION
ON DELETE NO ACTION
)
WITH (
OIDS = FALSE
)
TABLESPACE pg_default;
ALTER TABLE public.hfj_res_link
OWNER to dbadmin;
-- Index: idx_rl_dest
-- DROP INDEX public.idx_rl_dest;
CREATE INDEX idx_rl_dest
ON public.hfj_res_link USING btree
(target_resource_id)
TABLESPACE pg_default;
-- Index: idx_rl_src
-- DROP INDEX public.idx_rl_src;
CREATE INDEX idx_rl_src
ON public.hfj_res_link USING btree
(src_resource_id)
TABLESPACE pg_default;
-- Index: idx_rl_tpathres
-- DROP INDEX public.idx_rl_tpathres;
CREATE INDEX idx_rl_tpathres
ON public.hfj_res_link USING btree
(src_path COLLATE pg_catalog."default", target_resource_id)
TABLESPACE pg_default;
As I said in my answer to what is pretty much the same question, the problem is the bad estimate in the slow query.
In the fast query PostgreSQL obviously doesn't make the mistake to think that the condition is very selective, so it chooses a different and better plan.

postgresql simple select is slow

i have a table:
CREATE TABLE my_table
(
id integer NOT NULL DEFAULT nextval('seq_my_table_id'::regclass),
fk_id1 integer NOT NULL,
fk_id2 smallint NOT NULL,
name character varying(255) NOT NULL,
description text,
currency_name character varying(3) NOT NULL,
created timestamp with time zone NOT NULL DEFAULT now(),
updated timestamp with time zone NOT NULL DEFAULT now(),
CONSTRAINT "PK_my_table_id" PRIMARY KEY (id ),
CONSTRAINT "FK_my_table_fk_id1" FOREIGN KEY (fk_id1)
REFERENCES my_table2 (id) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION DEFERRABLE INITIALLY DEFERRED,
CONSTRAINT "FK_my_table_fk_id2" FOREIGN KEY (fk_id2)
REFERENCES my_table3 (id) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION DEFERRABLE INITIALLY DEFERRED
)
WITH (
OIDS=FALSE,
autovacuum_enabled=true,
autovacuum_vacuum_threshold=50,
autovacuum_vacuum_scale_factor=0.2,
autovacuum_analyze_threshold=50,
autovacuum_analyze_scale_factor=0.1,
autovacuum_vacuum_cost_delay=20,
autovacuum_vacuum_cost_limit=200,
autovacuum_freeze_min_age=50000000,
autovacuum_freeze_max_age=200000000,
autovacuum_freeze_table_age=150000000
);
ALTER TABLE my_table
OWNER TO postgres;
CREATE INDEX my_table_fk_id1
ON my_table
USING btree
(fk_id1 );
CREATE INDEX my_table_fk_id2
ON my_table
USING btree
(fk_id2 );
tables records count
select count(id) from my_table; --24061
select count(id) from my_table2; --24061
select count(id) from my_table3; --123
execution time
select * from my_table -- ~17sec
vacuum/analyze - no effect
description - length ~ 4000 chars in each row
postgres.conf - standart settings
Version: 9.1
select all fields except description reduce execution time to ~1,5 sec
How to icrease select speed with description ?
upd
--explain analyze select * from my_table
"Seq Scan on my_table (cost=0.00..3425.79 rows=24079 width=1015) (actual time=0.019..17.238 rows=24079 loops=1)"
"Total runtime: 18.649 ms"
The question is how to make this fast. The issue is not on the server since it takes 18ms there. The simple solution is to select fewer columns so that there is less to transfer over the network. My guess is that you have long descriptions on some. Leave that column off your select and try again.