API를 사용하여 인덱스 생성

SQL 명령을 사용하거나 TableRequest API를 사용하여 NoSQL 테이블에 대한 인덱스를 생성할 수 있습니다.

SQL 명령 사용

인덱스는 CREATE INDEX 명령을 사용하여 생성할 수 있습니다.

단일 필드 인덱스 생성:

예: 승객 예약 코드에 대한 인덱스를 생성합니다.

CREATE INDEX fixedschema_conf ON baggageInfo(confNo)

다음은 단일 열 고정 스키마 인덱스의 예제입니다. 인덱스는 baggageInfo 테이블에 string 데이터 유형이 있는 confNo 필드에 생성됩니다.

조합 인덱스 생성:

예: 승객의 성명 및 전화 번호에 대한 색인을 생성합니다.

CREATE INDEX compindex_namephone ON baggageInfo(fullName,contactPhone)

다음은 조합 인덱스의 예제입니다. 인덱스는 baggageInfo 스키마의 두 필드에 전체 이름과 연락처 전화 번호로 생성됩니다.

주: 이 인덱스의 필드를 고정 스키마 열로 하나 이상 가질 수 있습니다.

JSON 인덱스 생성:

하나 이상의 필드가 JSON 데이터 내에 있는 경우 인덱스를 JSON 인덱스라고 합니다. JSON은 스키마리스이므로 인덱스화된 JSON 필드의 데이터 유형은 행마다 다를 수 있습니다. JSON 필드에 인덱스를 생성할 때 JSON 필드에 예상되는 데이터 유형이 확실하지 않으면 anyAtomic 데이터 유형을 사용할 수 있습니다. 또는 Oracle NoSQL Database 기본 데이터 유형 중 하나를 지정할 수 있습니다. 이렇게 하려면 모든 인덱스 경로 옆에 있는 AS 키워드를 사용하여 데이터 유형을 JSON 필드로 선언합니다.

예 1: 승객 가방의 태그 번호에 대한 인덱스를 만듭니다.

CREATE INDEX jsonindex_tagnum ON baggageInfo(bagInfo[].tagnum as INTEGER)

위의 예제는 JSON 인덱스의 예입니다. 인덱스는 baggageInfo 테이블의 baginfo JSON 필드에 있는 tagnum 필드에 생성됩니다. 인덱스를 생성하는 동안 tagnum 필드에 대한 데이터 유형을 제공합니다.

연관된 테이블에 선언된 데이터 유형을 위반하는 데이터가 있는 행이 포함되어 있으면 JSON 인덱스 생성이 실패합니다. 마찬가지로, JSON 인덱스를 생성한 후 새 행이 JSON 인덱스의 선언된 데이터 유형을 준수하지 않으면 삽입/업데이트 작업이 실패합니다.

예제 2: 승객 경로에 대한 인덱스를 생성합니다.

CREATE INDEX jsonindex_routing ON baggageInfo(bagInfo[].routing as ANYATOMIC)

JSON 인덱스 경로를 anyAtomic으로 선언하면 인덱스화된 JSON 필드가 다양한 데이터 유형의 값을 가질 수 있다는 이점이 있습니다. 인덱스 항목이 오름차순으로 정렬됩니다. 이러한 값이 인덱스에 저장되면 다음과 같이 정렬됩니다.

그러나 이러한 이점은 공간 및 CPU 비용에 의해 오프셋됩니다. 인덱스화된 필드에 있는 모든 종류의 숫자 값이 인덱스에 저장되기 전에 Number로 변환되기 때문입니다. 이 캐스트는 CPU 시간이 걸리며 숫자에 대한 결과 저장 영역이 숫자에 대한 원래 저장 영역보다 큽니다.

단순 인덱스 생성:

테이블의 각 데이터 행에 대해 인덱스에 하나의 항목이 생성되는 경우 인덱스를 단순 인덱스라고 합니다. 인덱스는 원자 데이터 유형 또는 특수 값(SQL NULL, JSON NULL, EMPTY)인 단일 값을 반환합니다. 기본적으로 단순 인덱스의 인덱스 경로는 배열이나 맵 또는 중첩된 데이터 유형을 반환하지 않아야 합니다.

