简体   繁体   中英

Single count query taking too much time postgresql

explain analyze  SELECT COUNT(*) FROM "customers" WHERE (TRIM(telephone) = 
'06868787878' AND check_id = 41); 

                          QUERY PLAN                                                                      
------------------------------------------------------------------------------  
------------------------------------------------------------------- 
Aggregate  (cost=12982.58..12982.59 rows=1 width=0) (actual 
time=200.452..200.453 rows=1 loops=1) 
->  Bitmap Heap Scan on customers  (cost=544.59..12982.21 rows=147 width=0) 
(actual time=14.555..200.447 rows=1 loops=1) 
     Recheck Cond: (check_id = 41) 
     Filter: (btrim((telephone)::text) = '06868787878'::text) 
     Rows Removed by Filter: 29394 
     ->  Bitmap Index Scan on idx_customers_check_id  (cost=0.00..544.55 
   rows=29350 width=0) (actual time=9.669..9.669 rows=29395 loops=1) 
           Index Cond: (check_id = 41) 
  Total runtime: 200.750 ms 
 (8 rows) 

also sometimes its taking (293.6ms), (1956.3ms), is there any way to avoid this?

It depends quite a bit on your schema and your use patterns, but there are a few things to try.

  1. Trim your telephone numbers as they're entered into the DB rather than when you do this count. When you use TRIM during the count, the DB has to run it on every row it's evaluating, which is wasteful. If you guarantee your numbers are always trimmed, you can do a simpler telephone = '06868787878' check. If that's common, make sure there's an index on telephone .
  2. If you can't or don't want to trim your telephone data before the query, create an index on the expression TRIM(telephone) . This effectively precomputes all the work TRIM is doing, but obviously is only helpful looking up TRIM(telephone) = '123' , not telephone = '123' on its own anymore.
  3. Put your indices on the most specific columns you can. Eg. if check_id is only 41 in 2 rows, Postgres can use that index first to narrow down the set, then it has very little work to do verifying the rest of your conditions. If check_id is often 41 , but telephone is only infrequently 06868787878 , the same applies, and you should have your index on telephone . If both are pretty evenly distributed and this is a common query pattern, maybe you want a multicolumn index on (check_id, telephone) . Following the same reasoning as with single-column indices, put the more specific column first, or if you also need to filter on just one of the columns, put that one first. Eg. the (check_id, telephone) index lets you efficiently query for the check_id prefix too.

    3b. Creating a multicolumn index that covers all of your conditions can be quite efficient, since Postgres can use just the index to perform counts, without having to perform a secondary lookup to get the main record and check conditions not covered by the index.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM