Planner won't use composite index if there is an order by ???? - Mailing list pgsql-performance

From Dave Cramer
Subject Planner won't use composite index if there is an order by ????
Date
Msg-id DECED72A-5784-4D6C-9E27-6316FDE32E64@fastcrypt.com
Whole thread Raw
Responses Re: Planner won't use composite index if there is an order by ????
List pgsql-performance
Any idea why it wouldn't choose the right index ?

This is 8.3

> # \d battles
>                                          Table "public.battles"
>       Column        |            Type             |
> Modifiers
> ---------------------+-----------------------------
> +------------------------------------------------------
> id                  | integer                     | not null default
> nextval('battles_id_seq'::regclass)
> user_id             | integer                     | not null
> contest_id          | integer                     | not null
> entry_1_id          | integer                     | not null
> entry_2_id          | integer                     | not null
> new_entry_1_score   | integer                     |
> new_entry_2_score   | integer                     |
> score               | integer                     |
> scored_at           | timestamp without time zone |
> created_at          | timestamp without time zone | not null
> function_profile_id | integer                     |
> battle_type         | integer                     | default 0
> Indexes:
>    "battles_pkey" PRIMARY KEY, btree (id)
>    "unique_with_type" UNIQUE, btree (user_id, entry_1_id, entry_2_id,
> battle_type)
>    "battles_by_contest_and_type" btree (contest_id, battle_type)
>    "battles_by_time" btree (scored_at)
> Foreign-key constraints:
>    "fk_battles_contests" FOREIGN KEY (contest_id) REFERENCES
> contests(id)
>    "fk_battles_lefty" FOREIGN KEY (entry_1_id) REFERENCES entries(id)
>    "fk_battles_righty" FOREIGN KEY (entry_2_id) REFERENCES entries(id)
>    "fk_battles_users" FOREIGN KEY (user_id) REFERENCES users(id)
>
>
> Here is the analyze of the query we want but it takes forever because
> its using the index for the sort instead of restricting the number of
> battles by user_id:
>
> ourstage_production=# explain analyze SELECT * FROM battles WHERE
> user_id = 196698 and scored_at is not null and score in (-3,3) ORDER
> BY
> id DESC LIMIT 5;
>
> QUERY PLAN
>
>
-------------------------------------------------------------------------------------------------------------------------------------------------------
> Limit  (cost=0.00..8381.61 rows=5 width=56) (actual
> time=124421.499..183659.404 rows=2 loops=1)
>   ->  Index Scan Backward using battles_pkey on battles
> (cost=0.00..670528.67 rows=400 width=56) (actual
> time=124421.495..183659.394 rows=2 loops=1)
>         Filter: ((scored_at IS NOT NULL) AND (score = ANY
> ('{-3,3}'::integer[])) AND (user_id = 196698))
> Total runtime: 183659.446 ms
> (4 rows)
>
>
> If you remove the ORDER BY then it runs in 4 ms:
>
> ourstage_production=# explain analyze SELECT * FROM battles WHERE
> user_id = 196698 and scored_at is not null and score in (-3,3) LIMIT
> 5;
>                                                              QUERY
> PLAN
>
>
---------------------------------------------------------------------------------------------------------------------------------------
> Limit  (cost=0.00..126.65 rows=5 width=56) (actual time=4.607..4.621
> rows=2 loops=1)
>   ->  Index Scan using unique_with_type on battles
> (cost=0.00..10131.66 rows=400 width=56) (actual time=4.603..4.611
> rows=2 loops=1)
>         Index Cond: (user_id = 196698)
>         Filter: ((scored_at IS NOT NULL) AND (score = ANY
> ('{-3,3}'::integer[])))
> Total runtime: 4.660 ms
> (5 rows)
>
>
> Here we tried to limit the table scan by time so that it would scan
> far
> fewer records.  But what ended up happening is that it flipped it over
> to using the right index.  The one that is based on user_id is much
> preferred:
>
>
> ourstage_production=# explain analyze SELECT * FROM battles WHERE
> user_id = 196698 and scored_at is not null and score in (-3,3) and
> scored_at > now() - INTERVAL '6 month' ORDER BY id DESC LIMIT 5;
>                                                                 QUERY
> PLAN
>
---------------------------------------------------------------------------------------------------------------------------------------------
> Limit  (cost=10158.16..10158.18 rows=5 width=56) (actual
> time=0.097..0.106 rows=2 loops=1)
>   ->  Sort  (cost=10158.16..10158.92 rows=302 width=56) (actual
> time=0.094..0.096 rows=2 loops=1)
>         Sort Key: id
>         Sort Method:  quicksort  Memory: 25kB
>         ->  Index Scan using unique_with_type on battles
> (cost=0.00..10153.15 rows=302 width=56) (actual time=0.069..0.078
> rows=2 loops=1)
>               Index Cond: (user_id = 196698)
>               Filter: ((scored_at IS NOT NULL) AND (score = ANY
> ('{-3,3}'::integer[])) AND (scored_at > (now() - '6 mons'::interval)))
> Total runtime: 0.152 ms
> (8 rows)
>
>
> Notice that we added time restriction and it now chooses to not use
> the
> time index and goes after the index based on user_id.  Why?  We
> don't know.


pgsql-performance by date:

Previous
From: PFC
Date:
Subject: Re: Question about disk IO an index use and seeking advice
Next
From: Tom Lane
Date:
Subject: Re: Planner won't use composite index if there is an order by ????