나는 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';
를 반환합니다 - 하나 개의 튜플을 반환합니다.
따라서 인덱스가 B
및 A,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을 벤치마킹하는 것이 아니라 질문하는 것입니다. 위 쿼리의 성능을 어떻게 향상시킬 수 있습니까? 다음 솔루션 (또는 질문)이 있습니다.
- 최신 안정적인 PostgreSQL로 업그레이드하십시오. 우리는 많은 서버에서 8.1.5를 생산하고 있습니다. 단점 : 업그레이드 작업이 길어질 수 있습니다. 너무 많이 신경 쓰지 않습니다. 수술을 할 것이기 때문입니다. 데이터에는 전체 덤프 및 가져 오기가 필요합니다. Pro : 성능이 향상되고 최신 버전의 추가 기능을 활용할 수 있습니다.
- 계획자가 도움을 줄 수 있도록 쿼리를 최적화하십시오. 위의 쿼리에서이 작업을 수행하는 방법을 알 수 없습니다.
- 색인을 추가하십시오. 이것은 플래너와 실행 속도를 높이는 데 도움이됩니다. 그러나 약간의 오버 헤드가 추가됩니다. 그리고 어떤 인덱스를 추가해야합니까?
A,B
및B,C
또는A
,B
및C
? 전자는 위의 쿼리를 도와줍니다. 그러나 다른 열을 필터링하는 비슷한 쿼리가 있습니다. 쿼리는B
,B,C
,A,B
,A,B,C
,B,C,D
및A,B,C,D
과 같은 열 집합에 대해 수행됩니다. 그렇다면 각 열 집합에 대해 인덱스가 필요합니까? 아니면 가장 비싼 건가요? 위 쿼리에서B,C
을 검색하는 것이 가장 비쌉니다.
감사합니다.
'B, C'에 색인을 생성하면 8.1.5 상자에서 4.02.16.04까지 쿼리 비용이 발생합니다. 8.4.4 상자에서는 최소값이 증가하고 최대 값은 9.50.1.3.52로 감소합니다. – Nicolas
다른 쿼리를 사용하면 돕기 인덱스를 추가하면 8.1.5 상자에 118625.23..118629.26에서 4.02..8.04로 비용이 변경됩니다. 동일한 색인은 8.4.4 상자에 사용되지 않습니다. – Nicolas