65.2. GiST 토토 핫#

65.2.1. 소개#

지스트일반화된 검색 트리를 나타냅니다. 이는 임의의 색인 구성표를 구현하는 기본 템플릿 역할을 하는 균형 잡힌 트리 구조 액세스 방법입니다. B-트리, R-트리 및 기타 여러 색인 구성표를 다음에서 구현할 수 있습니다.지스트.

다음의 장점 중 하나지스트데이터베이스 전문가가 아닌 데이터 유형 분야의 전문가가 적절한 액세스 방법을 사용하여 사용자 정의 데이터 유형을 개발할 수 있다는 것입니다.

여기에 있는 일부 정보는 버클리 캘리포니아 대학의 GiST 색인 프로젝트에서 파생되었습니다.웹사이트그리고 Marcel Kornacker의 논문,차세대 데이터베이스 시스템을 위한 액세스 방법.지스트구현포스트그레SQL주로 Teodor Sigaev와 Oleg Bartunov가 관리하며 이들에 대한 자세한 정보가 있습니다.웹사이트.

65.2.2. 내장 연산자 클래스#

핵심포스트그레SQL배포에는 다음이 포함됩니다지스트다음에 표시된 연산자 클래스표 65.1. (다음에 설명된 일부 선택적 모듈PostgreSQL : 문서 : 17 : 부록 F. 추가 제공된 모듈 및 스포츠 토토 베트맨추가 제공지스트연산자 클래스.)

표 65.1. 내장GiST연산자 클래스

이름 인덱싱 가능한 연산자 주문 연산자
box_ops << (상자, 상자) <- (상자, 점)
&< (상자, 상자)
&&(상자, 상자)
& (상자, 상자)
(상자, 상자)
~= (상자, 상자)
@ (상자, 상자)
<@ (상자, 상자)
&<| (상자, 상자)
<<| (상자, 상자)
| (상자, 상자)
|& (상자, 상자)
circle_ops << (원, 원) <- (원, 점)
&<(원, 원)
& (원, 원)
(원, 원)
<@ (원, 원)
@ (원, 원)
~= (원, 원)
&&(원, 원)
| (원, 원)
<<| (원, 원)
&<| (원, 원)
|& (원, 원)
inet_ops << (inet, inet)
<<= (inet, inet)
(inet, inet)
= (inet, inet)
= (inet, inet)
< (inet, inet)
<(inet, inet)
<= (inet, inet)
(inet, inet)
= (inet, inet)
&&(inet, inet)
multirange_ops = (다중 범위, 다중 범위)
&&(다중 범위, 다중 범위)
&&(다중 범위, 범위 모두)
@ (모든 다중 범위, 모든 요소)
@ (다중 범위, 다중 범위)
@ (모든 다중 범위, 모든 범위)
<@ (anymultirange, anymultirange)
<@ (anymultirange, anyrange)
<< (다중 범위, 다중 범위)
<<(다중 범위, 범위 모두)
(다중 범위, 다중 범위)
(다중 범위, 범위 모두)
&< (다중 범위, 다중 범위)
&< (모든 다중 범위, 모든 범위)
& (다중 범위, 다중 범위)
& (모든 다중 범위, 모든 범위)
-|- (다중 범위, 다중 범위)
-|- (다중 범위, 범위 모두)
point_ops | (점, 점) <- (점, 점)
<< (점, 점)
(점, 점)
<<| (포인트, 포인트)
~= (점, 점)
<@ (점, 상자)
<@(점, 다각형)
<@ (점, 원)
poly_ops << (다각형, 다각형) <- (다각형, 점)
&<(다각형, 다각형)
& (다각형, 다각형)
(다각형, 다각형)
<@(다각형, 다각형)
@ (다각형, 다각형)
~= (다각형, 다각형)
&&(다각형, 다각형)
<<| (다각형, 다각형)
&<| (다각형, 다각형)
|& (다각형, 다각형)
| (다각형, 다각형)
range_ops = (모든 범위, 모든 범위)
&&(모든 범위, 모든 범위)
&&(모든 범위, 모든 다중 범위)
@ (모든 범위, 모든 요소)
@ (모든 범위, 모든 범위)
@ (모든 범위, 모든 다중 범위)
<@ (anyrange, anyrange)
<@ (모든 범위, 모든 다중 범위)
<< (모든 범위, 모든 범위)
<<(모든 범위, 모든 다중 범위)
(모든 범위, 모든 범위)
(모든 범위, 모든 다중 범위)
&<(모든 범위, 모든 범위)
&<(모든 범위, 모든 다중 범위)
& (모든 범위, 모든 범위)
& (모든 범위, 모든 다중 범위)
-|- (모든 범위, 모든 범위)
-|- (모든 범위, 모든 다중 범위)
tsquery_ops <@ (tsquery, tsquery)
@ (tsquery, tsquery)
tsVector_ops @@(ts벡터, tsquery)

역사적인 이유로,inet_ops연산자 클래스는 유형의 기본 클래스가 아닙니다inet그리고cidr. 그것을 사용하려면, 클래스 이름을 언급하십시오.색인 생성, 예를 들어

GIST(my_inet_column inet_ops)를 사용하여 my_table에 인덱스 생성;

65.2.3. 확장성#

전통적으로 새로운 색인 액세스 방법을 구현하는 것은 많은 어려운 작업을 의미했습니다. 잠금 관리자 및 미리 쓰기 로그와 같은 데이터베이스의 내부 작동을 이해하는 것이 필요했습니다.GiST인터페이스는 추상화 수준이 높기 때문에 액세스 방법 구현자가 액세스되는 데이터 유형의 의미 체계만 구현하면 됩니다.GiST계층 자체가 동시성, 로깅 및 트리 구조 검색을 관리합니다.

이 확장성은 처리할 수 있는 데이터 측면에서 다른 표준 검색 트리의 확장성과 혼동되어서는 안 됩니다. 예를 들어,PostgreSQL확장 가능한 B-트리 및 해시 인덱스를 지원합니다. 이는 다음을 사용할 수 있음을 의미합니다.PostgreSQL원하는 데이터 유형에 대해 B-트리 또는 해시를 구축합니다. 그러나 B-트리는 범위 술어()만 지원합니다.<, =, ), 해시 인덱스는 동등 쿼리만 지원합니다.

그러므로 예를 들어 이미지 컬렉션을 색인화한다면PostgreSQLB-트리, 다음과 같은 쿼리만 실행할 수 있습니다.imagex는 imagey와 같습니다, imagex는 imagey보다 작습니다그리고imagex가 imagey보다 큼. 어떻게 정의하느냐에 따라같음, 미만그리고보다 큼이런 맥락에서 이는 유용할 수 있습니다. 그러나 a를 사용하면GiST기반 색인을 사용하면 도메인별 질문을 하는 방법을 만들 수 있을 것입니다.말의 모든 이미지 찾기또는과다 노출된 이미지 모두 찾기.

을 얻기 위해 필요한 모든 것GiST액세스 방법 실행은 트리의 키 동작을 정의하는 여러 사용자 정의 방법을 구현하는 것입니다. 물론 이러한 방법은 멋진 쿼리를 지원하기 위해 매우 화려해야 하지만 모든 표준 쿼리(B-트리, R-트리 등)의 경우 상대적으로 간단합니다. 한마디로,GiST확장성과 일반성, 코드 재사용 및 깔끔한 인터페이스를 결합합니다.

색인 연산자 클래스에는 5가지 메소드가 있습니다.GiST반드시 제공해야 하며 7개는 선택사항입니다. 인덱스의 정확성은 다음의 적절한 구현을 통해 보장됩니다.같은, 일관적인그리고연합방법, 인덱스의 효율성(크기 및 속도)은 다음에 따라 달라집니다.페널티그리고picksplit메소드. 두 가지 선택적 방법은 다음과 같습니다.압축그리고압축해제: 토토 핫가 토토 핫하는 데이터와 다른 유형의 내부 트리 데이터를 가질 수 있도록 허용합니다. 리프는 토토 핫 데이터 유형이어야 하고 다른 트리 노드는 모든 C 구조체일 수 있습니다(그러나 여전히 따라야 합니다포스트그레SQL여기의 데이터 유형 규칙에 대한 내용을 참조하세요.발레나가변 크기 데이터의 경우). 트리의 내부 데이터 유형이 SQL 수준에 존재하는 경우,저장옵션연산자 클래스 생성명령을 사용할 수 있습니다. 선택적인 여덟 번째 방법은 다음과 같습니다.거리, 연산자 클래스가 정렬된 스캔(최근접 이웃 검색)을 지원하려는 경우에 필요합니다. 선택적 아홉 번째 방법가져오기연산자 클래스가 인덱스 전용 스캔을 지원하려는 경우 필요합니다. 단,압축메서드가 생략되었습니다. 선택적 열 번째 방법옵션연산자 클래스에 사용자 지정 매개변수가 있는 경우 필요합니다. 선택적 열한 번째 방법정렬지원빌드 속도를 높이는 데 사용됩니다.GiST색인. 선택적인 열두 번째 방법스트라트넘비교 유형을 번역하는 데 사용됩니다(fromsrc/include/nodes/primnodes.h)를 연산자 클래스에서 사용하는 전략 번호로 변환합니다. 이를 통해 핵심 코드는 시간 제약 조건 인덱스에 대한 연산자를 찾을 수 있습니다.

일관됨

색인 항목이 제공됨p및 쿼리 값q, 이 함수는 색인 항목이 다음과 같은지 여부를 결정합니다.일관됨질의로; 즉, 술어가 가능할까요indexed_column indexable_operator q색인 항목으로 표시되는 모든 행에 대해 true입니까? 리프 인덱스 항목의 경우 이는 인덱스 가능 조건을 테스트하는 것과 동일하며 내부 트리 노드의 경우 트리 노드로 표시되는 인덱스의 하위 트리를 스캔해야 하는지 여부를 결정합니다. 결과가 다음과 같을 때, 아다시 확인플래그도 반환되어야 합니다. 이는 술어가 확실히 참인지, 아니면 가능하다면 참인지를 나타냅니다. 만일재확인 = 거짓그러면 색인은 술어 조건을 정확하게 테스트한 반면 if다시 확인 = 행은 단지 후보 일치 항목입니다. 이 경우 시스템은 자동으로 다음을 평가합니다.indexable_operator실제 행 값과 비교하여 실제로 일치하는지 확인합니다. 이 규칙은 다음을 허용합니다.GiST무손실 및 손실 인덱스 구조를 모두 지원합니다.

SQL함수 선언은 다음과 같아야 합니다:

함수 생성 또는 교체 my_condependent(internal, data_type, smallint, oid, Internal)
반환 부울
AS 'MODULE_PATHNAME'
언어 C 엄격;

그리고 C 모듈의 일치 코드는 다음 뼈대를 따를 수 있습니다:

PG_FUNCTION_INFO_V1(my_condependent);

데이텀
내_일관성(PG_FUNCTION_ARGS)

    GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
    data_type *query = PG_GETARG_DATA_TYPE_P(1);
    StrategyNumber 전략 = (StrategyNumber) PG_GETARG_UINT16(2);
    /* Oid 하위 유형 = PG_GETARG_OID(3); */
    bool *재확인 = (bool *) PG_GETARG_POINTER(4);
    data_type *key = DatumGetDataType(entry-key);
    부울 복구;

    /*
     * 전략, 키 및 쿼리의 함수로 반환 값을 결정합니다.
     *
     * 인덱스 트리에서 호출된 위치를 확인하려면 GIST_LEAF(entry)를 사용하세요.
     * 예를 들어 = 연산자를 지원할 때 유용합니다(예:
     * 리프 노드가 아닌 노드에서 비어 있지 않은 Union()과 리프에서 동일성을 확인합니다.
     * 노드).
     */

    *재확인 = 사실;        /* 또는 검사가 정확하면 false */

    PG_RETURN_BOOL(복귀);

여기,은 색인의 요소이고질의색인에서 조회되는 값입니다.전략번호매개변수는 연산자 클래스 중 어떤 연산자가 적용되고 있는지 나타냅니다. 이는의 연산자 번호 중 하나와 일치합니다.연산자 클래스 생성명령.

클래스에 포함된 연산자에 따라 다음의 데이터 유형질의연산자 오른쪽에 있는 모든 유형이 왼쪽에 나타나는 색인 데이터 유형과 다를 수 있으므로 연산자에 따라 달라질 수 있습니다. (위 코드 뼈대에서는 한 가지 유형만 가능하다고 가정합니다. 그렇지 않은 경우에는질의인수 값은 연산자에 따라 달라져야 합니다.) SQL 선언은일관적인함수는 opclass의 색인 데이터 유형을 사용합니다.질의인수(실제 유형은 연산자에 따라 다를 수 있음).

연합

이 방법은 트리의 정보를 통합합니다. 일련의 항목이 주어지면 이 함수는 주어진 모든 항목을 나타내는 새로운 색인 항목을 생성합니다.

SQL함수 선언은 다음과 같아야 합니다:

함수 생성 또는 교체 my_union(내부, 내부)
반환 Storage_type
AS 'MODULE_PATHNAME'
언어 C 엄격;

그리고 C 모듈의 일치 코드는 다음 뼈대를 따를 수 있습니다:

PG_FUNCTION_INFO_V1(my_union);

데이텀
my_union(PG_FUNCTION_ARGS)

    GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
    GISTENTRY *ent = Entryvec-벡터;
    데이터 유형 *아웃,
               *tmp,
               *오래된;
    정수 숫자 범위,
                나는 = 0;

    숫자 범위 = 항목vec-n;
    tmp = DatumGetDataType(ent[0].key);
    아웃 = tmp;

    if (숫자 범위 == 1)

        출력 = data_type_deep_copy(tmp);

        PG_RETURN_DATA_TYPE_P(아웃);

    for (i = 1; i < 숫자 범위; i++)

        낡은 = 아웃;
        tmp = DatumGetDataType(ent[i].key);
        out = my_union_implementation(out, tmp);

    PG_RETURN_DATA_TYPE_P(아웃);

보시다시피, 이 뼈대에서 우리는 다음과 같은 데이터 유형을 다루고 있습니다.합집합(X, Y, Z) = 합집합(합집합(X, Y), Z). 여기에 적절한 통합 알고리즘을 구현하면 그렇지 않은 경우에도 데이터 유형을 지원하는 것이 충분히 쉽습니다.GiST지원 방법.

의 결과연합함수는 무엇이든 인덱스 저장 유형의 값이어야 합니다(인덱싱된 열의 유형과 다를 수도 있고 다를 수도 있음).연합함수는 새로 포인터를 반환해야 합니다팔록()ed 메모리. 유형 변경이 없더라도 입력 값을 그대로 반환할 수는 없습니다.

As shown above, the연합함수 첫 번째내부인수는 실제로는GistEntryVector포인터. 두 번째 인수는 무시할 수 있는 정수 변수에 대한 포인터입니다. (이전에는 다음이 필요했습니다.연합함수는 결과 값의 크기를 해당 변수에 저장하지만 더 이상 필요하지 않습니다.)

압축

데이터 항목을 인덱스 페이지의 물리적 저장에 적합한 형식으로 변환합니다. 만약압축메소드가 생략되면 데이터 항목이 수정 없이 색인에 저장됩니다.

SQL함수 선언은 다음과 같아야 합니다:

함수 생성 또는 교체 my_compress(내부)
내부 반환
AS 'MODULE_PATHNAME'
언어 C 엄격;

그리고 C 모듈의 일치 코드는 다음 뼈대를 따를 수 있습니다:

PG_FUNCTION_INFO_V1(my_compress);

데이텀
my_compress(PG_FUNCTION_ARGS)

    GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
    GISTENTRY *재발;

    if (엔트리-리프키)

        /* 항목-키를 압축된 버전으로 교체 */
        pressed_data_type *compressed_data = palloc(sizeof(compressed_data_type));

        /* 항목-키의 *compressed_data 채우기 ... */

        retval = palloc(sizeof(GISTENTRY));
        gistentryinit(*retval, PointerGetDatum(compressed_data),
                      항목-상대, 항목-페이지, 항목-오프셋, FALSE);

    그렇지 않으면

        /* 일반적으로 리프가 아닌 항목에는 아무 것도 할 필요가 없습니다 */
        retval = 항목;

    PG_RETURN_POINTER(복귀);

당신은 적응해야 합니다압축_데이터_유형물론 리프 노드를 압축하기 위해 변환하려는 특정 유형으로 변환합니다.

압축해제

데이터 항목의 저장된 표현을 연산자 클래스의 다른 GiST 메소드로 조작할 수 있는 형식으로 변환합니다. 만약압축해제메서드가 생략된 경우 다른 GiST 메소드가 저장된 데이터 형식에서 직접 작동할 수 있다고 가정합니다. (압축해제반드시 반대는 아닙니다압축방법; 특히 만약에압축손실이 있으면 불가능합니다.압축해제원본 데이터를 정확하게 재구성합니다.압축해제반드시 다음과 동일하지는 않습니다.가져오기, 다른 GiST 방법에서는 데이터의 전체 재구성이 필요하지 않을 수 있기 때문입니다.)

SQL함수 선언은 다음과 같아야 합니다:

함수 생성 또는 교체 my_decompress(내부)
내부 반환
AS 'MODULE_PATHNAME'
언어 C 엄격;

그리고 C 모듈의 일치 코드는 다음 뼈대를 따를 수 있습니다:

PG_FUNCTION_INFO_V1(my_decompress);

데이텀
my_decompress(PG_FUNCTION_ARGS)

    PG_RETURN_POINTER(PG_GETARG_POINTER(0));

위의 뼈대는 감압이 필요하지 않은 경우에 적합합니다. (물론, 메서드를 모두 생략하는 것이 훨씬 더 쉬우므로 이러한 경우에 권장됩니다.)

벌칙

다음을 나타내는 값을 반환합니다.비용트리의 특정 가지에 새 항목을 삽입하는 것입니다. 항목은 최소 경로에 삽입됩니다.페널티나무에. 반환된 값페널티음수가 아니어야 합니다. 음수 값이 반환되면 0으로 처리됩니다.

SQL함수 선언은 다음과 같아야 합니다:

함수 생성 또는 교체 my_penalty(내부, 내부, 내부)
내부 반환
AS 'MODULE_PATHNAME'
언어 C 엄격;  -- 어떤 경우에는 페널티 함수가 엄격할 필요가 없습니다.

그리고 C 모듈의 일치 코드는 다음 뼈대를 따를 수 있습니다:

PG_FUNCTION_INFO_V1(my_penalty);

데이텀
my_penalty(PG_FUNCTION_ARGS)

    GISTENTRY *오리젠트리 = (GISTENTRY *) PG_GETARG_POINTER(0);
    GISTENTRY *newentry = (GISTENTRY *) PG_GETARG_POINTER(1);
    float *페널티 = (float *) PG_GETARG_POINTER(2);
    data_type *orig = DatumGetDataType(origentry-key);
    data_type *new = DatumGetDataType(newentry-key);

    *penalty = my_penalty_implementation(orig, new);
    PG_RETURN_POINTER(페널티);

역사적인 이유로,페널티함수는 단지 a를 반환하지 않습니다플로트결과; 대신 세 번째 인수가 나타내는 위치에 값을 저장해야 합니다. 반환 값 자체는 무시되지만 해당 인수의 주소를 다시 전달하는 것이 일반적입니다.

페널티함수는 색인의 좋은 성능에 매우 중요합니다. 삽입 시 트리에서 새 항목을 추가할 위치를 선택할 때 따라야 할 분기를 결정하는 데 사용됩니다. 쿼리 시 토토 핫 균형이 높을수록 조회 속도가 빨라집니다.

picksplit

인덱스 페이지 분할이 필요할 때, 이 기능은 페이지의 어떤 항목이 이전 페이지에 남을 것인지, 어떤 항목이 새 페이지로 이동할 것인지를 결정합니다.

SQL함수 선언은 다음과 같아야 합니다:

함수 생성 또는 교체 my_picksplit(내부, 내부)
내부 반환
AS 'MODULE_PATHNAME'
언어 C 엄격;

그리고 C 모듈의 일치 코드는 다음 뼈대를 따를 수 있습니다:

PG_FUNCTION_INFO_V1(my_picksplit);

데이텀
my_picksplit(PG_FUNCTION_ARGS)

    GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
    GIST_SPLITVEC *v = (GIST_SPLITVEC *) PG_GETARG_POINTER(1);
    OffsetNumber maxoff = Entryvec-n - 1;
    GISTENTRY *ent = Entryvec-벡터;
    나는,
                n바이트;
    오프셋 번호 *왼쪽,
               *맞아요;
    data_type *tmp_union;
    data_type *unionL;
    data_type *unionR;
    GISTENTRY **raw_entryvec;

    maxoff = Entryvec-n - 1;
    nbytes = (maxoff + 1) * sizeof(OffsetNumber);

    v-spl_left = (OffsetNumber *) palloc(nbytes);
    왼쪽 = v-spl_left;
    v-spl_nleft = 0;

    v-spl_right = (OffsetNumber *) palloc(nbytes);
    오른쪽 = v-spl_right;
    v-spl_nright = 0;

    유니온L = NULL;
    유니온R = NULL;

    /* 원시 항목 벡터를 초기화합니다. */
    raw_entryvec = (GISTENTRY **) malloc(entryvec-n * sizeof(void *));
    for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
        raw_entryvec[i] = &(entryvec-벡터[i]);

    for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))

        int real_index = raw_entryvec[i] -entryvec-벡터;

        tmp_union = DatumGetDataType(entryvec-벡터[real_index].key);
        Assert(tmp_union != NULL);

        /*
         * 인덱스 항목을 넣을 위치를 선택하고 UnionL 및 UnionR을 업데이트합니다.
         * 따라서. 항목을 v-spl_left 또는
         * v-spl_right, 카운터에 주의하세요.
         */

        if (my_choice_is_left(unionL, 컬, UnionR, curr))

            if (unionL == NULL)
                UnionL = tmp_union;
            그렇지 않으면
                UnionL = my_union_implementation(unionL, tmp_union);

            *왼쪽 = real_index;
            ++왼쪽;
            ++(v-spl_nleft);

        그렇지 않으면

            /*
             * 오른쪽도 마찬가지
             */

    v-spl_ldatum = DataTypeGetDatum(unionL);
    v-spl_rdatum = DataTypeGetDatum(unionR);
    PG_RETURN_POINTER(v);

