I've created a partial index that I expect the query planner to use in executing a query, but it's using another index instead. Using this other partial index results in a slower query. I'd really appreciate some help understanding why this is occurring. Thanks in advance!
*Postgres Version* PostgreSQL 12.7 (Ubuntu 12.7-1.pgdg20.04+1) on x86_64-pc-linux-gnu, compiled by gcc (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0, 64-bit *Problem Description* Here's the index I expect the planner to use: CREATE INDEX other_events_1004175222_pim_evdef_67951aef14bc_idx ON public.other_events_1004175222 USING btree ("time", user_id) WHERE ( (user_id <= '(1080212440,9007199254740991)'::app_user_id) AND (user_id >= '(1080212440,0)'::app_user_id) AND ( ( (type = 'click'::text) AND (library = 'web'::text) AND (strpos(hierarchy, '#close_onborading;'::text) <> 0) AND (object IS NULL) ) OR ( (type = 'click'::text) AND (library = 'web'::text) AND (strpos(hierarchy, '#proceedOnboarding;'::text) <> 0) AND (object IS NULL) ) ) ); Here's the query: EXPLAIN (ANALYZE, VERBOSE, BUFFERS) SELECT user_id, "time", 0 AS event, session_id FROM test_yasp_events_exp_1004175222 WHERE ((test_yasp_events_exp_1004175222.user_id >= '(1080212440,0)'::app_user_id) AND (test_yasp_events_exp_1004175222.user_id <= '(1080212440,9007199254740991)'::app_user_id) AND ("time" >= '1624777200000'::bigint) AND ("time" <= '1627369200000'::bigint) AND ( ( (type = 'click'::text) AND (library = 'web'::text) AND (strpos(hierarchy, '#close_onborading;'::text) <> 0) AND (object IS NULL)) OR ( (type = 'click'::text) AND (library = 'web'::text) AND (strpos(hierarchy, '#proceedOnboarding;'::text) <> 0) AND (object IS NULL)))) Here's the plan: https://explain.depesz.com/s/uNGg Note that the index being used is other_events_1004175222_pim_core_custom_2_8e65d072fbdd_idx, which is defined this way: CREATE INDEX other_events_1004175222_pim_core_custom_2_8e65d072fbdd_idx ON public.other_events_1004175222 USING btree (type, "time", user_id) WHERE ( (type IS NOT NULL) AND (object IS NULL) AND ((user_id >= '(1080212440,0)'::app_user_id) AND (user_id <= '(1080212440,9007199254740991)'::app_user_id))) You can view the definition of test_yasp_events_exp_1004175222 here <https://pastebin.com/3wYiiTMn>. Note the child tables, other_events_1004175222, pageviews_1004175222, and sessions_1004175222 which have the following constraints: other_events_1004175222: CHECK (object IS NULL) pageviews_1004175222: CHECK (object IS NOT NULL AND object = 'pageview'::text) sessions_1004175222: CHECK (object IS NOT NULL AND object = 'session'::text) Also note that these child tables have 100s of partial indexes. You can find history on why we have things set up this way here <https://heap.io/blog/running-10-million-postgresql-indexes-in-production>. Here's the table metadata for other_events_1004175222: SELECT relname, relpages, reltuples, relallvisible, relkind, relnatts, relhassubclass, reloptions, pg_table_size(oid) FROM pg_class WHERE relname = 'other_events_1004175222'; Results: [image: image.png] -- K. Matt Dupree Data Science Engineer 321.754.0526 | matt.dup...@heap.io