PostgreSQL의 숨겨진 기능 [닫힌]


80

아직 게시되지 않은 것이 놀랍습니다. Postgres에서 알고있는 흥미로운 트릭이 있습니까? 모호한 구성 옵션과 확장 / 성능 트릭은 특히 환영합니다.

해당 MySQL 스레드 에 대한 9 개의 댓글을 이길 수 있다고 확신 합니다. :)

답변:


76

postgres는 MySQL보다 훨씬 더 건전하기 때문에보고 할 "트릭"이 많지 않습니다. ;-)

매뉴얼은 멋진가 성능 팁.

기억해야 할 몇 가지 다른 성능 관련 사항 :

  • autovacuum이 켜져 있는지 확인
  • postgres.conf (유효 캐시 크기, 공유 버퍼, 작업 메모리 ... 조정할 많은 옵션)를 살펴 보았는지 확인하십시오.
  • pgpool 또는 pgbouncer 를 사용 하여 "실제"데이터베이스 연결을 최소로 유지합니다.
  • EXPLAIN 및 EXPLAIN ANALYZE가 어떻게 작동 하는지 알아보십시오 . 출력을 읽는 방법을 배웁니다.
  • CLUSTER 는 인덱스에 따라 디스크의 데이터를 정렬합니다. 큰 (대부분) 읽기 전용 테이블의 성능을 크게 향상시킬 수 있습니다. 클러스터링은 일회성 작업입니다. 이후에 테이블이 업데이트 될 때 변경 사항이 클러스터링되지 않습니다.

다음은 구성 또는 성능과 관련이없는 유용한 몇 가지 사항입니다.

현재 무슨 일이 일어나고 있는지 확인하려면 :

select * from pg_stat_activity;

기타 기능 검색 :

select * from pg_proc WHERE proname ~* '^pg_.*'

데이터베이스 크기 찾기 :

select pg_database_size('postgres');
select pg_size_pretty(pg_database_size('postgres'));

모든 데이터베이스의 크기 찾기 :

select datname, pg_size_pretty(pg_database_size(datname)) as size
  from pg_database;

테이블 및 인덱스 크기 찾기 :

select pg_size_pretty(pg_relation_size('public.customer'));

또는 모든 테이블과 인덱스를 나열하려면 (아마도보기를 더 쉽게 만들 수 있음) :

select schemaname, relname,
    pg_size_pretty(pg_relation_size(schemaname || '.' || relname)) as size
  from (select schemaname, relname, 'table' as type
          from pg_stat_user_tables
        union all
        select schemaname, relname, 'index' as type
          from pg_stat_user_indexes) x;

아, 그리고 트랜잭션을 중첩하고 부분 트랜잭션을 롤백 할 수 있습니다 ++

test=# begin;
BEGIN
test=# select count(*) from customer where name='test';
 count 
-------
     0
(1 row)
test=# insert into customer (name) values ('test');
INSERT 0 1
test=# savepoint foo;
SAVEPOINT
test=# update customer set name='john';
UPDATE 3
test=# rollback to savepoint foo;
ROLLBACK
test=# commit;
COMMIT
test=# select count(*) from customer where name='test';
 count 
-------
     1
(1 row)

감사. 편집 : 클러스터에 대한 정보를 추가했습니다.
tommym 2009

데이터베이스 크기를 보여주는 것은 8.4 베타 psql의 "\ l"기능 중 하나입니다. 그때까지 8.3에는 크기를 바이트 단위로 미리 설정하는 pg_size_pretty () 함수가 있다고 생각합니다.
araqnid 2009

팁 고마워! pg_size_pretty를 알지 못했습니다. 나는 그것을 포함하도록 내 대답을 업데이트했습니다.
tommym 2009

3
replace (answer, 'per say', 'per se')
asjo

23

쉬운 트릭은 PostgreSQL의가 (아직 수행하지 않은 경우)와 그것을 작업에 더 많은 RAM을 제공하는 단지입니다 (따로 설정 물론 적절한 인덱스를 사용하는) 더 많이 수행 할 수 있습니다. 대부분의 기본 설치에서 shared_buffers 의 값 은 너무 낮습니다 (제 생각에는). 당신은 설정할 수 있습니다

