Table Store的表由行組成,每一行包含主鍵和屬性。本節將介紹Table Store資料的操作方法。

Table Store行簡介

組成Table Store表的基本單位是行,行由主鍵和屬性群組成。其中,主鍵是必須的,且每一行的主鍵列的名稱和類型相同;屬性不是必須的,並且每一行的屬性可以不同。更多資訊請參見Table Store的資料模型概念

Table Store的資料操作有以下三種類型:

  • 單行操作

    • GetRow:讀取單行資料。

    • PutRow:新插入一行。如果該行內容已經存在,則先刪除舊行,再寫入新行。

    • UpdateRow:更新一行。應用可以增加、刪除一行中的屬性列,或者更新已經存在的屬性列的值。如果該行不存在,則新增一行。

    • DeleteRow:刪除一行。

  • 批量操作

    • BatchGetRow:批量讀取多行資料。

    • BatchWriteRow:批量插入、更新或者刪除多行資料。

  • 範圍讀取

    • GetRange:讀取表中一個範圍內的資料。

Table Store單行操作

  • 單行寫入操作

    Table Store的單行寫操作有三種:PutRow、UpdateRow 和 DeleteRow。下面分別介紹每種操作的行為語義和注意事項:

    • PutRow:新寫入一行。如果這一行已經存在,則這一行舊的資料會先被刪除,再新寫入一行。

    • UpdateRow:更新一行的資料。Table Store會根據請求的內容在這一行中新增列,修改或者刪除指定列的值。如果這一行不存在,則會插入新的一行。但是有一種特殊的情境,若 UpdateRow 請求只包含刪除指定的列,且該行不存在,則該請求不會插入新行。

    • DeleteRow:刪除一行。如果刪除的行不存在,則不會發生任何變化。

    應用程式通過佈建要求中的 condition 欄位來指定寫入操作執行時,是否需要對行的存在性進行檢查。condition 有三種類型:

    • IGNORE:不做任何存在性檢查。

    • EXPECT_EXIST:期望行存在。如果該行存在,則操作成功;如果該行不存在,則操作失敗。

    • EXPECT_NOT_EXIST:期望行不存在。如果行不存在,則操作成功;如果該行存在,則操作失敗。

    condition 為 EXPECT_NOT_EXIST 的 DeleteRow、UpdateRow 操作是沒有意義的,刪除一個不存在的行是無意義的,如果需要更新不存在的行可以使用 PutRow 操作。

    如果操作發生錯誤,如參數檢查失敗、單行資料量過多、行存在性檢查失敗等等,會返回錯誤碼給應用程式。如果操作成功,Table Store會將操作消耗的服務能力單元返回給應用程式。

    各操作消耗的寫服務能力單元的計算規則如下:

    • PutRow:本次消耗的寫 CU 為修改的行主鍵資料大小與屬性列資料大小之和除以 4 KB 向上取整。若指定條件檢查不為 IGNORE,還需消耗該行主鍵資料大小除以 4 KB 向上取整的讀 CU。如果操作不滿足應用程式指定的行存在性檢查條件,則操作失敗並消耗 1 單位寫服務能力單元和 1 單位讀服務能力單元。請參見 PutRow 詳解。

    • UpdateRow:本次消耗的寫 CU 為修改的行主鍵資料大小與屬性列資料大小之和除以 4 KB 向上取整。UpdateRow 中包含的需要刪除的屬性列,只有其列名計入該屬性列資料大小。若指定條件檢查不為 IGNORE,還需消耗該行主鍵資料大小除以 4 KB 向上取整的讀 CU。如果操作不滿足應用程式指定的行存在性檢查條件,則操作失敗並消耗 1 單位寫服務能力單元和 1 單位讀服務能力單元。請參見 UpdateRow 詳解。

    • DeleteRow:被刪除的行主鍵資料大小除以 4 KB 向上取整。若指定條件檢查不為 IGNORE,還需消耗該行主鍵資料大小除以 4 KB 向上取整的讀 CU。如果操作不滿足應用程式指定的行存在性檢查條件,則操作失敗並消耗 1 單位寫服務能力單元。請參見 DeleteRow 詳解。

    寫操作會根據指定的 condition 情況消耗一定的讀服務能力單元。

    樣本

    下面舉例說明單行寫操作的寫服務能力單元和讀服務能力單元的計算。

    樣本 1,使用 PutRow 進行如下行寫入操作:

    //PutRow 操作
    //row_size=len('pk')+len('value1')+len('value2')+8Byte+1300Byte+3000Byte=4322Byte
    {
        primary_keys:{'pk':1},
        attributes:{'value1':String(1300Byte), 'value2':String(3000Byte)}
    }
    
    //原來的行
    //row_size=len('pk')+len('value2')+8Byte+900Byte=916Byte
    //row_primarykey_size=len('pk')+8Byte=10Byte
    {
        primary_keys:{'pk':1},
        attributes:{'value2':String(900Byte)}
    }
    

    讀/寫服務能力單元的消耗情況如下:

    • 將 condition 設定為 EXPECT_EXIST 時:消耗的寫服務能力單元為 4322 Byte 除以 4 KB 向上取整,消耗的讀服務能力單元為該行主鍵資料大小 10 Byte 除以 4 KB 向上取整。該 PutRow 操作消耗 2 個單位的寫服務能力單元和 1 個單位的讀服務能力單元。

    • 將 condition 設定為 IGNORE 時:消耗的寫服務能力單元為 4322 Byte 除以 4 KB 向上取整,消耗 0 個讀服務能力單元。該 PutRow 操作消耗 2 個單位的寫服務能力單元和 0 個單位的讀服務能力單元。

    • 將 condition 設定為 EXPECT_NOT_EXIST 時:指定的行存在性檢查條件檢查失敗,該 PutRow 操作消耗 1 個單位的寫服務能力單元和 1 個單位的讀服務能力單元。

    樣本 2,使用 UpdateRow 新寫入一行:

    //UpdateRow 操作
    //刪除的屬性列列名長度計入 row_size
    //row_size=len('pk')+len('value1')+len('value2')+8Byte+900Byte=922Byte
    {
        primary_keys:{'pk':1},
        attributes:{'value1':String(900Byte), 'value2':Delete}
    }
    
    //原來的行不存在
    //row_size=0
    

    讀/寫服務能力單元的消耗情況如下:

    • 將 condition 設定為 IGNORE 時:消耗的寫服務能力單元為 922 Byte 除以 4 KB 向上取整,消耗 0 個讀服務能力單元。該 UpdateRow 操作消耗 1個單位的寫服務能力單元和 0 個讀服務能力單元。

    • 將 condition 設定為 EXPECT_EXIST 時:指定的行存在性檢查條件檢查失敗,該 PutRow 操作消耗 1 個單位的寫服務能力單元和 1 個單位的讀服務能力單元。

    樣本 3,使用 UpdateRow 對存在的行進行更新操作:

    //UpdateRow 操作
    //row_size=len('pk')+len('value1')+len('value2')+8Byte+1300Byte+3000Byte=4322Byte
    {
        primary_keys:{'pk':1},
        attributes:{'value1':String(1300Byte), 'value2':String(3000Byte)}
    }
    //原來的行
    //row_size=len('pk')+len('value1')+8Byte+900Byte=916Byte
    //row_primarykey_size=len('pk')+8Byte=10Byte
    {
        primary_keys:{'pk':1},
        attributes:{'value1':String(900Byte)}
    }
    

    讀/寫服務能力單元的消耗情況如下:

    • 將 condition 設定為 EXPECT_EXIST 時:消耗的寫服務能力單元為 4322 Byte 除以 4 KB 向上取整,消耗的讀服務能力單元為該行主鍵資料大小 10 Byte 除以 4 KB 向上取整。該 UpdateRow 操作消耗 2 個單位的寫服務能力單元和 1 個單位的讀服務能力單元。

    • 將 condition 設定為 IGNORE 時:消耗的寫服務能力單元為 4322 Byte 除以 4 KB 向上取整,消耗 0 個讀服務能力單元,該 UpdateRow 操作消耗 2 個單位的寫服務能力單元和 0 個單位的讀服務能力單元。

    樣本 4,使用 DeleteRow 刪除不存在的行:

    //原來的行不存在
    //row_size=0
    
    //DeleteRow 操作
    //row_size=0
    //row_primarykey_size=len('pk')+8Byte=10Byte
    {
        primary_keys:{'pk':1},
    }
    

    修改前後的資料大小均為 0,無論讀寫操作成功還是失敗至少消耗 1 個單位服務能力單元。因此,該 DeleteRow 操作消耗 1 個單位的寫服務能力單元。

    讀/寫服務能力單元的消耗情況如下:

    • 將 condition 設定為 EXPECT_EXIST 時:消耗的寫服務能力單元為該行主鍵資料大小 10 Byte 除以 4 KB 向上取整,消耗的讀服務能力單元為該主鍵資料大小 10 Byte 除以 4 KB 向上取整。該 DeleteRow 操作消耗 1 個單位的寫服務能力單元和 1 個單位的讀服務能力單元。

    • 將 condition 設定為 IGNORE 時:消耗的寫服務能力單元為該行主鍵資料大小 10 Byte 除以 4 KB 向上取整,消耗 0 個讀服務能力單元。該 DeleteRow 操作消耗 1 個單位的寫服務能力單元和 0 個單位的讀服務能力單元。

    更多資訊請參見 API Reference 中的 PutRowUpdateRowDeleteRow 章節。

  • 單行讀取操作

    Table Store的單行讀操作只有一種:GetRow。

    應用程式提供完整的主鍵和需要返回的列名。列名可以是主鍵列或屬性列,也可以不指定要返回的列名,此時請求返回整行資料。

    Table Store根據被讀取的行主鍵的資料大小與實際讀取的屬性列資料大小之和計算讀服務能力單元。將行資料大小除以 4 KB 向上取整作為本次讀取操作消耗的讀服務能力單元。如果操作指定的行不存在,則消耗 1 單位讀服務能力單元,單行讀取操作不會消耗寫服務能力單元。

    樣本

    使用 GetRow 讀取一行消耗的寫服務能力單元的計算:

    //被讀取的行
    
    //row_size=len('pk')+len('value1')+len('value2')+8Byte+1200Byte+3100Byte=4322Byte
    {
        primary_keys:{'pk':1},
        attributes:{'value1':String(1200Byte), 'value2':String(3100Byte)}
    }
    
    //GetRow 操作
    //擷取的資料 size=len('pk')+len('value1')+8Byte+1200Byte=1216Byte
    {
        primary_keys:{'pk':1},
        columns_to_get:{'value1'}
    }
    

    消耗的讀服務能力單元為 1216 Byte 除以 4 KB 向上取整,該 GetRow 操作消耗 1 個單位的讀服務能力單元。

    更多資訊請參見 API Reference 的 GetRow 章節。

