使用 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 欄位具有各種資料類型的值。索引項目會依遞增順序排序。當這些值儲存在索引中時,其排序方式如下:
  • 數字
  • String
  • 布林值

不過,這種優點會使用空間與 CPU 成本來偏移。這是因為在索引欄位中,任何種類的數值都會轉換成「數字」,然後再儲存在索引中。這項轉換需要 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 文件中沒有 lastSeenTimeGmtbagArrivalDatelastSeenTimeStation 項目,或者如果沒有 bagInfo JSON 陣列,則會編製 EMPTY 特殊值索引。

建立多重相似索引:

如果表格中每個資料列的索引中都有多個建立的項目,則索引稱為多重索引鍵索引。在多相似的索引中,至少有一個使用陣列或巢狀資料類型的索引路徑。在多重相似索引中,對於每個表格資料列,會在正在編製索引之陣列中的所有元素上建立索引項目。

範例 1:多重相似索引:在串流帳戶應用程式的序列資訊陣列上建立索引。
CREATE INDEX multikeyindex1 ON stream_acct (acct_data.contentStreamed[].seriesInfo[] AS ANYATOMIC)

索引會在 stream_acct 表格的 seriesInfo[] 陣列上建立。此處將編製 stream_acct 表格中每個資料列之 seriesInfo[] 陣列中的所有元素索引。

範例 2:巢狀多重相似索引:在串流帳戶應用程式的 episode 詳細資訊陣列上建立索引。

如果索引建立在出現在陣列內部的欄位上,而陣列又出現在另一個陣列中,則該索引是一個巢狀多重相似索引。
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)

以上是具有一個多相似索引路徑與一個簡單索引路徑的複合多相似索引範例。索引會在 country 欄位建立,並在 stream_acct 表格的 acct_data JSON 資料欄中建立 episodes[] 陣列。

請參閱多重相似索引的規格與限制,瞭解多重相似索引的限制。

使用 NO NULLS 子句建立索引

您可以使用選擇性的 WITH NO NULLS 子句建立索引。在此情況下,索引欄位上具有 NULL 和 (或) EMPTY 值的資料列將不會編製索引。
CREATE INDEX nonull_phone ON baggageInfo (contactPhone) WITH NO NULLS
  • 上述查詢會在乘客的電話號碼上建立索引。如果有些乘客沒有電話號碼,這些欄位就不會是索引的一部分。
  • 使用 WITH NO NULLS 子句建立的索引,當資料在已編製索引的欄位中包含許多空值和 (或) EMPTY 值時,可能會很有用。它可以減少編製索引期間的時間和空間負荷。
  • 不過,查詢只能使用這類索引。如果索引是使用 WITH NO NULLS 子句建立的,則不能使用 IS NULL 和 NOT EXISTS 述詞作為該索引的索引述詞。
  • 實際上,只有在查詢具有每個已編製索引之欄位的索引述詞時,查詢才能使用此類索引。

建立每一資料列具有唯一索引鍵的索引

您可以為每個資料列特性建立具有唯一索引鍵的索引。
CREATE INDEX idx_showid ON 
stream_acct(acct_data.contentStreamed[].showId AS INTEGER)
WITH UNIQUE KEYS PER ROW

在上述查詢中,會在 showId 上建立索引,單一 contentStreamed 陣列則不能有重複的 showId。這會通知查詢處理器,對於任何串流使用者,contentStreamed 陣列不可包含兩個或更多具有相同顯示 ID 的顯示。需有限制,因為如果有重複的顯示 ID,這些 ID 將不會包含在索引中。如果您在單一 contentStreamed 陣列中插入具有相同 showId 兩個或更多項目的列,則會發生錯誤,且插入作業不成功。

查詢程式實際執行中的最佳化:

當您建立索引時,索引所包含的項目數會比 contentStreamed 陣列中的元素數少。您可以編寫有效率的查詢來使用此索引。依查詢使用此類索引所產生的 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 命令檢視查詢計畫來進行驗證。

範例 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 命令檢視查詢計畫來進行驗證。

範例 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))
下面是使用此索引的查詢範例。此查詢會計算在 2022 年中,曾觀看任何一集 16 的使用者數目。
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 命令檢視查詢計畫來進行驗證。
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 類別是用來在表格上建立索引。此要求所指定的作業執行非同步。這些作業可能會長時間執行。TableResult 會從 TableRequest 作業傳回,並且會封裝表格的狀態。請參閱 Oracle NoSQL Java SDK API Reference ,瞭解 TableRequest 類別及其方法的詳細資訊。

Download the full code Indexes.java from the examples here.

/**
* 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() 以等待作業完成。請參閱 Oracle NoSQL Python SDK API Reference ,瞭解 table_request 及其方法的詳細資訊。

Download the full code Indexes.py from the examples here.

#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 指定的作業執行非同步。這些作業可能會長時間執行。此要求是用來作為 Client.DoTableRequest() 作業的輸入,它會傳回可用來輪詢的 TableResult,直到表格達到所需的狀態為止。請參閱 Oracle NoSQL Go SDK API Reference ,瞭解 TableRequest 類別各種方法的詳細資訊。

Download the full code Indexes.go from the examples here.

//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 類別。

Download the full JavaScript code Indexes.js from the examples here and the full TypeScript code Indexes.ts from the examples here.

//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);
}

若要在表格上建立索引,請使用 ExecuteTableDDLAsyncExecuteTableDDLWithCompletionAsync 方法。這兩種方法都會傳回 Task<TableResult>TableResult 執行處理包含 DDL 作業的狀態,例如 TableState 和表格綱要。如需這些方法的詳細資訊,請參閱 Oracle NoSQL Dotnet SDK API Reference

Download the full code Indexes.cs from the examples here.
// 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);
}