다음에 주목하세요.picksplit함수 결과는 전달된 값을 수정하여 전달됩니다.v구조. 반환 값 자체는 무시되지만 주소를 다시 전달하는 것이 일반적입니다.v.

좋아요페널티, 그picksplit함수는 색인의 좋은 성능에 매우 중요합니다. 적합한 디자인페널티그리고picksplit구현은 우수한 성능을 구현하는 데 어려움을 겪는 곳입니다.GiST거짓말을 색인화합니다.

같은

두 개의 색인 항목이 동일하면 참을 반환하고, 그렇지 않으면 거짓을 반환합니다. (안색인 항목은 인덱스 저장 유형의 값이며 반드시 원래 색인화된 열의 유형일 필요는 없습니다.)

SQL함수 선언은 다음과 같아야 합니다:

함수 생성 또는 교체 my_same(storage_type, Storage_type, 내부)
내부 반환
AS 'MODULE_PATHNAME'
언어 C 엄격;

그리고 C 모듈의 일치 코드는 다음 뼈대를 따를 수 있습니다:

PG_FUNCTION_INFO_V1(나의_동일);

데이텀
내_동일(PG_FUNCTION_ARGS)

    접두사_범위 *v1 = PG_GETARG_PREFIX_RANGE_P(0);
    prefix_range *v2 = PG_GETARG_PREFIX_RANGE_P(1);
    bool *result = (bool *) PG_GETARG_POINTER(2);

    *결과 = my_eq(v1, v2);
    PG_RETURN_POINTER(결과);

역사적인 이유로,같은함수는 단순히 부울 결과를 반환하지 않습니다. 대신 세 번째 인수가 나타내는 위치에 플래그를 저장해야 합니다. 반환 값 자체는 무시되지만 해당 인수의 주소를 다시 전달하는 것이 일반적입니다.

거리

색인 항목이 제공됨p및 쿼리 값q, 이 함수는 색인 항목의를 결정합니다.거리쿼리 값에서. 연산자 클래스에 순서 연산자가 포함된 경우 이 함수를 제공해야 합니다. 순서 연산자를 사용하는 쿼리는 가장 작은 인덱스 항목을 반환하여 구현됩니다.거리값을 먼저 지정하므로 결과는 연산자의 의미와 일치해야 합니다. 리프 인덱스 항목의 경우 결과는 인덱스 항목까지의 거리만 나타냅니다. 내부 트리 노드의 경우 결과는 모든 하위 항목이 가질 수 있는 최소 거리여야 합니다.

SQL함수 선언은 다음과 같아야 합니다:

함수 생성 또는 교체 my_distance(internal, data_type, smallint, oid, Internal)
반환 float8
AS 'MODULE_PATHNAME'
언어 C 엄격;

그리고 C 모듈의 일치 코드는 다음 뼈대를 따를 수 있습니다:

PG_FUNCTION_INFO_V1(내_거리);

데이텀
my_distance(PG_FUNCTION_ARGS)

    GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
    data_type *query = PG_GETARG_DATA_TYPE_P(1);
    StrategyNumber 전략 = (StrategyNumber) PG_GETARG_UINT16(2);
    /* Oid 하위 유형 = PG_GETARG_OID(3); */
    /* bool *재확인 = (bool *) PG_GETARG_POINTER(4); */
    data_type *key = DatumGetDataType(entry-key);
    이중 회수;

    /*
     * 전략, 키 및 쿼리의 함수로 반환 값을 결정합니다.
     */

    PG_RETURN_FLOAT8(복귀);

에 대한 인수거리함수는의 인수와 동일합니다.일관됨함수.

결과가 항목의 실제 거리보다 크지 않는 한 거리를 결정할 때 일부 근사치가 허용됩니다. 따라서 예를 들어 기하학적 응용에서는 일반적으로 경계 상자까지의 거리면 충분합니다. 내부 트리 노드의 경우 반환된 거리는 하위 노드까지의 거리보다 클 수 없습니다. 반환된 거리가 정확하지 않으면 함수를 설정해야 합니다.*다시 확인참입니다. (이것은 내부 트리 노드에는 필요하지 않습니다. 계산은 항상 부정확하다고 가정됩니다.) 이 경우 실행기는 힙에서 튜플을 가져온 후 정확한 거리를 계산하고 필요한 경우 튜플을 재정렬합니다.