예: 가방이 마지막으로 표시되었을 때 마지막 확인 스테이션과 도착 날짜 및 시간에 대해 세 개의 필드에 인덱스를 생성합니다.

CREATE INDEX simpleindex_arrival ON baggageInfo(bagInfo[].lastSeenTimeGmt as ANYATOMIC,
bagInfo[].bagArrivalDate as ANYATOMIC, bagInfo[].lastSeenTimeStation as ANYATOMIC)

위의 예제는 JSON 필드에서 JSON 문서에 생성된 단순 인덱스의 예입니다. 인덱스는 lastSeenTimeGmtbagArrivalDatelastSeenTimeStation에 생성되며, 모두 baggageInfo 테이블의 정보 JSON 필드에 있는 bagInfo JSON 문서에서 생성됩니다. 단순 인덱스 경로 평가에서 빈 결과가 반환되면 특수 값 EMPTY가 인덱스 항목으로 사용됩니다. 위 예에서 bagInfo JSON 문서에 lastSeenTimeGmt 또는 bagArrivalDate 또는 lastSeenTimeStation 항목이 없거나 bagInfo JSON 배열이 없는 경우 특수 값 EMPTY가 인덱스화됩니다.

다중 키 인덱스 생성:

테이블의 각 데이터 행에 대해 인덱스에 여러 항목이 생성되는 경우 인덱스를 다중 키 인덱스라고 합니다. 다중 키 인덱스에는 배열 또는 중첩 데이터 유형을 사용하는 인덱스 경로가 하나 이상 있습니다. 다중 키 인덱스에서 각 테이블 행에 대해 인덱스화되는 배열의 모든 요소에 대해 인덱스 항목이 생성됩니다.

예 1: 다중 키 인덱스: 스트리밍 계정 응용 프로그램의 series info 배열에 인덱스를 생성합니다.

CREATE INDEX multikeyindex1 ON stream_acct (acct_data.contentStreamed[].seriesInfo[] AS ANYATOMIC)

인덱스는 stream_acct 테이블의 seriesInfo[] 배열에 생성됩니다. 여기서는 stream_acct 테이블의 각 행에 있는 seriesInfo[] 배열의 모든 요소가 인덱스화됩니다.

예제 2: 중첩된 다중 키 인덱스: 스트리밍 계정 응용 프로그램의 에피소드 세부 정보 배열에 인덱스를 생성합니다.

인덱스는 배열 내에 있고 다른 배열 내에 있는 필드에 생성될 경우 중첩된 다중 키 인덱스입니다.

CREATE INDEX multikeyindex2 ON stream_acct (
    acct_data.contentStreamed[].seriesInfo[].episodes[]  AS ANYATOMIC)

위의 예는 다른 배열 내에 있는 배열에 필드가 있는 중첩된 다중 키 인덱스의 예입니다. 인덱스는 stream_acct 테이블의 acct_data JSON에 있는 seriesInfo[] 배열의 episodes[] 배열에 생성됩니다.

예제 3: 조합 다중 키 인덱스:

둘 이상의 필드에 인덱스가 생성되고 이러한 필드 중 하나 이상이 다중 키인 경우 복합 다중 키 인덱스라고 합니다. 조합 다중 키 인덱스는 다중 키 인덱스 경로와 단순 인덱스 경로의 조합을 가질 수 있습니다.

CREATE INDEX multikeyindex3 ON stream_acct (acct_data.country AS ANYATOMIC,
acct_data.contentStreamed[].seriesInfo[].episodes[]  AS ANYATOMIC)

위의 예제는 하나의 다중 키 인덱스 경로와 하나의 단순 인덱스 경로가 있는 조합 다중 키 인덱스의 예입니다. 인덱스는 stream_acct 테이블의 acct_data JSON 열에 있는 country 필드와 episodes[] 배열에 생성됩니다.

