2010-08-12 4 views
1

나는 3 백만 개의 튜플을 가진 테이블을 가지고 있습니다. 너무 자주 변경되지는 않으며 (일주일에 몇 번 업데이트되거나 삽입됩니다) 많이 읽습니다. (제발 길이 1의 varchar에 대해 언급하지 말아라. 나도 안다.)PostgreSQL 쿼리 및 테이블 최적화

Column |   Type   |      Modifiers      
-------------+-----------------------+------------------------------------------------------ 
id   | integer    | not null default nextval('mytable_id_seq'::regclass) 
A   | character varying(5) | not null 
B   | character varying(16) | not null 
C   | character varying(3) | not null 
D   | character varying(1) | not null 
otherdata | character varying(99) | not null 
Indexes: 
    "mytable_pkey" PRIMARY KEY, btree (id) 
    "mytable_unique_key" UNIQUE, btree (A, B, C, D) 
    "mytable_B_idx" btree (B) 
Foreign-key constraints: 
    "$1" FOREIGN KEY (A, B) REFERENCES anothertable1(A, B) 
    "$2" FOREIGN KEY (C) REFERENCES anothertable2(C) 
    "$3" FOREIGN KEY (D) REFERENCES anothertable3(D) 
Referenced by: 
    TABLE "anothertable4" CONSTRAINT "$1" FOREIGN KEY (id) REFERENCES mytable(id) 
    TABLE "anothertable5" CONSTRAINT "fkey_id" FOREIGN KEY (id) REFERENCES mytable(id) ON UPDATE CASCADE ON DELETE CASCADE 

id이 내 기본 키입니다. A,B,C,D은 후보 키입니다. 둘 다 분명히 튜플을 식별합니다.

가장 자주 쿼리는 다음과 같습니다

SELECT * FROM mytable WHERE B='foo';이 - 튜플

의 숫자

SELECT * FROM mytable WHERE A='foo' AND B='bar' AND C='baz' AND D='f';를 반환합니다 - 하나 개의 튜플을 반환합니다.

따라서 인덱스가 BA,B,C,D 인 이유는 무엇입니까?

자, 어떤 이유로, 나는 다음과 같은 쿼리를하고 있어요 (그리고 더 유사) :

SELECT * FROM mytable WHERE ((A='foo' AND B='bar') OR (B='foo' AND C='bar'));

한 상자의 PostgreSQL 8.4.4을 실행 중입니다. 내가 첫 번째 쿼리를 분석 EXPLAIN 경우에, 나는 다음과 같은 쿼리 계획을 얻을 :

                  QUERY PLAN                   
--------------------------------------------------------------------------------------------------------------------------------------------------------------- 
Bitmap Heap Scan on mytable (cost=9.74..174.30 rows=1 width=14) (actual time=0.000..0.000 rows=5 loops=1) 
    Recheck Cond: ((((A)::text = 'foo'::text) AND ((B)::text = 'bar'::text)) OR ((B)::text = 'foo'::text)) 
    Filter: ((((A)::text = 'foo'::text) AND ((B)::text = 'bar'::text)) OR (((B)::text = 'foo'::text) AND ((C)::text = 'bar'::text))) 
    -> BitmapOr (cost=9.74..9.74 rows=42 width=0) (actual time=0.000..0.000 rows=0 loops=1) 
     -> Bitmap Index Scan on mytable_unique_key(cost=0.00..4.80 rows=1 width=0) (actual time=0.000..0.000 rows=0 loops=1) 
       Index Cond: (((A)::text = 'foo'::text) AND ((B)::text = 'bar'::text)) 
     -> Bitmap Index Scan on mytable_B_idx(cost=0.00..4.94 rows=42 width=0) (actual time=0.000..0.000 rows=316 loops=1) 
       Index Cond: ((B)::text = 'foo'::text) 
Total runtime: 0.000 ms 
(9 rows) 

9.74의 최소 비용과 거의 즉시 반환 (예치, 그것은 캐시)입니다. 테이블에 동일한 내용 - - 내가 다른 유사한 시스템에 PostgreSQL의 8.1.5에서 동일한 쿼리를 실행하면 지금, 나는 다음과 같은 얻을 :

                  QUERY PLAN                  