거리 함수가 반환되는 경우*재확인 = true모든 리프 노드의 경우 원래 순서 연산자의 반환 유형은 다음과 같아야 합니다float8또는플로트4, 실행기가 거리 함수 결과와 다시 계산된 순서 연산자 결과를 모두 사용하여 정렬하므로 거리 함수의 결과 값은 원래 순서 연산자의 결과 값과 비교 가능해야 합니다. 그렇지 않으면 거리 함수의 결과 값은 유한할 수 있습니다.float8값, 결과 값의 상대적 순서가 순서 연산자가 반환한 순서와 일치하는 경우에 한합니다. (무한대와 마이너스 무한대는 null과 같은 경우를 처리하기 위해 내부적으로 사용되므로 권장하지 않습니다.거리함수는 다음 값을 반환합니다.)

가져오기

인덱스 전용 스캔을 위해 데이터 항목의 압축된 인덱스 표현을 원래 데이터 유형으로 변환합니다. 반환된 데이터는 원래 인덱싱된 값의 정확하고 손실 없는 복사본이어야 합니다.

SQL함수 선언은 다음과 같아야 합니다:

함수 생성 또는 교체 my_fetch(내부)
내부 반환
AS 'MODULE_PATHNAME'
언어 C 엄격;

인수는 a에 대한 포인터입니다.GISTENTRY구조체. 입장 시, 그것은필드에 압축된 형식의 NULL이 아닌 리프 데이터가 포함되어 있습니다. 반환 값은 또 다른 것입니다.GISTENTRY구조체, 누구의필드에는 압축되지 않은 원래 형식의 동일한 데이터가 포함되어 있습니다. opclass의 압축 함수가 리프 항목에 대해 아무 작업도 수행하지 않으면,가져오기메소드는 인수를 있는 그대로 반환할 수 있습니다. 또는 opclass에 압축 함수가 없는 경우,가져오기메서드는 반드시 작동하지 않으므로 생략할 수도 있습니다.

C 모듈의 일치 코드는 다음 뼈대를 따를 수 있습니다.

PG_FUNCTION_INFO_V1(my_fetch);

데이텀
my_fetch(PG_FUNCTION_ARGS)

    GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
    input_data_type *in = DatumGetPointer(entry-key);
    fetched_data_type *fetched_data;
    GISTENTRY *재발;

    retval = palloc(sizeof(GISTENTRY));
    fetched_data = palloc(sizeof(fetched_data_type));

    /*
     * 'fetched_data'를 원래 데이터 유형의 데이터로 변환합니다.
     */

    /* fetched_data에서 *retval을 채웁니다. */
    gistentryinit(*retval, PointerGetDatum(converted_datum),
                  항목-상대, 항목-페이지, 항목-오프셋, FALSE);

    PG_RETURN_POINTER(복귀);

압축 방법이 리프 항목에 대해 손실이 있는 경우 연산자 클래스는 인덱스 전용 스캔을 지원할 수 없으며 다음을 정의해서는 안 됩니다.가져오기함수.

옵션

연산자 클래스 동작을 제어하는 사용자 표시 매개변수 정의를 허용합니다.

SQL함수 선언은 다음과 같아야 합니다:

함수 생성 또는 교체 my_options(내부)
반품 무효
AS 'MODULE_PATHNAME'
언어 C 엄격;

함수는 a에 대한 포인터를 전달받습니다.local_reloptsstruct, 연산자 클래스별 옵션 세트로 채워져야 합니다. 옵션은를 사용하여 다른 지원 기능에서 액세스할 수 있습니다.PG_HAS_OPCLASS_OPTIONS()그리고PG_GET_OPCLASS_OPTIONS()매크로.

my_options()의 구현 예와 다른 지원 함수에서 사용하는 매개변수는 다음과 같습니다:

typedef enum MyEnumType

    MY_ENUM_ON,
    MY_ENUM_OFF,
    MY_ENUM_AUTO
 MyEnumType;

typedef 구조체

    int32 vl_len_;    /* varlena 헤더(직접 건드리지 마세요!) */
    int int_param;  /* 정수 매개변수 */
    이중 real_param; /* 실제 매개변수 */
    MyEnumType enum_param; /* 열거형 매개변수 */
    int str_param;  /* 문자열 매개변수 */
 MyOptionsStruct;

/* 열거형 값의 문자열 표현 */
정적 relopt_enum_elt_def myEnumValues[] =

    "on", MY_ENUM_ON,
    "끄기", MY_ENUM_OFF,
    "자동", MY_ENUM_AUTO,
    (const char *) NULL /* 목록 종결자 */
;

static char *str_param_default = "기본값";

/*
 * 샘플 유효성 검사기: 문자열이 8바이트보다 길지 않은지 확인합니다.
 */
정적 공백
verify_my_string_relopt(const char *값)

    if (strlen(값)  8)
        ereport(오류,
                (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                 errmsg("str_param은 최대 8바이트여야 합니다.")));

/*
 * 샘플 필러: 문자를 소문자로 전환합니다.
 */
정적 크기
fill_my_string_relopt(const char *값, void *ptr)

    char *tmp = str_tolower(value, strlen(value), DEFAULT_COLLATION_OID);
    int len = strlen(tmp);

    만약 (ptr)
        strcpy(ptr,tmp);

    pfree(tmp);
    len + 1을 반환합니다.

PG_FUNCTION_INFO_V1(my_options);

