2025년 9월 25일:토토 커뮤니티 : 토토
이 문서는 지원되지 않는 사설 토토 버전에 대한 것입니다.
다음에 대한 동일한 페이지를 보고 싶을 수도 있습니다.현재버전 또는 위에 나열된 다른 지원 버전 중 하나를 사용하세요.

55.2. 확장성

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

이 확장성을 확장성과 혼동해서는 안 됩니다. 데이터 측면에서 다른 표준 검색 트리보다 핸들. 예를 들어,포스트그레SQL확장 가능한 B-트리 및 해시 인덱스를 지원합니다. 그 말은 당신이 사용할 수 있습니다포스트그레SQL빌드하기 위해 원하는 데이터 유형에 대한 B-트리 또는 해시. 하지만 B-트리만 지원 범위 술어(<, =, ) 및 해시 인덱스 동등 쿼리만 지원합니다.

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

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

색인 연산자 클래스에는 7가지 메소드가 있습니다.지스트제공해야 하며 여덟 번째는 그건 선택사항입니다. 사설 토토의 정확성은 적절한 방법으로 보장됩니다. 의 구현같은, 일관됨그리고연합방법, 효율성(크기 및 속도) 인덱스는 다음에 따라 달라집니다.페널티그리고picksplit메소드. 나머지 2개는 기본 방법은압축그리고압축해제, 사설 토토가 내부를 가질 수 있도록 허용 인덱싱하는 데이터와 다른 유형의 트리 데이터입니다. 나뭇잎 다른 트리 노드는 사설 토토 데이터 유형이어야 하며 C 구조체 중 하나여야 합니다. (그러나 여전히 따라야 합니다.사설 토토여기의 데이터 유형 규칙에 대한 내용을 참조하세요.발레나가변 크기 데이터의 경우). 만약 트리의 내부 데이터 유형은 SQL 수준에 존재합니다.저장옵션만들기 운영자 클래스명령을 사용할 수 있습니다. 선택적 여덟 번째 방법 이다거리, 다음과 같은 경우에 필요합니다. 연산자 클래스는 정렬된 스캔(최근접 이웃)을 지원하기를 원합니다. 검색).

일관적인

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

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

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

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

데이텀 my_contant(PG_FUNCTION_ARGS);
PG_FUNCTION_INFO_V1(내_일관성);

데이텀
내_일관성(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선언 함수는 다음과 같아야 합니다:

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

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

데이텀 my_union(PG_FUNCTION_ARGS);
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지원 방법.

연합구현 함수 새로 포인터를 반환해야 합니다.팔록()에드 메모리. 뭐든지 그냥 돌려줄 수는 없어 입력은 다음과 같습니다.

압축

데이터 항목을 물리적인 형식에 적합한 형식으로 변환합니다. 색인 페이지에 저장됩니다.

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

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

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

데이텀 my_compress(PG_FUNCTION_ARGS);
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(복귀);

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

귀하의 필요에 따라 다음 사항에 관심을 가져야 할 수도 있습니다. 압축NULL그 안에 값, 저장 예를 들어(데이텀) 0좋아요gist_circle_compress그렇습니다.

압축해제

의 반대압축방법. 데이터 항목의 사설 토토 표현을 데이터베이스에서 조작할 수 있는 형식입니다.

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

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

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

데이텀 my_decompress(PG_FUNCTION_ARGS);
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 모듈의 일치 코드는 다음을 따를 수 있습니다. 뼈대:

데이텀 my_penalty(PG_FUNCTION_ARGS);
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(페널티);

페널티함수는 매우 중요합니다. 인덱스의 좋은 성능. 삽입 시 다음 작업에 사용됩니다. 새 항목을 추가할 위치를 선택할 때 따라야 할 분기를 결정합니다. 트리에 입장. 쿼리 시 인덱스의 균형이 더욱 잘 유지될수록 검색 속도가 빨라집니다.

picksplit

색인 페이지 분할이 필요할 때 이 기능은 다음을 결정합니다. 페이지의 어떤 항목이 이전 페이지에 남아 있는지, 새 페이지로 이동합니다.

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

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

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

데이텀 my_picksplit(PG_FUNCTION_ARGS);
PG_FUNCTION_INFO_V1(my_picksplit);

데이텀
my_picksplit(PG_FUNCTION_ARGS)

    GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
    OffsetNumber maxoff = Entryvec-n - 1;
    GISTENTRY *ent = Entryvec-벡터;
    GIST_SPLITVEC *v = (GIST_SPLITVEC *) PG_GETARG_POINTER(1);
    나는,
                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함수는 좋은 성능을 위해 매우 중요합니다 사설 토토의. 적합한 디자인페널티그리고picksplit구현은 도전이 되는 곳입니다 좋은 성과를 구현하는 방법GiST거짓말을 색인화합니다.

같은

두 개의 색인 항목이 동일하면 true를 반환하고 false를 반환합니다. 그렇지 않으면.

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

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

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

데이텀 my_same(PG_FUNCTION_ARGS);
PG_FUNCTION_INFO_V1(my_same);

데이텀
내_동일(PG_FUNCTION_ARGS)

    접두사_범위 *v1 = PG_GETARG_PREFIX_RA사설 토토E_P(0);
    prefix_ra사설 토토e *v2 = PG_GETARG_PREFIX_RA사설 토토E_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)
반환 float8
AS 'MODULE_PATHNAME'
언어 C 엄격;

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

데이텀 my_distance(PG_FUNCTION_ARGS);
PG_FUNCTION_INFO_V1(my_distance);

데이텀
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); */
    data_type *key = DatumGetDataType(entry-key);
    이중 회수;

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

    PG_RETURN_FLOAT8(복귀);

에 대한 인수거리함수는의 인수와 동일합니다.일관적인함수(재확인 플래그가 없다는 점 제외) 사용됩니다. 리프 인덱스 항목까지의 거리는 항상 다음과 같아야 합니다. 튜플을 다시 정렬할 수 있는 방법이 없기 때문에 정확하게 결정됩니다. 일단 반환되면. 다음과 같은 경우 일부 근사치가 허용됩니다. 내부 트리 노드까지의 거리를 결정하는 동안 결과는 어린이의 실제 거리보다 결코 크지 않습니다. 따라서 예를 들어 경계 상자까지의 거리가 일반적으로 충분합니다. 기하학적 응용. 결과 값은 유한할 수 있습니다.float8값. (무한대와 마이너스 무한대 null과 같은 경우를 처리하기 위해 내부적으로 사용되므로 추천함거리함수 이 값을 반환합니다.)

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