表格存储的表由行组成,每一行包含主键和属性。本节将介绍表格存储数据的操作方法。

表格存储行简介

组成表格存储表的基本单位为行,行由主键和属性组成。其中,主键是必须的,且每一行的主键列的名称和类型相同;属性不是必须的,并且每一行的属性可以不同。更多信息请参见表格存储的模型介绍

表格存储的数据操作有以下三种类型。

  • 单行操作

    • GetRow:读取单行数据。
    • PutRow:新插入一行。如果该行内容已经存在,则先删除旧行,再写入新行。
    • UpdateRow:更新一行。应用可以增加、删除一行中的属性列,或者更新已经存在的属性列的值。如果该行不存在,则新增一行。
    • DeleteRow:删除一行。
  • 批量操作

    • BatchGetRow:批量读取多行数据。
    • BatchWriteRow:批量插入、更新或者删除多行数据。
  • 范围读取

    GetRange:读取表中一个范围内的数据。

表格存储单行操作

  • 单行写入操作

    表格存储的单行写操作有三种:PutRow、UpdateRow和DeleteRow。下面分别介绍每种操作的行为语义和注意事项。

    • PutRow:新写入一行。如果这一行已经存在,则该行旧的数据会被删除,再新写入一行。
    • UpdateRow:更新一行。表格存储会根据请求的内容在这一行中新增列,修改或者删除指定列的值。如果这一行不存在,则会插入新的一行。但是有一种特殊的场景,若UpdateRow请求只包含删除指定的列,且该行不存在,则该请求不会插入新行。
    • DeleteRow:删除一行。如果删除的行不存在,则不会发生任何变化。

    应用程序通过设置请求中的condition字段来指定写入操作执行时,是否需要对行的存在性进行检查。condition有三种类型:

    • IGNORE:不做任何存在性检查。
    • EXPECT_EXIST:期望行存在。如果该行存在,则操作成功;如果该行不存在,则操作失败。
    • EXPECT_NOT_EXIST:期望行不存在。如果该行不存在,则操作成功;如果该行存在,则操作失败。

    condition为EXPECT_NOT_EXIST的DeleteRow、UpdateRow操作是没有意义的,删除一个不存在的行是无意义的。如果需要更新不存在的行可以使用PutRow操作。

    如果操作发生错误,如参数检查失败、单行数据量过多、行存在性检查失败等等,会返回错误码给应用程序。如果操作成功,表格存储会将操作消耗的服务能力单元返回给应用程序。

    各操作消耗的写服务能力单元的计算规则如下。

    • PutRow:本次消耗的写CU为修改的行主键数据大小与属性列数据大小之和除以4 KB向上取整。若指定条件检查不为IGNORE,还需消耗该行主键数据大小除以4 KB向上取整的读CU。如果操作不满足应用程序指定的行存在性检查条件,则操作失败并消耗1个写CU和1个读CU。更多详情请参见PutRow详解。
    • UpdateRow:本次消耗的写CU为修改的行主键数据大小与属性列数据大小之和除以4 KB向上取整。UpdateRow 中包含的需要删除的属性列,只有其列名计入该属性列数据大小。若指定条件检查不为IGNORE,还需消耗该行主键数据大小除以4 KB向上取整的读CU。如果操作不满足应用程序指定的行存在性检查条件,则操作失败并消耗1个写 CU和1个读CU。更多详情请参见UpdateRow详解。
    • DeleteRow:被删除的行主键数据大小除以4 KB向上取整。若指定条件检查不为IGNORE,还需消耗该行主键数据大小除以4 KB向上取整的读CU。如果操作不满足应用程序指定的行存在性检查条件,则操作失败并消耗1个写CU。更多详情请参见DeleteRow详解。

    写操作会根据指定的condition情况消耗一定的读CU。

    示例:

    下面将举例说明单行写操作的写CU和读CU的计算。

    示例 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)}
    }
    					

    读/写服务能力单元(CU)的消耗情况如下。

    • 将condition设置为EXPECT_EXIST时:消耗的写CU为4322 Byte除以4 KB向上取整,消耗的读CU为该行主键数据大小10 Byte除以4 KB向上取整。该PutRow操作消耗2个写CU和1个读CU。
    • 将condition设置为IGNORE时:消耗的写CU为4322 Byte除以4 KB向上取整,消耗0个读CU。该PutRow操作消耗2个写CU和0个读CU。
    • 将condition设置为EXPECT_NOT_EXIST时:指定的行存在性检查条件检查失败,该PutRow操作消耗1个写CU和1个读CU。

    示例 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
    					

    CU的消耗情况如下:

    • 将condition设置为IGNORE时:消耗的写CU为922 Byte除以4 KB向上取整,消耗0个读CU。该UpdateRow操作消耗1个写CU和0个读CU。

    • 将condition设置为EXPECT_EXIST时:指定的行存在性检查条件检查失败,该PutRow操作消耗1个写CU和1个读CU。

    示例 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)}
    }
    					

    CU的消耗情况如下:

    • 将condition设置为EXPECT_EXIST时:消耗的写CU为4322 Byte除以4 KB向上取整,消耗的读CU为该行主键数据大小10 Byte除以4 KB向上取整。该UpdateRow操作消耗2个CU 和1个读CU。

    • 将condition设置为IGNORE时:消耗的写CU为4322 Byte除以4 KB向上取整,消耗0个读CU,该UpdateRow操作消耗2个写CU和0个读CU。

    示例 4,使用DeleteRow删除不存在的行:

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

    修改前后的数据大小均为0,无论读写操作成功还是失败至少消耗1 CU。因此,该DeleteRow操作消耗1个写 CU。

    CU的消耗情况如下:

    • 将condition设置为EXPECT_EXIST时:消耗的写CU为该行主键数据大小10 Byte除以4 KB向上取整,消耗的读CU为该主键数据大小10 Byte除以4 KB向上取整。该DeleteRow操作消耗1个写CU和1个读CU。

    • 将condition设置为IGNORE时:消耗的写CU为该行主键数据大小10 Byte除以4 KB向上取整,消耗0个读CU。该DeleteRow操作消耗1个写CU和0个读CU。

    更多信息请参见API 参考中的PutRowUpdateRowDeleteRow章节。

  • 单行读取操作

    表格存储的单行读操作只有一种:GetRow。

    应用程序提供完整的主键和需要返回的列名。列名可以是主键列或属性列,也可以不指定要返回的列名,此时请求返回整行数据。

    表格存储根据被读取的行主键的数据大小与实际读取的属性列数据大小之和,按4 KB向上取整作为本次读取操作消耗的读CU。如果操作指定的行不存在,则消耗1个读CU,单行读取操作不会消耗写CU。

    使用GetRow读取一行消耗的写CU的计算,示例如下:

    //被读取的行
    
    //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'}
    }
    					

    消耗的读CU为1216 Byte除以4 KB向上取整,该GetRow操作消耗1个读CU。

    更多信息请参见API 参考的GetRow章节。