多行操作

Table Store提供了 BatchWriteRow 和 BatchGetRow 兩種多行操作。

  • BatchWriteRow 用於插入、修改、刪除一個表或者多個表中的多行記錄。BatchWriteRow 操作由多個 PutRow、UpdateRow、DeleteRow 子操作組成。BatchWriteRow 的各個子操作獨立執行,Table Store會將各個子操作的執行結果分別返回給應用程式,可能存在部分請求成功、部分請求失敗的現象。即使整個請求沒有返回錯誤,應用程式也必須要檢查每個子操作返回的結果,從而拿到正確的狀態。BatchWriteRow 的各個子操作單獨計算寫服務能力單元。

  • BatchGetRow 用於讀取一個表或者多個表中的多行記錄。BatchGetRow 各個子操作獨立執行,Table Store會將各個子操作的執行結果分別返回給應用程式,可能存在部分請求成功、部分請求失敗的現象。即使整個請求沒有返回錯誤,應用程式也必須要檢查每個子操作返回的結果,從而拿到正確的狀態。BatchGetRow 的各個子操作單獨計算讀服務能力單元。

更多資訊請參見 API Reference 中的 BatchWriteRow BatchGetRow 章節。

範圍讀取操作

Table Store提供了範圍讀取操作 GetRange,該操作將指定主鍵範圍內的資料返回給應用程式。