다중 키 인덱스에 대한 제한 사항에 대한 자세한 내용은 다중 키 인덱스에 대한 사양 및 제한 사항을 참조하십시오.

NO NULLS 절을 사용하여 인덱스 생성

선택적 WITH NO NULLS 절을 사용하여 인덱스를 생성할 수 있습니다. 이 경우 인덱스화된 필드에 NULL 및/또는 EMPTY 값이 있는 행은 인덱스화되지 않습니다.

CREATE INDEX nonull_phone ON baggageInfo (contactPhone) WITH NO NULLS

행당 고유 키가 있는 인덱스 생성

행 속성당 고유 키를 사용하여 인덱스를 생성할 수 있습니다.

CREATE INDEX idx_showid ON
stream_acct(acct_data.contentStreamed[].showId AS INTEGER)
WITH UNIQUE KEYS PER ROW

위 질의에서 인덱스는 showId에 생성되며 단일 contentStreamed 배열에 대해 중복 showId가 있을 수 없습니다. 스트리밍 사용자의 경우 contentStreamed 배열에 동일한 표시 ID를 가진 둘 이상의 표시가 포함될 수 없음을 질의 프로세서에 알립니다. 중복 표시 ID가 있는 경우 인덱스에 포함되지 않으므로 제한이 필요합니다. 단일 contentStreamed 배열에 동일한 showId 두 개 이상의 항목이 있는 행을 삽입하면 오류가 발생하고 삽입 작업이 실패합니다.

쿼리 실행 시간의 최적화:

행당 고유 키를 사용하여 인덱스를 생성하는 경우 인덱스는 contentStreamed 배열의 요소 수보다 적은 수의 항목을 포함합니다. 이 인덱스를 사용하기 위한 효율적인 query를 작성할 수 있습니다. 이러한 인덱스를 query에 사용하면 인덱스가 사용되지 않은 경우보다 FROM 절의 결과가 더 적어집니다.

함수의 인덱스를 생성하는 예제는 다음과 같습니다.

예 1: BaggageInfo 테이블의 행을 최신 수정 시간으로 인덱스화하는 인덱스를 생성합니다.

CREATE INDEX idx_modtime ON BaggageInfo(modification_time())

이 인덱스는 필터 조건으로 modification_time가 있는 질의에 사용됩니다.

SELECT * FROM BaggageInfo $u WHERE
modification_time($u) > "2019-08-01T10:45:00"

이 질의는 가장 최근 수정 시간이 2019-08-01T10:45:00 이후인 모든 행을 반환합니다. 위에 정의된 idx_modtime 인덱스를 사용합니다. show query 명령을 사용하여 query 계획을 확인하면 이를 확인할 수 있습니다.

예제 2: 경로 지정 필드의 길이에 대해 BaggageInfo 테이블의 행을 인덱스화하는 인덱스를 생성합니다.

CREATE INDEX idx_routlen ON BaggageInfo (length(bagInfo[].routing as string))

이 인덱스는 필터 조건으로 length가 있는 질의에 사용됩니다.

SELECT * from BaggageInfo $bag where length($bag.bagInfo[].routing) > 10

이 질의는 공정순서 필드 길이가 10보다 큰 모든 행을 반환합니다. 위에 정의된 idx_routlen 인덱스를 사용합니다. show query 명령을 사용하여 query 계획을 확인하면 이를 확인할 수 있습니다.

예제 3: 다중 키 인덱스 경로 사용

다음 예제에서는 사용자가 보는 쇼의 ID와 쇼가 시청된 날짜의 연도 및 월을 기준으로 stream_acct 테이블의 사용자를 인덱스화합니다.

CREATE INDEX idx_showid_year_month ON
stream_acct(acct_data.contentStreamed[].showId AS INTEGER,
substring(acct_data.contentStreamed[].seriesInfo[].episodes[].date AS STRING,0, 4),
substring(acct_data.contentStreamed[].seriesInfo[].episodes[].date AS STRING,5, 2))

이 인덱스를 사용하는 query의 예는 다음과 같습니다. 질의는 202216번의 에피소드를 본 사용자 수를 계산합니다.