공유 버퍼

postgresql.conf에서. 이 숫자를 128로 나누어 postgres가 요구할 수있는 메모리 양 (MB)의 근사치를 구합니다. 충분하면 postgresql이 날아갈 것입니다. postgresql을 다시 시작하는 것을 잊지 마십시오.

Linux 시스템에서 postgresql이 다시 시작되지 않으면 kernel.shmmax 제한에 도달했을 것입니다. 더 높게 설정하십시오.

sysctl -w kernel.shmmax=xxxx

부팅 사이에이를 유지하려면 kernel.shmmax 항목을 /etc/sysctl.conf에 추가하십시오.

여기에서 Postgresql 트릭 전체를 찾을 수 있습니다 .


17

Postgres는 INTERVAL 지원 덕분에 매우 강력한 날짜 시간 처리 기능을 갖추고 있습니다.

예를 들면 :

select NOW(), NOW() + '1 hour';
              now              |           ?column?            
-------------------------------+-------------------------------
 2009-04-18 01:37:49.116614+00 | 2009-04-18 02:37:49.116614+00
(1 row)



select current_date ,(current_date +  interval '1 year')::date;
    date             |  date            
---------------------+----------------
 2014-10-17          | 2015-10-17
(1 row)

많은 문자열을 INTERVAL 유형으로 캐스트 할 수 있습니다.


15

시작하겠습니다. SQLite에서 Postgres로 전환 할 때마다 일반적으로 매우 큰 데이터 세트가 있습니다. 핵심은 INSERTS를 수행하는 대신 COPY FROM을 사용하여 테이블을로드하는 것입니다. 문서 참조 :

http://www.postgresql.org/docs/8.1/static/sql-copy.html

다음 예제는 필드 구분 기호로 수직 막대 (|)를 사용하여 클라이언트에 테이블을 복사합니다.

COPY country TO STDOUT WITH DELIMITER '|';

파일의 데이터를 국가 테이블로 복사하려면 :

COPY country FROM '/usr1/proj/bray/sql/country_data';

참조 : sqlite3에서 더 빠른 대량 삽입?


2
이것은 csv 가져 오기에도 유용합니다.
ChristopheD

최근 릴리스 (최소 8.3 이상)에서는 COPY와 동일한 트랜잭션에서 채우는 테이블을 생성하거나 자르면 WAL 로그를 건드리지 않고 더 빠른 성능을 얻을 수 있습니다. postgresql.org/docs/8.3/static/populate.html
TREE

12
  • 내가 가장 좋아하는 것은 generate_series: 마침내 더미 행 집합을 생성하는 깨끗한 방법입니다.
  • LIMIT하위 쿼리 의 절 에서 상관 값을 사용하는 기능 :

    SELECT  (
            SELECT  exp_word
            FROM    mytable
            OFFSET id
            LIMIT 1
            )
    FROM    othertable
    
  • 사용자 지정 집계 (문서에서 다루지 않음)에서 여러 매개 변수를 사용하려는 경우 : 내 블로그의 기사에서 예제를 참조하십시오 .

1
+1, generate_series ()는 몇 가지 작업에 필요한 것입니다 (예 : "더미 테이블"이 필요할 때마다). 두 번째 스 니펫도 흥미로워 보입니다.
j_random_hacker

9

Postgres에 대해 정말 좋아하는 것 중 하나는 열에서 지원되는 데이터 유형 중 일부입니다. 예를 들어 네트워크 주소배열 을 저장하기 위해 만들어진 열 유형이 있습니다. 이러한 열 유형에 해당하는 함수 ( Network Addresses / Arrays )를 사용하면 MySQL 또는 기타 데이터베이스 엔진의 코드를 통해 결과를 처리하여 수행해야하는 쿼리 내에서 복잡한 작업을 많이 수행 할 수 있습니다.


2
표준 유형이 적합하지 않은 경우 자신 만의 유형을 쉽게 만들 수 있습니다!
bortzmeyer 2009