Table Store表中的行按主鍵進行從小到大排序,GetRange 的讀取範圍是一個左閉右開的區間。操作會返回主鍵屬於該區間的行資料,區間的起始點是有效主鍵或者是由 INF_MIN 和 INF_MAX 類型組成的虛擬點,虛擬點的列數必須與主鍵相同。其中,INF_MIN 表示無限小,任何類型的值都比它大;INF_MAX 表示無限大,任何類型的值都比它小。

GetRange 操作需要指定請求列名,請求列名中可以包含多個列名。如果某一行的主鍵屬於讀取的範圍,但是不包含指定返回的列,那麼請求返回結果中不包含該行資料。不指定請求列名,則返回完整的行。

GetRange 操作需要指定讀取方向,讀取方向可以為正序或逆序。假設同一表中有兩個主鍵 A 和 B,A < B。如正序讀取 [A, B),則按從 A 至 B 的順序返回主鍵大於等於 A、小於 B 的行。逆序讀取 [B,A),則按從 B 至 A 的順序返回大於 A、小於等於 B 的資料。

GetRange 操作可以指定最大返回行數。Table Store按照正序或者逆序最多返回指定的行數之後即結束該操作的執行,即使該區間內仍有未返回的資料。

GetRange 操作可能在以下幾種情況下停止執行並返回資料給應用程式:

  • 返回的行資料大小之和達到 4 MB。

  • 返回的行數等於 5000。

  • 返回的行數等於最大返回行數。

  • 當前剩餘的預留讀輸送量已被全部使用,餘量不足以讀取下一條資料。同時 GetRange 請求的返回結果中還包含下一條未讀資料的主鍵,應用程式可以使用該傳回值作為下一次 GetRange 操作的起始點繼續讀取。如果下一條未讀資料的主鍵為空白,表示讀取區間內的資料全部返回。