SELECT count(*) FROM stream_acct s1 WHERE EXISTS
s1.acct_data.contentStreamed[$element.showId = 16].seriesInfo.
episodes[substring($element.date, 0, 4) = "2022"]

이 질의는 idx_showid_year_month 인덱스를 사용합니다. show query 명령을 사용하여 query 계획을 확인하면 이를 확인할 수 있습니다.

show query SELECT count(*) FROM stream_acct s1 WHERE EXISTS
> s1.acct_data.contentStreamed[$element.showId = 16].seriesInfo.episodes[substring($element.date, 0, 4) = "2022"]

{
  "iterator kind" : "GROUP",
  "input variable" : "$gb-1",
  "input iterator" :
  {
    "iterator kind" : "RECEIVE",
    "distribution kind" : "ALL_SHARDS",
    "distinct by fields at positions" : [ 1 ],
    "input iterator" :
    {
      "iterator kind" : "SELECT",
      "FROM" :
      {
        "iterator kind" : "TABLE",
        "target table" : "stream_acct",
        "row variable" : "$$s1",
        "index used" : "idx_showid_year_month",
        "covering index" : true,
        "index row variable" : "$$s1_idx",
        "index scans" : [
          {
            "equality conditions" : {"acct_data.contentStreamed[].showId":16,"substring#acct_data.contentStreamed[].seriesInfo[].episodes[].date@,0,4":"2022"},
            "range conditions" : {}
          }
        ]
      },
      "FROM variable" : "$$s1_idx",
      "SELECT expressions" : [
        {
          "field name" : "Column_1",
          "field expression" :
          {
            "iterator kind" : "CONST",
            "value" : 1
          }
        },
        {
          "field name" : "acct_id_gen",
          "field expression" :
          {
            "iterator kind" : "FIELD_STEP",
            "field name" : "#acct_id",
            "input iterator" :
            {
              "iterator kind" : "VAR_REF",
              "variable" : "$$s1_idx"
            }
          }
        }
      ]
    }
  },
  "grouping expressions" : [

  ],
  "aggregate functions" : [
    {
      "iterator kind" : "FUNC_COUNT_STAR"
    }
  ]
}

TableRequest API 사용

TableRequest API를 사용하여 NoSQL 테이블에 인덱스를 생성할 수 있습니다.

TableRequest 클래스는 테이블에 인덱스를 생성하는 데 사용됩니다. 이 요청에 의해 지정된 작업의 실행은 비동기입니다. 이러한 작업은 장시간 실행되는 작업일 수 있습니다. TableResultTableRequest 작업에서 반환되며 테이블의 상태를 캡슐화합니다. TableRequest 클래스 및 해당 메소드에 대한 자세한 내용은 Oracle NoSQL Java SDK API Reference를 참조하십시오.

Indexes.java의 전체 코드를 여기에서 다운로드하십시오.

/**
* Create an index acct_episodes in the stream_acct table
*/
private static void crtIndex(NoSQLHandle handle) throws Exception {
   String createIndexDDL = "CREATE INDEX acct_episodes ON " + tableName +
                           "(acct_data.contentStreamed[].seriesInfo[].episodes[]  AS ANYATOMIC)";
   TableRequest treq = new TableRequest().setStatement(createIndexDDL);
   TableResult tres = handle.tableRequest(treq);
   tres.waitForCompletion(handle, 60000, /* wait 60 sec */
          1000); /* delay ms for poll */
   System.out.println("Index acct_episodes on " + tableName + " is created");
}

borneo.TableRequest 클래스는 테이블에 인덱스를 생성하는 데 사용됩니다. borneo.NoSQLHandle.table_request()에 대한 모든 호출은 비동기적이므로 결과를 확인하고 borneo.TableResult.wait_for_completion()를 호출하여 작업이 완료될 때까지 기다려야 합니다. table_request 및 해당 메소드에 대한 자세한 내용은 Oracle NoSQL Python SDK API Reference를 참조하십시오.

Indexes.py의 전체 코드를 여기에서 다운로드하십시오.