8

배열은 일단 알게되면 정말 멋집니다. 페이지 간 하이퍼 링크를 저장하고 싶다고 가정 해 보겠습니다. 다음과 같은 테이블 생성에 대해 생각하는 것으로 시작할 수 있습니다.

CREATE TABLE hyper.links (
     tail INT4,
     head INT4
);

꼬리 열 을 인덱싱해야하는데 200,000,000 개의 링크 행 (위키피디아가 제공하는 것처럼)이 있다면 거대한 테이블과 거대한 인덱스가있을 것입니다.

그러나 PostgreSQL에서는 대신 다음 테이블 형식을 사용할 수 있습니다.

CREATE TABLE hyper.links (
     tail INT4,
     head INT4[],
     PRIMARY KEY(tail)
);

링크에 대한 모든 헤드를 얻으려면 다음과 같은 명령을 보낼 수 있습니다 (8.4부터 unnest ()가 표준입니다).

SELECT unnest(head) FROM hyper.links WHERE tail = $1;

이 쿼리는 첫 번째 옵션과 비교할 때 놀랍도록 빠릅니다 (unnest ()는 빠르며 인덱스는 훨씬 작습니다). 또한 테이블과 인덱스는 특히 배열이 너무 길어서 토스트 테이블로 압축 될 때 RAM 메모리와 HD 공간을 훨씬 적게 차지합니다. 배열은 정말 강력합니다.

참고 : unnest ()는 배열에서 행을 생성하지만 array_agg ()는 행을 배열로 집계합니다.


6

구체화 된 뷰는 설정하기가 매우 쉽습니다.

CREATE VIEW my_view AS SELECT id, AVG(my_col) FROM my_table GROUP BY id;
CREATE TABLE my_matview AS SELECT * FROM my_view;

그러면 my_view의 열과 값이있는 새 테이블 my_matview가 생성됩니다. 그런 다음 데이터를 최신 상태로 유지하거나 게으른 경우 트리거 또는 크론 스크립트를 설정할 수 있습니다.

TRUNCATE my_matview;
INSERT INTO my_matview SELECT * FROM my_view;

6
  • Inheritance..infact 다중 상속 (많은 웹 프레임 워크에서 postgres로 작업 할 때 구현하는 일대일 관계 상속이 아닌 부모-자식 "상속"에서와 같음).

  • PostGIS (공간 확장), 포괄적 인 지오메트리 기능 세트를 제공하고 즉시 저장을 조정하는 멋진 애드온입니다. 많은 오픈 소스 지리 라이브러리 (예 : OpenLayers, MapServer, Mapnik 등)에서 널리 사용되며 확실히 MySQL의 공간 확장보다 훨씬 좋습니다.

  • C, Python, Perl 등과 같은 다른 언어로 프로 시저를 작성합니다 (db 관리자가 아닌 개발자라면 코딩을 쉽게 할 수 있습니다).

    또한 모든 프로시 저는 외부에 (모듈로) 저장 될 수 있으며 지정된 인수에 의해 런타임에 호출되거나 가져올 수 있습니다. 이렇게하면 코드를 소스 제어하고 코드를 쉽게 디버깅 할 수 있습니다.

  • 데이터베이스에 구현 된 모든 개체 (예 : 테이블, 제약 조건, 인덱스 등)에 대한 방대하고 포괄적 인 카탈로그.

    나는 항상 몇 가지 쿼리를 실행하고 모든 메타 정보 (예 : 제약 조건 이름 및 필드가 구현 된 필드, 인덱스 이름 등)를 얻는 것이 매우 유용하다는 것을 알게되었습니다.

    저에게는 새로운 데이터를로드하거나 큰 테이블에서 대규모 업데이트를 수행해야 할 때 (자동으로 트리거를 비활성화하고 인덱스를 삭제) 처리가 완료된 후 다시 쉽게 다시 만들어야 할 때 모든 것이 매우 편리해집니다. 누군가는 이러한 쿼리 중 소수를 작성하는 훌륭한 작업을 수행했습니다.

    http://www.alberton.info/postgresql_meta_info.html

  • 하나의 데이터베이스에 여러 스키마가 있고 데이터베이스에 많은 수의 테이블이있는 경우 사용할 수 있으며 스키마를 범주로 생각할 수 있습니다. 모든 테이블 (스키마에 관계없이)은 상위 db에있는 다른 모든 테이블과 함수에 액세스 할 수 있습니다.