Table Store計算讀取,區間起始點到下一條未讀資料的起始點的,所有行主鍵資料大小與實際讀取的屬性列資料大小之和。將資料大小之和除以 4 KB 向上取整計算消耗的讀服務能力單元。例如,若讀取範圍中包含 10 行,每行主鍵資料大小與實際讀取到的屬性列資料之和佔用資料大小為 330 Byte,則消耗的讀服務能力單元為 1(資料總和 3.3 KB,除以 4 KB 向上取整為 1)。

樣本

下面舉例說明 GetRange 操作的行為。假設表的內容如下,PK1、PK2 是表的主鍵列,類型分別為 String 和 Integer;Attr1、Attr2 是表的屬性列。

PK1 PK2 Attr1 Attr2
'A' 2 'Hell' 'Bell'
'A' 5 'Hello' 不存在
'A' 6 不存在 'Blood'
'B' 10 'Apple' 不存在
'C' 1 不存在 不存在
'C' 9 'Alpha' 不存在

樣本 1,讀取某一範圍內的資料:

//請求
table_name: "table_name"
direction: FORWARD
inclusive_start_primary_key: ("PK1", STRING, "A"), ("PK2", INTEGER, 2)
exclusive_end_primary_key: ("PK1", STRING, "C"), ("PK2", INTEGER, 1)

//響應
cosumed_read_capacity_unit: 1
rows: {
      {
	    primary_key_columns:("PK1", STRING, "A"), ("PK2", INTEGER, 2)
    	attribute_columns:("Attr1", STRING, "Hell"), ("Attr2", STRING, "Bell")
      },
      {
    	primary_key_columns:("PK1", STRING, "A"), ("PK2", INTEGER, 5)
    	attribute_columns:("Attr1", STRING, "Hello")
      },
      {
    	primary_key_columns:("PK1", STRING, "A"), ("PK2", INTEGER, 6)
    	attribute_columns:("Attr2", STRING, "Blood")
      },
      {
    	primary_key_columns:("PK1", STRING, "B"), ("PK2", INTEGER, 10)
    	attribute_columns:("Attr1", STRING, "Apple")
      }
    }

