0

I have a table with 4707838 rows. When I run the following query on this table it takes around 9 seconds to execute.

SELECT json_agg(
            json_build_object('accessorId',
                              p."accessorId",
                              'mobile',json_build_object('enabled', p.mobile,'settings',
                                                         json_build_object('proximityAccess', p."proximity",
                                                                           'tapToAccess', p."tapToAccess",
                                                                           'clickToAccessRange', p."clickToAccessRange",
                                                                           'remoteAccess',p."remote")
                                                                           ),'
                                                         card',json_build_object('enabled',p."card"),
                                                         'fingerprint',json_build_object('enabled',p."fingerprint"))
      ) AS permissions 
FROM permissions AS p 
WHERE p."accessPointId"=99

The output of explain analyze is as follows:

Aggregate  (cost=49860.12..49860.13 rows=1 width=32) (actual time=9011.711..9011.712 rows=1 loops=1)
  Buffers: shared read=29720
  I/O Timings: read=8192.273
  ->  Bitmap Heap Scan on permissions p  (cost=775.86..49350.25 rows=33991 width=14) (actual time=48.886..8704.470 rows=36556 loops=1)
        Recheck Cond: ("accessPointId" = 99)
        Heap Blocks: exact=29331
        Buffers: shared read=29720
        I/O Timings: read=8192.273
        ->  Bitmap Index Scan on composite_key_accessor_access_point  (cost=0.00..767.37 rows=33991 width=0) (actual time=38.767..38.768 rows=37032 loops=1)
              Index Cond: ("accessPointId" = 99)
              Buffers: shared read=105
              I/O Timings: read=32.592
Planning Time: 0.142 ms
Execution Time: 9012.719 ms

This table has a btree index on accessorId column and composite index on (accessorId,accessPointId). Can anyone tell me what could be the reason for this query to be slow even though it uses an index?

  • The I/O timing looks extremely slow. Are you running this on some kind of I/O limited system? –  May 21 '22 at 12:48

1 Answers1

0

Over 90% of the time is waiting to get data from disk. At 3.6 ms per read, that is pretty fast for a harddrive (suggesting that much of the data was already in the filesystem cache, or that some of the reads brought in neighboring data that was also eventually required--that is sequential reads not just random reads) but slow for a SSD.

If you set enable_bitmapscan=off and clear the cache (or pick a not recently used "accessPointId" value) what performance do you get?

How big is the table? If you are reading a substantial fraction of the table and think you are not getting as much benefit from sequential reads as you should be, you can try making your OSes readahead settings more aggressive. On Linux that is something like sudo blockdev --setra ...

You could put all columns referred to by the query into the index, to enable index-only scans. But given the number of columns you are using that might be impractical. You could want "accessPointId" to be the first column in the index. By the way, is the index currently used really on (accessorId,accessPointId)? It looks to me like "accessPointId" is really the first column in that index, not the 2nd one.

You could cluster the table by an index which has "accessPointId" as the first column. That would group the related records together for faster access. But note it is a slow operation and takes a strong lock on the table while it is running, and future data going into the table won't be clustered, only the current data.

You could try to increase effective_io_concurrency so that you can have multiple io requests outstanding at a time. How effective this is will depend on your hardware.

jjanes
  • 37,812
  • 5
  • 27
  • 34