+1 다중 상속이 이렇게 멀다는 것을 믿을 수 없습니다.
Adam Gent


4
select pg_size_pretty(200 * 1024)

이 시도 PostgreSQL 9.3잡은 오류
비벡 S.

@WingedPanther 당신의 오류는 무엇입니까? 여기서 9.3에도 오류가 있습니다 (2009 년에는 오류가 없음). 수정 사항은 정수를 큰 정수로 변환해야한다는 것입니다.pg_size_pretty((200 * 1024)::bigint)
Michael Buen

예 그게 문제입니다
비벡 S.

3

pgcrypto : 많은 프로그래밍 언어의 암호화 모듈이 제공하는 것보다 더 많은 암호화 기능을 데이터베이스에서 직접 액세스 할 수 있습니다. 그것은 암호화 자료를 Just Get Right를 믿을 수 없을 정도로 쉽게 만듭니다.


3

다음을 사용하여 데이터베이스를 복사 할 수 있습니다.

createdb -T old_db new_db

문서는 다음과 같이 말합니다.

이것은 (아직) 범용 "COPY DATABASE"기능이 아닙니다.

그러나 그것은 나를 위해 잘 작동하고

createdb new_db

pg_dump old_db | psql new_db


2

일회용 데이터 / 전역 변수를위한 메모리 스토리지

RAM에있는 테이블 스페이스와 해당 테이블 스페이스에 테이블 (9.1에서 로그되지 않을 수 있음)을 생성하여 세션간에 공유하려는 일회용 데이터 / 전역 변수를 저장할 수 있습니다.

http://magazine.redhat.com/2007/12/12/tip-from-an-rhce-memory-storage-on-postgresql/

자문 잠금

이것들은 매뉴얼의 모호한 영역에 문서화되어 있습니다.

http://www.postgresql.org/docs/9.0/interactive/functions-admin.html

여러 행 수준 잠금을 획득하는 것보다 때때로 더 빠르며 FOR UPDATE가 구현되지 않은 경우 (예 : 재귀 CTE 쿼리)를 해결하는 데 사용할 수 있습니다.


4
RAM에 테이블 스페이스를 생성하는 것은 매우 나쁜 생각입니다. 이렇게하지 마십시오. 전체 데이터베이스가 심각하고 복구 불가능한 손상의 위험이 있습니다. UNLOGGED테이블을 사용하십시오 .
Craig Ringer

2

이것은 덜 알려진 기능의 즐겨 찾기 목록입니다.

트랜잭션 DDL

거의 모든 SQL 문은 Postgres에서 트랜잭션입니다. 자동 커밋을 끄면 다음이 가능합니다.

drop table customer_orders;
rollback;
select *
from customer_orders;

범위 유형 및 제외 제약

필자가 아는 한 Postgres는 두 범위가 겹치는 지 확인하는 제약 조건을 만들 수있는 유일한 RDBMS입니다. 예를 들어 "유효 시작"및 "유효 종료"날짜가있는 제품 가격이 포함 된 테이블이 있습니다.

create table product_price
(
   price_id      serial        not null primary key,
   product_id    integer       not null references products,
   price         numeric(16,4) not null,
   valid_during  daterange not null
);

NoSQL 기능

hstore 확장은 데이터베이스의 일부가 "스키마가 없어야"할 때 사용할 수있는 유연하고 매우 빠른 키 / 값 저장소를 제공합니다. JSON은 스키마없는 방식으로 데이터를 저장하는 또 다른 옵션이며

insert into product_price 
  (product_id, price, valid_during)
values 
  (1, 100.0, '[2013-01-01,2014-01-01)'),
  (1,  90.0, '[2014-01-01,)');


