Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • SEARCH
  • Home
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 8731443
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: June 13, 20262026-06-13T09:14:25+00:00 2026-06-13T09:14:25+00:00

Hi I’m hosted on Heroku running postgresql 9.1.6 on a their Ika plan (7,5gb

  • 0

Hi I’m hosted on Heroku running postgresql 9.1.6 on a their Ika plan (7,5gb ram). I have a table called cars. I need to do the following:

SELECT COUNT(*) FROM "cars" WHERE "cars"."reference_id" = 'toyota_hilux'

Now this takes an awful lot of time (64 sec!!!)

Aggregate  (cost=2849.52..2849.52 rows=1 width=0) (actual time=63388.390..63388.391 rows=1 loops=1)
  ->  Bitmap Heap Scan on cars  (cost=24.76..2848.78 rows=1464 width=0) (actual time=1169.581..63387.361 rows=739 loops=1)
        Recheck Cond: ((reference_id)::text = 'toyota_hilux'::text)
        ->  Bitmap Index Scan on index_cars_on_reference_id  (cost=0.00..24.69 rows=1464 width=0) (actual time=547.530..547.530 rows=832 loops=1)
              Index Cond: ((reference_id)::text = 'toyota_hilux'::text)
Total runtime: 64112.412 ms

A little background:

The table holds around 3.2m rows, and the column that I’m trying to count on, has the following setup:

reference_id character varying(50);

and index:

CREATE INDEX index_cars_on_reference_id
  ON cars
  USING btree
  (reference_id COLLATE pg_catalog."default" );

What am I doing wrong? I expect that this performance is not what I should expect – or should I?

  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-06-13T09:14:27+00:00Added an answer on June 13, 2026 at 9:14 am

    What @Satya claims in his comment is not quite true. In the presence of a matching index, the planner only chooses a full table scan if table statistics imply it would return more than around 5 % (depends) of the table, because it is then faster to scan the whole table.

    As you see from your own question this is not the case for your query. It uses a Bitmap Index Scan followed by a Bitmap Heap Scan. Though I would have expected a plain index scan. (?)

    I notice two more things in your explain output:
    The first scan find 832 rows, while the second reduces the count to 739. This would indicate that you have many dead tuples in your index.

    Check the execution time after each step with EXPLAIN ANALYZE and maybe add the results to your question:

    First, rerun the query with EXPLAIN ANALYZE two or three times to populate the cache. What’s the result of the last run compared to the first?

    Next:

    VACUUM ANALYZE cars;
    

    Rerun.

    If you have lots of write operations on the table, I would set a fill factor lower than 100. Like:

    ALTER TABLE cars SET (fillfactor=90);
    

    Lower if your row size is big or you have a lot of write operations. Then:

    VACUUM FULL ANALYZE cars;
    

    This will take a while. Rerun.

    Or, if you can afford to do this (and other important queries do not have contradicting requirements):

    CLUSTER cars USING index_cars_on_reference_id;
    

    This rewrites the table in the physical order of the index, which should make this kind of query much faster.


    Normalize schema

    If you need this to be really fast, create a table car_type with a serial primary key and reference it from the table cars. This will shrink the necessary index to a fraction of what it is now.

    Goes without saying that you make a backup before you try any of this.

    CREATE temp TABLE car_type (
       car_type_id serial PRIMARY KEY
     , car_type text
     );
    
    INSERT INTO car_type (car_type)
    SELECT DISTINCT car_type_id FROM cars ORDER BY car_type_id;
    
    ANALYZE car_type;
    
    CREATE UNIQUE INDEX car_type_uni_idx ON car_type (car_type); -- unique types
    
    ALTER TABLE cars RENAME COLUMN car_type_id TO car_type; -- rename old col
    ALTER TABLE cars ADD COLUMN car_type_id int; -- add new int col
    
    UPDATE cars c
    SET car_type_id = ct.car_type_id
    FROM car_type ct
    WHERE ct.car_type = c.car_type;
    
    ALTER TABLE cars DROP COLUMN car_type; -- drop old varchar col
    
    CREATE INDEX cars_car_type_id_idx ON cars (car_type_id);    
    
    ALTER TABLE cars 
    ADD CONSTRAINT cars_car_type_id_fkey FOREIGN KEY (car_type_id )
    REFERENCES car_type (car_type_id) ON UPDATE CASCADE; -- add fk
    
    VACUUM FULL ANALYZE cars;
    

    Or, if you want to go all-out:

    CLUSTER cars USING cars_car_type_id_idx;
    

    Your query would now look like this:

    SELECT count(*)
    FROM   cars
    WHERE  car_type_id = (SELECT car_type_id FROM car_type
                          WHERE car_type = 'toyota_hilux')
    

    And should be even faster. Mainly because index and table are smaller now, but also because integer handling is faster than varchar handling. The gain will not be dramatic over the clustered table on the varchar column, though.

    A welcome side effect: if you have to rename a type, it’s a tiny UPDATE to one row now, not messing with the big table at all.

    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

I have a string like this: La Torre Eiffel paragonata all’Everest What PHP function
I have a French site that I want to parse, but am running into
I have thousands of HTML files to process using Groovy/Java and I need to
I have a .ini file as follows: [playlist] numberofentries=2 File1=http://87.230.82.17:80 Title1=(#1 - 365/1400) Example
link Im having trouble converting the html entites into html characters, (&# 8217;) i
I have just tried to save a simple *.rtf file with some websites and
I have a jquery bug and I've been looking for hours now, I can't
this is what i have right now Drawing an RSS feed into the php,
I have this code to decode numeric html entities to the UTF8 equivalent character.
In my XML file chapters tag has more chapter tag.i need to display chapters

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.