2017-02-06 102 views
0

下面的查询运行在Postgres的了解缓慢位图扫描堆在LIKE查询

SELECT COUNT(*) 
FROM "posts" 
WHERE "posts"."author_id" = 20 
AND ("posts"."title" ILIKE '123'); 

显然涉及到一个很慢的位图堆扫描。我如何能够诊断这种缓慢的原因?我能做些什么来让它表现更好?

my-app::DATABASE=> EXPLAIN ANALYZE VERBOSE 
my-app::DATABASE-> SELECT COUNT(*) 
my-app::DATABASE-> FROM "posts" 
my-app::DATABASE-> WHERE "posts"."author_id" = 20 
my-app::DATABASE-> AND ("posts"."title" ILIKE '123'); 
                      QUERY PLAN                    
------------------------------------------------------------------------------------------------------------------------------------------------------------------ 
Aggregate (cost=25516.64..25516.64 rows=1 width=0) (actual time=35632.267..35632.267 rows=1 loops=1) 
    Output: count(*) 
    -> Bitmap Heap Scan on public.posts (cost=307.46..25516.64 rows=1 width=0) (actual time=35632.264..35632.264 rows=0 loops=1) 
     Recheck Cond: (posts.author_id = 20) 
     Filter: ((posts.title)::text ~~* '123'::text) 
     Rows Removed by Filter: 22216 
     Heap Blocks: exact=15419 
     -> Bitmap Index Scan on index_posts_on_author_id_and_state (cost=0.00..307.46 rows=23586 width=0) (actual time=54.585..54.585 rows=22235 loops=1) 
       Index Cond: (posts.author_id = 20) 
Planning time: 0.853 ms 
Execution time: 35632.405 ms 
(11 rows) 
+0

为什么在没有通配符时使用'ILIKE'? – dnoeth

+0

它只是探索查询策略,但通常它可能会搜索后缀或前缀。 – sunless

+0

如果标题不是很大,在'(author_id,title)'上创建一个索引 –

回答

2

查询写入的方式没有索引可以使它更好。

但是你可以重写它是这样的:

SELECT count(*) 
FROM posts 
WHERE posts.author_id = 20 
AND lower(posts.title) LIKE lower('abc%'); 

那么下面的索引可以帮助在某些情况下

CREATE INDEX posts_auth_title_ind 
    ON posts (
     author_id, 
     lower(title) text_pattern_ops 
    ); 

text_pattern_ops需要LIKE,除非你使用的是CPOSIX整理。

如果搜索模式以通配符开头,则没有B树索引可以提供帮助。在这种情况下,您可以尝试pg_tgrm索引。