#create an index
def create_index(handle):
   statement = '''CREATE INDEX acct_episodes ON stream_acct (acct_data.contentStreamed[].seriesInfo[].episodes[]  AS ANYATOMIC)'''
   request = TableRequest().set_statement(statement)
   table_result = handle.do_table_request(request, 40000, 3000)
   table_result.wait_for_completion(handle, 40000, 3000)
   print('Index acct_episodes on the table stream_acct is created')

TableRequest 클래스는 테이블에 인덱스를 생성하는 데 사용됩니다. TableRequest에 의해 지정된 작업의 실행은 비동기입니다. 이러한 작업은 장시간 실행되는 작업일 수 있습니다. 이 요청은 테이블이 원하는 상태에 도달할 때까지 폴링하는 데 사용할 수 있는 TableResult를 반환하는 Client.DoTableRequest() 작업의 입력으로 사용됩니다. TableRequest 클래스의 다양한 메소드에 대한 자세한 내용은 Oracle NoSQL Go SDK API Reference를 참조하십시오.

Indexes.go여기 예제에서 전체 코드를 다운로드하십시오.

//create an index on a table
func createIndex(client *nosqldb.Client, err error, tableName string)(){
   stmt := fmt.Sprintf("CREATE INDEX acct_episodes ON %s "+
		"(acct_data.contentStreamed[].seriesInfo[].episodes[]  AS ANYATOMIC)",tableName)
   tableReq := &nosqldb.TableRequest{
		Statement: stmt,
   }
   tableRes, err := client.DoTableRequest(tableReq)
   if err != nil {
      fmt.Printf("cannot initiate CREATE INDEX request: %v\n", err)
      return
   }
   // The create index request is asynchronous, wait for index creation to complete.
   _, err = tableRes.WaitForCompletion(client, 60*time.Second, time.Second)
   if err != nil {
      fmt.Printf("Error finishing CREATE INDEX request: %v\n", err)
      return
   }
   fmt.Println("Created Index acct_episodes on table ", tableName)
   return
}

tableDDL 메소드를 사용하여 테이블에 인덱스를 생성할 수 있습니다. 이 메소드는 비동기적이며 TableResult의 Promise를 반환합니다. TableResult는 테이블의 상태를 캡슐화하는 일반 JavaScript 객체입니다. 메소드 세부 정보는 NoSQLClient 클래스를 참조하십시오.

Indexes.js의 예에서 전체 JavaScript 코드 인덱스.jsIndexes.ts의 전체 TypeScript 코드를 여기에서 다운로드하십시오.

//creates an index
async function createIndex(handle) {
   const crtindDDL = `CREATE INDEX acct_episodes ON ${TABLE_NAME}(acct_data.contentStreamed[].seriesInfo[].episodes[]  AS ANYATOMIC)`;
   let res =  await handle.tableDDL(crtindDDL);
   console.log('Index acct_episodes is created on table:' + TABLE_NAME);
}

테이블에 인덱스를 생성하려면 ExecuteTableDDLAsync 또는 ExecuteTableDDLWithCompletionAsync 메소드 중 하나를 사용합니다. 이 두 메소드는 모두 Task<TableResult>를 반환합니다. TableResult 인스턴스는 TableState 및 테이블 스키마와 같은 DDL 작업의 상태를 포함합니다. 이러한 방법에 대한 자세한 내용은 Oracle NoSQL Dotnet SDK API Reference를 참조하십시오.

Indexes.cs의 전체 코드를 여기에서 다운로드하십시오.

// Creates an index on a table
private static async Task createIndex(NoSQLClient client){
   var sql =
      $@"CREATE INDEX acct_episodes ON {TableName}(acct_data.contentStreamed[].seriesInfo[].episodes[]  AS ANYATOMIC)";
   var tableResult = await client.ExecuteTableDDLAsync(sql);
   // Wait for the operation completion
   await tableResult.WaitForCompletionAsync();
   Console.WriteLine(" Index acct_episodes is created on table Table {0}",
                tableResult.TableName);
}