-- querying is simply and can use an index on the valid_during column
select price
from product_price
where product_id = 42
  and valid_during @> date '2014-10-17';

700.000 행이있는 테이블에 대한 위의 실행 계획 :

Index Scan using check_price_range on public.product_price  (cost=0.29..3.29 rows=1 width=6) (actual time=0.605..0.728 rows=1 loops=1)
  Output: price
  Index Cond: ((product_price.valid_during @> '2014-10-17'::date) AND (product_price.product_id = 42))
  Buffers: shared hit=17
Total runtime: 0.772 ms

유효 범위가 겹치는 행을 삽입하지 않으려면 간단하고 효율적인 고유 제약 조건을 정의 할 수 있습니다.

alter table product_price
  add constraint check_price_range 
  exclude using gist (product_id with =, valid_during with &&)

무한대

먼 미래의 "실제"날짜를 요구하는 대신 Postgres는 날짜를 무한대로 비교할 수 있습니다. 예 : 날짜 범위를 사용하지 않는 경우 다음을 수행 할 수 있습니다.

insert into product_price 
  (product_id, price, valid_from, valid_until)
values 
  (1,  90.0, date '2014-01-01', date 'infinity');

쓰기 가능한 공통 테이블 표현식

단일 명령문에서 삭제, 삽입 및 선택할 수 있습니다.

with old_orders as (
   delete from orders
   where order_date < current_date - interval '10' year
   returning *
), archived_rows as (
   insert into archived_orders 
   select * 
   from old_orders
   returning *
)
select *
from archived_rows;

위의 경우 10 년이 지난 모든 주문을 삭제하고 archived_orders테이블 로 이동 한 다음 이동 된 행을 표시합니다.


2

1.) 질의에 대한 추가 통지가 필요한 경우 중첩 된 주석을 사용할 수 있습니다.

SELECT /* my comments, that I would to see in PostgreSQL log */
       a, b, c
   FROM mytab;

2.) 데이터베이스의 모든 textvarchar필드에서 후행 공백을 제거 합니다.

do $$
declare
    selectrow record;
begin
for selectrow in
select 
       'UPDATE '||c.table_name||' SET '||c.COLUMN_NAME||'=TRIM('||c.COLUMN_NAME||')  WHERE '||c.COLUMN_NAME||' ILIKE ''% '' ' as script
from (
       select 
          table_name,COLUMN_NAME
       from 
          INFORMATION_SCHEMA.COLUMNS 
       where 
          table_name LIKE 'tbl%'  and (data_type='text' or data_type='character varying' )
     ) c
loop
execute selectrow.script;
end loop;
end;
$$;

3.) 중복 행을 매우 효과적으로 제거하기 위해 창 기능을 사용할 수 있습니다.

DELETE FROM tab 
  WHERE id IN (SELECT id 
                  FROM (SELECT row_number() OVER (PARTITION BY column_with_duplicate_values), id 
                           FROM tab) x 
                 WHERE x.row_number > 1);

일부 PostgreSQL의 최적화 된 버전 (ctid 포함) :

DELETE FROM tab 
  WHERE ctid = ANY(ARRAY(SELECT ctid 
                  FROM (SELECT row_number() OVER (PARTITION BY column_with_duplicate_values), ctid 
                           FROM tab) x 
                 WHERE x.row_number > 1));

4.) 서버의 상태를 식별해야 할 때 함수를 사용할 수 있습니다.

SELECT pg_is_in_recovery();

5.) 함수의 DDL 명령을 가져옵니다.

select pg_get_functiondef((select oid from pg_proc where proname = 'f1'));

6.) PostgreSQL에서 안전하게 열 데이터 유형 변경

create table test(id varchar );
insert into test values('1');
insert into test values('11');
insert into test values('12');

select * from test
--Result--
id
character varying
--------------------------
1
11
12