多行操作

表格存储提供了BatchWriteRow和BatchGetRow两种多行操作。

  • BatchWriteRow用于插入、修改、删除一个表或者多个表中的多行记录。BatchWriteRow操作由多个PutRow、UpdateRow、DeleteRow子操作组成。

    BatchWriteRow的各个子操作独立执行,表格存储会将各个子操作的执行结果分别返回给应用程序。返回结果可能存在部分请求成功、部分请求失败的现象。即使整个请求没有返回错误,应用程序也会检查每个子操作返回的结果,从而拿到正确的状态。BatchWriteRow的各个子操作单独计算写服务能力单元。

  • BatchGetRow用于读取一个表或者多个表中的多行记录。

    BatchGetRow各个子操作独立执行,表格存储会将各个子操作的执行结果分别返回给应用程序。返回结果可能存在部分请求成功、部分请求失败的现象。即使整个请求没有返回错误,应用程序也会检查每个子操作返回的结果,从而拿到正确的状态。

    BatchGetRow的各个子操作单独计算读服务能力单元。

更多信息请参见API 参考中的BatchWriteRowBatchGetRow章节。

范围读取操作

表格存储提供了范围读取操作GetRange,该操作将指定主键范围内的数据返回给应用程序。

表格存储表中的行按主键进行从小到大排序,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操作可以指定最大返回行数。表格存储按照正序或者逆序最多返回指定的行数之后即结束该操作的执行,即使该区间内仍有未返回的数据。

GetRange操作可能在以下几种情况下停止执行并返回数据给应用程序:

  • 返回的行数据大小之和达到4 MB。

  • 返回的行数等于5000。

  • 返回的行数等于最大返回行数。

  • 当前剩余的预留读吞吐量已被全部使用,余量不足以读取下一条数据。同时GetRange请求的返回结果中还包含下一条未读数据的主键,应用程序可以使用该返回值作为下一次GetRange操作的起始点继续读取。如果下一条未读数据的主键为空,表示读取区间内的数据全部返回。

表格存储的读取计算为,从区间起始点到下一条未读数据的起始点,所有行主键数据大小与实际读取的属性列数据大小之和按4 KB向上取整计算消耗的读CU。例如,若读取范围中包含10行,每行主键数据大小与实际读取到的属性列数据之和为330 Byte,则消耗的读CU为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操作消耗的读CU计算:

在以下表中执行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 参考中的GetRange章节。

最佳实践

表格存储数据操作的最佳实践

使用表格存储 SDK 进行数据操作

使用TableStore Java SDK进行数据操作

使用TableStore Python SDK进行数据操作