--------------------------------------------------------------------------------------------------------------------------------------------------------------------- 
Bitmap Heap Scan on mytable (cost=110156.34..110168.36 rows=3 width=26) (actual time=147200.984..147221.480 rows=5 loops=1) 
    Recheck Cond: ((((A)::text = 'foo'::text) AND ((B)::text = 'bar'::text)) OR (((B)::text = 'foo'::text) AND ((C)::text = 'bar'::text))) 
    -> BitmapOr (cost=110156.34..110156.34 rows=3 width=0) (actual time=147185.513..147185.513 rows=0 loops=1) 
     -> Bitmap Index Scan on mytable_unique_key(cost=0.00..2.01 rows=1 width=0) (actual time=83.275..83.275 rows=0 loops=1) 
       Index Cond: (((A)::text = 'foo'::text) AND ((B)::text = 'bar'::text)) 
     -> Bitmap Index Scan on mytable_unique_key(cost=0.00..110154.34 rows=2 width=0) (actual time=147102.230..147102.230 rows=5 loops=1) 
       Index Cond: (((B)::text = 'foo'::text) AND ((C)::text = 'bar'::text)) 
Total runtime: 147221.663 ms 
(8 rows) 

두 테이블이 VACUUM'ed 두 상자를했다. 그래서 놀라운 차이는 8.1.5와 8.4.4 사이에 도입 된 다양한 버전과 성능 향상 때문입니다. devs까지 큰!

이 질문은 다른 버전의 PostgreSQL을 벤치마킹하는 것이 아니라 질문하는 것입니다. 위 쿼리의 성능을 어떻게 향상시킬 수 있습니까? 다음 솔루션 (또는 질문)이 있습니다.

  1. 최신 안정적인 PostgreSQL로 업그레이드하십시오. 우리는 많은 서버에서 8.1.5를 생산하고 있습니다. 단점 : 업그레이드 작업이 길어질 수 있습니다. 너무 많이 신경 쓰지 않습니다. 수술을 할 것이기 때문입니다. 데이터에는 전체 덤프 및 가져 오기가 필요합니다. Pro : 성능이 향상되고 최신 버전의 추가 기능을 활용할 수 있습니다.
  2. 계획자가 도움을 줄 수 있도록 쿼리를 최적화하십시오. 위의 쿼리에서이 작업을 수행하는 방법을 알 수 없습니다.
  3. 색인을 추가하십시오. 이것은 플래너와 실행 속도를 높이는 데 도움이됩니다. 그러나 약간의 오버 헤드가 추가됩니다. 그리고 어떤 인덱스를 추가해야합니까? A,BB,C 또는 A, BC? 전자는 위의 쿼리를 도와줍니다. 그러나 다른 열을 필터링하는 비슷한 쿼리가 있습니다. 쿼리는 B, B,C, A,B, A,B,C, B,C,DA,B,C,D과 같은 열 집합에 대해 수행됩니다. 그렇다면 각 열 집합에 대해 인덱스가 필요합니까? 아니면 가장 비싼 건가요? 위 쿼리에서 B,C을 검색하는 것이 가장 비쌉니다.

감사합니다.

+0

'B, C'에 색인을 생성하면 8.1.5 상자에서 4.02.16.04까지 쿼리 비용이 발생합니다. 8.4.4 상자에서는 최소값이 증가하고 최대 값은 9.50.1.3.52로 감소합니다. – Nicolas

+0

다른 쿼리를 사용하면 돕기 인덱스를 추가하면 8.1.5 상자에 118625.23..118629.26에서 4.02..8.04로 비용이 변경됩니다. 동일한 색인은 8.4.4 상자에 사용되지 않습니다. – Nicolas

답변

2

8.1 상자에 mytable_unique_key-index가 부풀어 오른 것처럼 보입니다. 먼저이 문제를 해결해보십시오.

새로운 색인을 만들 수 있습니까?

새로운 버전으로의 이전을 시작해야합니다. 8.1에 대한 지원은 올해 끝납니다.

+0

Roger, Roger. DB를 최근에 프로덕션 백업에서 가져 왔고 가져 오기 이후 내용이 변경되지 않았기 때문에 다시 인덱싱이 도움이 될 것이라고 생각하지 않습니다. 일단 완료되면 다시보고 할 것입니다. – Nicolas

+0

새 색인이없는 새 비용 = 42553.34..42565.36. 그래서 개선되었지만 여전히 무거운 짐입니다. 나는 받아 들일 것이고 작전에 약간의 일을 줄 것이다. 고맙습니다. – Nicolas

+0

8.4- 플래너가 8.1- 플래너보다 훨씬 더 똑똑하다는 것을 잊지 마십시오. 이것이 8.1 상자가 잘못된 색인을 선택하는 이유 일 수 있습니다. 8.1- 박스에서는 B.뿐만 아니라 B와 C에 인덱스를 사용하는 것이 더 나을 것입니다. –