저장 프로 시저 성능 (이전 기사) 과 유용성 이 의심스러운 MySQL 배경에서 회사의 새 제품에 대한 PostgreSQL을 평가하고 있습니다.
내가하고 싶은 일 중 하나는 일부 응용 프로그램 논리 를 저장 프로 시저로 옮기는 것이므로 PostgreSQL (9.0)의 함수 사용에 대한 DO 및 DO N'T (모범 사례), 특히 성능 함정과 관련하여 요청합니다.
저장 프로 시저 성능 (이전 기사) 과 유용성 이 의심스러운 MySQL 배경에서 회사의 새 제품에 대한 PostgreSQL을 평가하고 있습니다.
내가하고 싶은 일 중 하나는 일부 응용 프로그램 논리 를 저장 프로 시저로 옮기는 것이므로 PostgreSQL (9.0)의 함수 사용에 대한 DO 및 DO N'T (모범 사례), 특히 성능 함정과 관련하여 요청합니다.
답변:
엄밀히 말하면, "저장 프로 시저"라는 용어 는 Postgres 11에 도입 된 Postgres의 SQL 프로 시저 를 가리 킵니다 .
거의 동일하지는 않지만 기능 이 있으며 처음부터 기능이 있습니다.
기능 과는 LANGUAGE sql
기본적으로 (항상 내에서 실행하기 때문에 원자, 일반 SQL의 함수 래퍼 명령을 단지 배치 파일입니다 단일 거래) 받아들이는 매개 변수를 설정합니다. SQL 함수의 모든 명령문은 한 번 에 계획 되며 이는 하나의 명령문을 차례로 실행하는 것과 미묘하게 다르며 잠금이 수행되는 순서에 영향을 줄 수 있습니다.
무엇보다 가장 성숙한 언어는 PL / pgSQL ( LANGUAGE plpgsql
)입니다. 잘 작동하고 지난 10 년 동안 모든 릴리스에서 개선되었지만 SQL 명령의 풀 역할을하는 것이 가장 좋습니다. SQL 계산 이외의 많은 계산을위한 것은 아닙니다.
PL / pgSQL 함수는 준비된 명령문 과 같은 쿼리를 실행합니다 . 캐시 된 쿼리 계획을 다시 사용하면 일부 계획 오버 헤드가 줄어들고 동등한 SQL 문보다 약간 빠르므로 상황에 따라 눈에 띄는 영향을 줄 수 있습니다. 이 관련 질문과 같은 부작용이있을 수도 있습니다.
이것은 매뉴얼에서 논의 된 것처럼 준비된 진술의 장단점을 가지고 있습니다 . 불규칙한 데이터 분배 및 다양한 매개 변수가있는 테이블에 대한 쿼리의 경우 지정된 매개 변수에 대해 최적화 된 실행 계획의 이득이 재 계획 비용을 능가 할 때 동적 SQL 이 EXECUTE
더 잘 수행 될 수 있습니다.
Postgres 9.2 일반 실행 계획은 여전히 세션에 대해 캐시되지만 manual을 인용하기 때문에 :
이것은 매개 변수없이 준비된 명령문에 대해 즉시 발생합니다. 그렇지 않으면 예상 비용 평균 (계획 오버 헤드 포함)이 일반 계획 비용 추정치보다 비싼 계획을 생성하는 다섯 번 이상의 실행 후에 만 발생합니다.
우리는 (ab) 사용하지 않고 대부분의 시간 동안 ( 두 개의 추가 오버 헤드가 거의 없음) 두 세계를 최대한 활용합니다EXECUTE
. PostgreSQL Wiki PostgreSQL 9.2의 새로운 기능에 대한 세부 정보 .
Postgres 12에는 일반 또는 사용자 정의 계획을 강제 적용하기 위한 추가 서버 변수plan_cache_mode
가 도입되었습니다 . 특별한 경우에는 조심해서 사용하십시오.
응용 프로그램에서 데이터베이스 서버로의 추가 왕복 을 막는 서버 측 기능으로 큰 성과 를 거둘 수 있습니다 . 서버가 한 번에 최대한 많이 실행되도록하고 잘 정의 된 결과 만 반환하도록하십시오.
복잡한 함수, 특히 테이블 함수 ( RETURNING SETOF record
또는 TABLE (...)
)의 중첩 을 피하십시오 . 함수는 쿼리 플래너에 대한 최적화 장벽으로 사용되는 블랙 박스입니다. 외부 쿼리의 컨텍스트가 아닌 개별적으로 최적화되어 계획이 단순 해지지 만 완벽한 계획은 아닙니다. 또한 함수의 비용 및 결과 크기를 확실하게 예측할 수 없습니다.
이 규칙 의 예외 는 간단한 SQL 함수 ( LANGUAGE sql
)이며 일부 전제 조건이 충족되는 경우 "인라인" 될 수 있습니다 . 이 프레젠테이션에서 Neil Conway (고급 항목) 의 쿼리 플래너 작동 방식에 대해 자세히 알아보십시오 .
PostgreSQL에서 함수는 항상 단일 트랜잭션 내에서 자동으로 실행 됩니다 . 모든 것이 성공하거나 아무것도 아닙니다. 예외가 발생하면 모든 것이 롤백됩니다. 그러나 오류 처리가 있습니다 ...
그렇기 때문에 함수가 정확히 "저장 프로 시저" 가 아닌 이유도 있습니다 (비록 잘못 사용되는 용어가 사용 되더라도). 일부 명령은 좋아하는 , 또는 그들이 기능에서 허용되지 않도록, 트랜잭션 블록 내에서 실행할 수 없습니다. (Postgres 11부터는 SQL 프로 시저에서도 마찬가지입니다. 나중에 추가 될 수 있습니다.)VACUUM
CREATE INDEX CONCURRENTLY
CREATE DATABASE
몇 년 동안 수천 개의 plpgsql 함수를 작성했습니다.
일부는 :
postgresql에서 사용자 정의 함수 (UDF)를 사용하여 매우 흥미로운 작업을 수행 할 수 있습니다. 예를 들어, 사용할 수있는 수십 가지 언어가 있습니다. 내장 된 pl / sql 및 pl / pgsql은 성능과 안정성이 뛰어나고 샌드 박스 방법을 사용하여 사용자가 너무 위험한 일을하지 않도록합니다. C로 작성된 UDF는 데이터베이스 자체와 동일한 컨텍스트에서 실행되므로 최고의 성능과 성능을 제공합니다. 그러나 작은 실수만으로도 백엔드 충돌 또는 데이터 손상과 같은 큰 문제가 발생할 수 있기 때문에 불을 가지고 노는 것과 같습니다. pl / R, pl / ruby, pl / perl 등과 같은 custom pl 언어는 데이터베이스와 앱 계층을 동일한 언어로 작성할 수있는 기능을 제공합니다. 이것은 UDF를 작성하기 위해 perl 프로그래머에게 java 또는 pl / pgsql 등을 가르 칠 필요가 없기 때문에 편리합니다.
마지막으로 pl / proxy 언어가 있습니다. 이 UDF 언어를 사용하면 확장 목적으로 수십 개 이상의 백엔드 postgresql 서버에서 애플리케이션을 실행할 수 있습니다. Skype의 좋은 사람들에 의해 개발되었으며 기본적으로 가난한 사람의 수평 확장 솔루션을 허용합니다. 놀랍도록 쓰기도 쉽습니다.
이제 성능 문제와 관련하여 이것은 회색 영역입니다. 한 사람을위한 앱을 작성하고 있습니까? 아니면 1,000? 또는 10,000,000? 앱을 빌드하고 UDF를 사용하는 방법은 확장하려는 방법에 따라 다릅니다. 수천 명의 사용자를 대상으로 작성하는 경우 가장 중요한 것은 가능한 한 DB의 부하를 줄이는 것입니다. 데이터베이스로 이동하고 다시 데이터베이스로 이동하는 데이터의 양을 줄이는 UDF는 IO로드를 줄이는 데 도움이됩니다. 그러나 CPU로드가 증가하기 시작하면 문제가 될 수 있습니다. 일반적으로 말하자면 IO로드를 줄이는 것이 최우선 순위이며 CPU에 과부하가 걸리지 않도록 UDF가 효율적이어야합니다.