2010-06-14 4 views
3

나는 테이블은 사용자에게 열 개 제목의 목록을 보여주는, 내가 검색 필드의 자동 완성을 위해 해당 테이블의 정보를 사용하려면프리픽스 검색을 위해 PostgreSQL DB를 최적화하는 방법은 무엇입니까?

=#\d nodes 
      Table "public.nodes" 
Column |   Type   | Modifiers 
--------+------------------------+----------- 
id  | integer    | not null 
title | character varying(256) | 
score | double precision  | 
Indexes: 
    "nodes_pkey" PRIMARY KEY, btree (id) 

내 PostgreSQL의 DB에 약 170 만 행이 "노드"라고했다 자신의 의견에 가장 적합한 점수를 얻습니다. 그래서이 쿼리를 사용했습니다. 여기에서 "s"로 시작하는 모든 제목을 검색합니다.

=# explain analyze select title,score from nodes where title ilike 's%' order by score desc; 
                 QUERY PLAN              
----------------------------------------------------------------------------------------------------------------------- 
Sort (cost=64177.92..64581.38 rows=161385 width=25) (actual time=4930.334..5047.321 rows=161264 loops=1) 
    Sort Key: score 
    Sort Method: external merge Disk: 5712kB 
    -> Seq Scan on nodes (cost=0.00..46630.50 rows=161385 width=25) (actual time=0.611..4464.413 rows=161264 loops=1) 
     Filter: ((title)::text ~~* 's%'::text) 
Total runtime: 5260.791 ms 
(6 rows) 

이것은 자동 완성과 함께 사용하는 것이 훨씬 느립니다. Using PostgreSQL in Web 2.0 Applications에서 몇 가지 정보를 통해 내가 그래서이 더욱 향상 될 수 내게 요인 그러나 4의 속도 향상을 준 특별한 인덱스

=# create index title_idx on nodes using btree(lower(title) text_pattern_ops); 
=# explain analyze select title,score from nodes where lower(title) like lower('s%') order by score desc limit 10; 
                   QUERY PLAN                 
------------------------------------------------------------------------------------------------------------------------------------------ 
Limit (cost=18122.41..18122.43 rows=10 width=25) (actual time=1324.703..1324.708 rows=10 loops=1) 
    -> Sort (cost=18122.41..18144.60 rows=8876 width=25) (actual time=1324.700..1324.702 rows=10 loops=1) 
     Sort Key: score 
     Sort Method: top-N heapsort Memory: 17kB 
     -> Bitmap Heap Scan on nodes (cost=243.53..17930.60 rows=8876 width=25) (actual time=96.124..1227.203 rows=161264 loops=1) 
       Filter: (lower((title)::text) ~~ 's%'::text) 
       -> Bitmap Index Scan on title_idx (cost=0.00..241.31 rows=8876 width=0) (actual time=90.059..90.059 rows=161264 loops=1) 
        Index Cond: ((lower((title)::text) ~>=~ 's'::text) AND (lower((title)::text) ~<~ 't'::text)) 
Total runtime: 1325.085 ms 
(9 rows) 

와 그 개선 할 수 있었다? 's%' 대신 '%s%'을 사용하려면 어떻게해야합니까? 이 경우에도 PostgreSQL과 함께 훌륭한 성능을 얻을 수있는 기회가 있습니까? 또는 내 자동 완성 기능을 구현하기 위해 다른 솔루션 (Lucene?, Sphinx?)을 사용해 보는 것이 좋습니다. 추가 조사를 위해

답변

2

팁 :

  • 파티션 타이틀 키의 표. 이렇게하면 포스트그레스가 작업 할 필요가있는 목록을 더 작게 만들 수 있습니다.

  • postgresql에 더 많은 메모리를 제공하여 캐시 적중률이 98 % 이상이되도록하십시오. 이 테이블은 약 0.5G 걸릴 것입니다, 나는 2G가 요즘 문제가 없어야한다고 생각합니다. 통계 수집이 가능하고 pg_stats 테이블에서 읽혀 졌는지 확인하십시오.

  • 제목이 감소 된 두 번째 테이블을 만듭니다. 전체 테이블이 더 적은 데이터베이스 블록에 적합하도록 12 자. 하위 문자열의 인덱스도 작동 할 수 있지만 신중한 쿼리가 필요합니다.

  • 부분 문자열이 길면 쿼리가 더 빨리 실행됩니다. 작은 하위 문자열에 대해 별도의 테이블을 만들고 값에 상위 10 개 또는 표시하려는 선택 항목을 저장합니다. 1,2,3 문자열 조합은 약 20000 개입니다.

  • % abc % 쿼리를 원한다면 같은 아이디어를 사용할 수 있지만 아마도 lucene으로 전환하는 것이 좋습니다.

0

당신은 분명히 150000+ 결과에 관심이 없다, 그래서 당신이 그들을 제한해야합니다 :

select title,score 
    from nodes 
    where title ilike 's%' 
    order by score desc 
    limit 10; 

또한 "> ="와 "<"기능 인덱스를 생성하고 사용을 고려할 수 있습니다 :

create index nodes_title_lower_idx on nodes (lower(title)); 
select title,score 
    from nodes 
    where lower(title)>='s' and lower(title)<'t' 
    order by score desc 
    limit 10; 

또한 점수에 색인을 작성해야합니다. ilike %s%의 경우 도움이됩니다.

3

C 로캘이 아닌 경우 text_pattern_ops 색인이 필요합니다.

참조 : index types.

관련 문제