위의 표에서 내가 데이터 유형을 사용한 것을 볼 수 있습니다
. 'id' 열에 '가변 문자'입니다 . 그러나 나는 항상 정수를 id로 제공하기 때문에 실수였습니다. 따라서 여기서 varchar를 사용하는 것은 나쁜 습관입니다. 따라서 열 유형을 정수로 변경해 보겠습니다.

ALTER TABLE test ALTER COLUMN id TYPE integer;

그러나 다음을 반환합니다.

오류 : "id"열은 정수 SQL 상태 유형으로 자동 캐스트 할 수 없습니다. 42804 힌트 : 변환을 수행하려면 USING 표현식을 지정하십시오.

즉, 데이터가 이미 열에 있기 때문에 단순히 데이터 유형을 변경할 수 없습니다. 데이터가 'character varying'유형이므로 postgres는 정수만 입력했지만 정수로 기대할 수 없습니다. 이제 postgres가 제안했듯이 'USING'표현식을 사용하여 데이터를 정수로 변환 할 수 있습니다.

ALTER TABLE test ALTER COLUMN id  TYPE integer USING (id ::integer);

효과가있다.

7.) 데이터베이스에 누가 연결되어 있는지 알기
이것은 다소간 모니터링 명령입니다. 어떤 사용자가 자신의 IP 및 포트를 포함하여 어떤 데이터베이스에 연결되었는지 확인하려면 다음 SQL을 사용하십시오.

SELECT datname,usename,client_addr,client_port FROM pg_stat_activity ;

8.) 서버를 다시 시작하지 않고 PostgreSQL 구성 파일 다시로드

PostgreSQL 구성 매개 변수는 postgresql.conf 및 pg_hba.conf와 같은 특수 파일에 있습니다. 종종 이러한 매개 변수를 변경해야 할 수 있습니다. 그러나 일부 매개 변수를 적용하려면 종종 구성 파일을 다시로드해야합니다. 물론 서버를 다시 시작하면됩니다. 그러나 프로덕션 환경에서는 일부 매개 변수를 설정하기 위해 수천 명이 사용하고있는 데이터베이스를 다시 시작하는 것이 바람직하지 않습니다. 이러한 상황에서 다음 기능을 사용하여 서버를 다시 시작하지 않고 구성 파일을 다시로드 할 수 있습니다.

select pg_reload_conf();

이것은 모든 매개 변수에 대해 작동하지 않습니다. 일부 매개 변수 변경 사항을 적용하려면 서버를 완전히 다시 시작해야합니다.

9.) 현재 데이터베이스 클러스터의 데이터 디렉토리 경로 얻기

시스템에서 PostgreSQL의 여러 인스턴스 (클러스터)가 일반적으로 서로 다른 포트 등에서 설정 될 수 있습니다. 이러한 경우 어떤 인스턴스가 어떤 디렉토리 (물리적 저장소 디렉토리)를 사용하는지 찾는 것이 바쁜 작업입니다. 이러한 경우 관심있는 클러스터의 모든 데이터베이스에서 다음 명령을 사용하여 디렉터리 경로를 가져올 수 있습니다.

SHOW data_directory;

동일한 기능을 사용하여 클러스터의 데이터 디렉토리를 변경할 수 있지만 서버를 다시 시작해야합니다.

SET data_directory to new_directory_path;

10.) CHAR가 DATE인지 아닌지 찾기

create or replace function is_date(s varchar) returns boolean as $$
begin
  perform s::date;
  return true;
exception when others then
  return false;
end;
$$ language plpgsql;

사용법 : 다음은 True 를 반환합니다.

select is_date('12-12-2014')
select is_date('12/12/2014')
select is_date('20141212')
select is_date('2014.12.12')
select is_date('2014,12,12')

11.) PostgreSQL에서 소유자 변경

REASSIGN OWNED BY sa  TO postgres;

12.) PGADMIN PLPGSQL 디버거

여기에 잘 설명되어 있습니다.


+1 2 , 3 , 6 , 9

0

mysql이 할 수있는 것보다 오래된 데이터베이스의 이름을 바꾸는 것이 편리합니다. 다음 명령을 사용하십시오.

ALTER DATABASE name RENAME TO new_name
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.