데이텀
내_옵션(PG_FUNCTION_ARGS)

    local_relopts *relopts = (local_relopts *) PG_GETARG_POINTER(0);

    init_local_reloptions(relopts, sizeof(MyOptionsStruct));
    add_local_int_reloption(relopts, "int_param", "정수 매개변수",
                            100, 0, 1000000,
                            offsetof(MyOptionsStruct, int_param));
    add_local_real_reloption(relopts, "real_param", "실제 매개변수",
                             1.0, 0.0, 1000000.0,
                             offsetof(MyOptionsStruct, real_param));
    add_local_enum_reloption(relopts, "enum_param", "enum 매개변수",
                             myEnumValues, MY_ENUM_ON,
                             "유효한 값은 \"on\", \"off\" 및 \"auto\"입니다.",
                             offsetof(MyOptionsStruct, enum_param));
    add_local_string_reloption(relopts, "str_param", "문자열 매개변수",
                               str_param_default,
                               &validate_my_string_relopt,
                               &fill_my_string_relopt,
                               offsetof(MyOptionsStruct, str_param));

    PG_RETURN_VOID();

PG_FUNCTION_INFO_V1(my_compress);

데이텀
my_compress(PG_FUNCTION_ARGS)

    int int_param = 100;
    더블 real_param = 1.0;
    MyEnumType enum_param = MY_ENUM_ON;
    char *str_param = str_param_default;

    /*
     * 일반적으로 opclass에 'options' 메서드가 포함되어 있으면 옵션은 항상
     * 지원 기능으로 전달됩니다.  그러나 'options' 메소드를 추가하면
     * 기존 opclass, 이전에 정의된 인덱스에는 옵션이 없으므로
     * 확인이 필요합니다.
     */
    if (PG_HAS_OPCLASS_OPTIONS())

        MyOptionsStruct *options = (MyOptionsStruct *) PG_GET_OPCLASS_OPTIONS();

        int_param = 옵션-int_param;
        real_param = 옵션-real_param;
        enum_param = 옵션-enum_param;
        str_param = GET_STRING_RELOPTION(옵션, str_param);

    /* 지원 함수의 나머지 구현 */

키의 표현 이후GiST유연하며 사용자가 지정한 매개변수에 따라 달라질 수 있습니다. 예를 들어 조표의 길이를 지정할 수 있습니다. 참조gtsVector_options()예를 들어.

정렬지원

지역성을 유지하는 방식으로 데이터를 정렬하는 비교기 함수를 반환합니다. 다음에서 사용됩니다.색인 생성그리고REINDEX명령. 생성된 인덱스의 품질은 비교 함수에 의해 결정된 정렬 순서가 입력의 지역성을 얼마나 잘 유지하는지에 따라 달라집니다.

정렬지원방법은 선택사항입니다. 제공되지 않은 경우,색인 생성다음을 사용하여 각 튜플을 트리에 삽입하여 인덱스를 구축합니다.페널티그리고picksplit기능이 훨씬 느립니다.

SQL함수 선언은 다음과 같아야 합니다:

함수 생성 또는 교체 my_sortsupport(내부)
반품 무효
AS 'MODULE_PATHNAME'
언어 C 엄격;

인수는 a에 대한 포인터입니다.정렬지원구조체. 최소한 함수는 비교기 필드를 채워야 합니다. 비교기는 세 가지 인수, 즉 비교할 두 개의 데이텀과에 대한 포인터를 사용합니다.정렬지원구조체. 데이텀은 인덱스에 저장된 형식으로 된 두 개의 인덱스 값입니다. 즉, 다음에서 반환된 형식입니다.압축방법. 전체 API는 다음에 정의되어 있습니다.src/include/utils/sortsupport.h.

C 모듈의 일치 코드는 다음 뼈대를 따를 수 있습니다.

PG_FUNCTION_INFO_V1(my_sortsupport);

정적 정수
my_fastcmp(데이텀 x, 데이텀 y, SortSupport ssup)

  /* 정렬 값 z를 계산하여 x와 y 사이의 순서를 설정합니다 */

  int z1 = ComputeSpatialCode(x);
  int z2 = ComputeSpatialCode(y);

  z1 == z2 반환 ? 0 : z1  z2 ? 1: -1;

데이텀
my_sortsupport(PG_FUNCTION_ARGS)

  SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);

  ssup-비교기 = my_fastcmp;
  PG_RETURN_VOID();
translate_cmptype

주어진 a비교유형값:src/include/nodes/primnodes.h, 기능 일치를 위해 이 연산자 클래스에서 사용하는 전략 번호를 반환합니다. 함수가 반환되어야 합니다.잘못된 전략연산자 클래스에 일치하는 전략이 없는 경우.

이것은 시간적 토토 핫 제약 조건에 사용됩니다(예:기본 키그리고고유). 연산자 클래스가 이 함수를 제공하고 다음에 대한 결과를 반환하는 경우COMPARE_EQ, 비-에서 사용할 수 있습니다.겹침 없음색인 제약조건의 일부.

이 지원 함수는 인덱스 액세스 메소드 콜백 함수에 해당합니다.amtranslatecmptype(참조섹션 63.2).amtranslatecmptypeGiST 인덱스에 대한 콜백 함수는 단지 다음을 호출합니다.translate_cmptypeGiST 인덱스 액세스 방법 자체에는 고정된 전략 번호가 없으므로 해당 연산자 계열의 기능을 지원합니다.

SQL함수 선언은 다음과 같아야 합니다:

함수 생성 또는 교체 my_translate_cmptype(정수)
반환 smallint
AS 'MODULE_PATHNAME'
언어 C 엄격;

그리고 운영자 가족 등록은 다음과 같아야 합니다:

gist ADD를 사용하는 ALTER OPERATOR FAMILY my_opfamily
    기능 12 ("모든", "모든") my_translate_cmptype(int);

C 모듈의 일치 코드는 다음 뼈대를 따를 수 있습니다.