樣本 2,利用 INF_MIN 和 INF_MAX 讀取全表資料:

//請求
table_name: "table_name"
direction: FORWARD
inclusive_start_primary_key: ("PK1", INF_MIN)
exclusive_end_primary_key: ("PK1", INF_MAX)

//響應
cosumed_read_capacity_unit: 1
rows: {
      {
	    primary_key_columns:("PK1", STRING, "A"), ("PK2", INTEGER, 2)
    	attribute_columns:("Attr1", STRING, "Hell"), ("Attr2", STRING, "Bell")
      },
      {
    	primary_key_columns:("PK1", STRING, "A"), ("PK2", INTEGER, 5)
    	attribute_columns:("Attr1", STRING, "Hello")
      },
      {
    	primary_key_columns:("PK1", STRING, "A"), ("PK2", INTEGER, 6)
    	attribute_columns:("Attr2", STRING, "Blood")
      },
      {
    	primary_key_columns:("PK1", STRING, "B"), ("PK2", INTEGER, 10)
    	attribute_columns:("Attr1", STRING, "Apple")
      }
      {
    	primary_key_columns:("PK1", STRING, "C"), ("PK2", INTEGER, 1)
      }
      {
    	primary_key_columns:("PK1", STRING, "C"), ("PK2", INTEGER, 9)
    	attribute_columns:("Attr1", STRING, "Alpha")
      }
    }

樣本 3,在某些主鍵列上使用 INF_MIN 和 INF_MAX:

//請求
table_name: "table_name"
direction: FORWARD
inclusive_start_primary_key: ("PK1", STRING, "A"), ("PK2", INF_MIN)
exclusive_end_primary_key: ("PK1", STRING, "A"), ("PK2", INF_MAX)

//響應
cosumed_read_capacity_unit: 1
rows: {
      {
	    primary_key_columns:("PK1", STRING, "A"), ("PK2", INTEGER, 2)
    	attribute_columns:("Attr1", STRING, "Hell"), ("Attr2", STRING, "Bell")
      },
      {
    	primary_key_columns:("PK1", STRING, "A"), ("PK2", INTEGER, 5)
    	attribute_columns:("Attr1", STRING, "Hello")
      },
      {
    	primary_key_columns:("PK1", STRING, "A"), ("PK2", INTEGER, 6)
    	attribute_columns:("Attr2", STRING, "Blood")
      }
    }

樣本 4,逆序讀取:

//請求
table_name: "table_name"
direction: BACKWARD
inclusive_start_primary_key: ("PK1", STRING, "C"), ("PK2", INTEGER, 1)
exclusive_end_primary_key: ("PK1", STRING, "A"), ("PK2", INTEGER, 5)

//響應
cosumed_read_capacity_unit: 1
rows: {
      {
	    primary_key_columns:("PK1", STRING, "C"), ("PK2", INTEGER, 1)
      },
      {
    	primary_key_columns:("PK1", STRING, "B"), ("PK2", INTEGER, 10)
    	attribute_columns:("Attr1", STRING, "Apple")
      },
      {
    	primary_key_columns:("PK1", STRING, "A"), ("PK2", INTEGER, 6)
    	attribute_columns:("Attr2", STRING, "Blood")
      }
    }

樣本 5,指定列名不包含 PK:

//請求
table_name: "table_name"
direction: FORWARD
inclusive_start_primary_key: ("PK1", STRING, "C"), ("PK2", INF_MIN)
exclusive_end_primary_key: ("PK1", STRING, "C"), ("PK2", INF_MAX)
columns_to_get: "Attr1"

//響應
cosumed_read_capacity_unit: 1
rows: {
      {
		attribute_columns: {"Attr1", STRING, "Alpha"}
      }
    }

樣本 6,指定列名中包含 PK:

//請求
table_name: "table_name"
direction: FORWARD
inclusive_start_primary_key: ("PK1", STRING, "C"), ("PK2", INF_MIN)
exclusive_end_primary_key: ("PK1", STRING, "C"), ("PK2", INF_MAX)
columns_to_get: "Attr1", "PK1"

//響應
cosumed_read_capacity_unit: 1
rows: {
      {
	    primary_key_columns:("PK1", STRING, "C")
      }
      {
    	primary_key_columns:("PK1", STRING, "C")
    	attribute_columns:("Attr1", STRING, "Alpha")
      }
    }

樣本 7,使用 limit 和斷點:

//請求 1
table_name: "table_name"
direction: FORWARD
inclusive_start_primary_key: ("PK1", STRING, "A"), ("PK2", INF_MIN)
exclusive_end_primary_key: ("PK1", STRING, "A"), ("PK2", INF_MAX)
limit: 2

//響應 1
cosumed_read_capacity_unit: 1
rows: {
      {
	    primary_key_columns:("PK1", STRING, "A"), ("PK2", INTEGER, 2)
    	attribute_columns:("Attr1", STRING, "Hell"), ("Attr2", STRING, "Bell")
      },
      {
    	primary_key_columns:("PK1", STRING, "A"), ("PK2", INTEGER, 5)
    	attribute_columns:("Attr1", STRING, "Hello")
      }
    }
next_start_primary_key:("PK1", STRING, "A"), ("PK2", INTEGER, 6)

//請求 2
table_name: "table_name"
direction: FORWARD
inclusive_start_primary_key: ("PK1", STRING, "A"), ("PK2", INTEGER, 6)
exclusive_end_primary_key: ("PK1", STRING, "A"), ("PK2", INF_MAX)
limit: 2

//響應 2
cosumed_read_capacity_unit: 1
rows: {
      {
	    primary_key_columns:("PK1", STRING, "A"), ("PK2", INTEGER, 6)
    	attribute_columns:("Attr2", STRING, "Blood")
      }
    }

樣本 8,使用 GetRange 操作消耗的讀服務能力單元計算:

在以下表中執行 GetRange 操作,其中 PK 1 是表的主鍵列,Attr1、Attr2 是表的屬性列。

PK1 Attr1 Attr2
1 不存在 String(1000Byte)
2 8 String(1000Byte)
3 String(1000Byte) 不存在
4 String(1000Byte) String(1000Byte)
//請求
table_name: "table2_name"
direction: FORWARD
inclusive_start_primary_key: ("PK1", INTEGER, 1)
exclusive_end_primary_key: ("PK1", INTEGER, 4)
columns_to_get: "PK1", "Attr1"

//響應
cosumed_read_capacity_unit: 1
rows: {
      {
	    primary_key_columns:("PK1", INTEGER, 1)
      },
      {
    	primary_key_columns:("PK1", INTEGER, 2),
    	attribute_columns:("Attr1", INTEGER, 8)
      },
      {
    	primary_key_columns:("PK1", INTEGER, 3),
    	attribute_columns:("Attr1", STRING, String(1000Byte))
      },
    }

此次 GetRange 請求中:

  • 擷取的第一行資料大小為:len ('PK1') + 8 Byte = 11 Byte

  • 第二行資料大小為:len ('PK1') + 8 Byte + len ('Attr1') + 8 Byte = 24 Byte

  • 第三行資料大小為:len ('PK1')+ 8 Byte + len ('Attr1') + 1000 Byte = 1016 Byte

消耗的讀服務能力單元為擷取的三行資料之和 11 Byte + 24 Byte + 1016 Byte = 1051 Byte 除以 4 KB 向上取整,該 GetRange 操作消耗 1 個單位的讀服務能力單元。

更多詳細資料請參見 API Reference 中的 GetRange 章節。

最佳實務

Table Store資料操作的最佳實務

使用Table Store SDK 進行資料操作

使用 TableStore Java SDK 進行資料操作

使用 TableStore Python SDK 進行資料操作