PG_FUNCTION_INFO_V1(my_translate_cmptype);

데이텀
my_translate_cmptype(PG_FUNCTION_ARGS)

    CompareType cmptype = PG_GETARG_INT32(0);
    StrategyNumber ret = InvalidStrategy;

    스위치(cmptype)

        사례 COMPARE_EQ:
            ret = BTEqualStrategyNumber;

    PG_RETURN_UINT16(ret);

하나의 번역 기능은 다음에서 제공됩니다.포스트그레SQL: gist_translate_cmptype_common은를 사용하는 연산자 클래스용입니다.RT*전략번호상수.btree_gist확장은 두 번째 번역 기능을 정의합니다.gist_translate_cmptype_btree, 다음을 사용하는 연산자 클래스의 경우BT*전략번호상수.

모든 GiST 지원 방법은 일반적으로 단기 메모리 컨텍스트에서 호출됩니다. 즉,CurrentMemoryContext각 튜플이 처리된 후 재설정됩니다. 그러므로 palloc하는 모든 것을 해제하는 것에 대해 걱정하는 것은 그리 중요하지 않습니다. 그러나 어떤 경우에는 반복 호출에서 데이터를 캐시하는 지원 방법이 유용합니다. 그렇게 하려면 더 오래 지속되는 데이터를 할당하세요.fcinfo-flinfo-fn_mcxt, 그리고 그것에 대한 포인터를 유지fcinfo-flinfo-fn_extra. 이러한 데이터는 인덱스 작업(예: 단일 GiST 인덱스 스캔, 인덱스 빌드 또는 인덱스 튜플 삽입)이 진행되는 동안 유지됩니다. a를 교체할 때 이전 값을 해제하도록 주의하세요.fn_extra값을 입력하지 않으면 작업 기간 동안 누수가 누적됩니다.

65.2.4. 구현#

65.2.4.1. GiST 인덱스 구축 방법#

GiST 인덱스를 구축하는 가장 간단한 방법은 모든 항목을 하나씩 삽입하는 것입니다. 인덱스 튜플이 인덱스 전체에 분산되어 있고 인덱스가 캐시에 맞지 않을 만큼 큰 경우 많은 임의 I/O가 필요하기 때문에 큰 인덱스의 경우 속도가 느려지는 경향이 있습니다.포스트그레SQLGiST 인덱스의 초기 빌드를 위한 두 가지 대체 방법을 지원합니다.정렬그리고버퍼됨모드.

정렬된 방법은 색인에서 사용되는 각 opclass가 다음을 제공하는 경우에만 사용할 수 있습니다.정렬지원함수, 다음에 설명된 대로섹션 65.2.3. 그렇다면 일반적으로 이 방법이 가장 적합하므로 기본적으로 사용됩니다.

버퍼링된 방법은 튜플을 인덱스에 직접 삽입하지 않는 방식으로 작동합니다. 순서가 지정되지 않은 데이터 세트에 필요한 임의 I/O 양을 대폭 줄일 수 있습니다. 잘 정렬된 데이터 세트의 경우 이점은 더 작거나 존재하지 않습니다. 한 번에 소수의 페이지만 새 튜플을 수신하고 인덱스 전체가 그렇지 않더라도 해당 페이지는 캐시에 적합하기 때문입니다.

버퍼링된 메소드는 다음을 호출해야 합니다.페널티추가 CPU 리소스를 소비하는 간단한 방법보다 더 자주 작동합니다. 또한 버퍼에는 결과 인덱스 크기까지 임시 디스크 공간이 필요합니다. 버퍼링은 결과 인덱스의 품질에 긍정적인 방향과 부정적인 방향 모두에 영향을 미칠 수도 있습니다. 그 영향은 입력 데이터의 분포 및 연산자 클래스 구현과 같은 다양한 요인에 따라 달라집니다.

정렬이 불가능할 경우 기본적으로 GiST 인덱스 빌드는 인덱스 크기에 도달하면 버퍼링 방법으로 전환됩니다.유효_캐시_크기. 버퍼링은 다음을 통해 수동으로 강제하거나 방지할 수 있습니다.버퍼링매개변수를 CREATE INDEX 명령에 추가합니다. 기본 동작은 대부분의 경우에 좋지만 입력 데이터가 정렬된 경우 버퍼링을 끄면 빌드 속도가 다소 빨라질 수 있습니다.

65.2.5. 예#

포스트그레SQL소스 배포에는 다음을 사용하여 구현된 색인 메소드의 여러 예가 포함되어 있습니다.GiST. 핵심 시스템은 현재 텍스트 검색 지원(인덱싱 대상)을 제공합니다.ts벡터그리고tsquery) 및 내장된 일부 기하학적 데이터 유형에 대한 R-Tree 동등한 기능(참조src/backend/access/gist/gistproc.c). 다음기여모듈에는 다음도 포함됨GiST연산자 클래스:

btree_gist

여러 데이터 유형에 대한 B-트리 동등한 기능

큐브

다차원 큐브에 대한 인덱싱

h스토어

(키, 값) 쌍을 저장하기 위한 모듈

인타레이

int4 값의 1차원 배열을 위한 RD-트리

트리

나무와 같은 구조에 대한 인덱싱

pg_trgm

트라이그램 일치를 사용한 텍스트 유사성

세그

인덱싱 대상부동 범위

수정 사항 제출

문서에 올바르지 않은 내용이 있으면 일치하지 않습니다. 특정 기능에 대한 경험이 있거나 추가 설명이 필요한 경우 이용해주세요이 양식문서 문제를 보고합니다.