读取数据

表格存储提供了单行读取、批量读取和范围读取的查询方式用于读取数据表中数据。当要读取单行数据或者批量读取表中数据时,您必须指定行的完整主键;当要范围读取表中数据时,您需要指定完整主键范围或者主键前缀。读取数据时支持配置返回指定属性列、指定数据版本个数、指定数据时间范围或者满足过滤条件的数据。

如果需要了解表格存储各场景的应用案例,请参见快速玩转Tablestore入门与实战

查询方式

表格存储提供的数据读取接口包括GetRow、BatchGetRowGetRange。读取数据时,请根据实际查询场景使用相应查询方式。

重要

当要读取带有自增主键列的表数据时,请确保已获取到包含自增主键列值在内的完整主键。更多信息,请参见主键列自增。如果未记录自增主键列的值,您可以使用范围读取数据按照第一个主键列确定范围读取数据。

查询方式

说明

适用场景

读取单行数据

调用GetRow接口读取一行数据。

适用于能确定完整主键且要读取行数较少的场景。

批量读取数据

调用BatchGetRow接口一次请求读取多行数据或者一次对多张表进行读取。

BatchGetRow操作由多个GetRow子操作组成,构造子操作的过程与使用GetRow接口时相同。

适用于能确定完整主键,且要读取行数较多或者要读取多个表中数据的场景。

范围读取数据

调用GetRange接口读取一个范围内的数据。

GetRange操作支持按照确定范围进行正序读取和逆序读取,可以设置要读取的行数。如果范围较大,已扫描的行数或者数据量超过一定限制,会停止扫描,并返回已获取的行和下一个主键信息。您可以根据返回的下一个主键信息,继续发起请求,获取范围内剩余的行。

适用于能确定完整主键范围或者主键前缀的场景。

重要

如果不能确定主键前缀,您也可以通过设置完整主键范围均为虚拟点INF_MININF_MAX进行全表数据扫描,但是执行此操作会消耗较多计算资源,请谨慎使用。

前提条件

  • 已初始化Client。具体操作,请参见初始化OTSClient

  • 已创建数据表并写入数据。

读取单行数据

调用GetRow接口读取一行数据。读取的结果可能有如下两种:

  • 如果该行存在,则返回该行的各主键列以及属性列。

  • 如果该行不存在,则返回中不包含行,并且不会报错。

接口

"""
说明:获取一行数据。
``table_name``是对应的表名。
``primary_key``是主键,类型为dict。
``columns_to_get``是可选参数,表示要获取的列的名称列表,类型为list;如果不填,表示获取所有列。
``column_filter``是可选参数,表示读取指定条件的行
``max_version``是可选参数,表示最多读取的版本数
``time_range``是可选参数,表示读取额版本范围或特定版本,和max_version至少存在一个
返回:本次操作消耗的CapacityUnit、主键列和属性列。
``consumed``表示消耗的CapacityUnit,是tablestore.metadata.CapacityUnit类的实例。
``return_row``表示行数据,包括主键列和属性列,类型都为list,如:[('PK0',value0), ('PK1',value1)]。
``next_token``表示宽行读取时下一次读取的位置,编码的二进制。
示例:
    primary_key = [('gid',1), ('uid',101)]
    columns_to_get = ['name', 'address', 'age']
    consumed, return_row, next_token = client.get_row('myTable', primary_key, columns_to_get)
"""
def get_row(self, table_name, primary_key, columns_to_get=None,
            column_filter=None, max_version=1, time_range=None,
            start_column=None, end_column=None, token=None,
            transaction_id=None):

参数

参数

说明

table_name

数据表名称。

primary_key

行的主键。主键包括主键列名、主键类型和主键值。

重要

设置的主键个数和类型必须和数据表的主键个数和类型一致。

columns_to_get

读取的列集合,列名可以是主键列或属性列。

  • 如果不设置返回的列名,则返回整行数据。

  • 如果设置了返回的列名,当某行中指定的列均不存在时,则不返回该行,即返回值为null;当某行中存在部分指定的列时,则返回该行且只返回存在的列。

说明
  • 查询一行数据时,默认返回此行所有列的数据。如果需要只返回特定列,可以通过设置columns_to_get参数限制。如果将col0col1加入到columns_to_get中,则只返回col0col1列的值。

  • columns_to_getcolumn_filter同时使用时,执行顺序是先获取columns_to_get指定的列,再在返回的列中进行条件过滤。

column_filter

使用过滤器,在服务端对读取结果再进行一次过滤,只返回符合过滤器中条件的数据行。更多信息,请参见过滤器

说明

columns_to_getcolumn_filter同时使用时,执行顺序是先获取columns_to_get指定的列,再在返回的列中进行条件过滤。

max_version

最多读取的版本数。

重要

max_versiontime_range必须至少设置一个。

  • 如果仅设置max_version,则最多返回所有版本中从新到旧指定数量版本的数据。

  • 如果仅设置time_range,则返回该范围内所有数据或指定版本数据。

  • 如果同时设置max_versiontime_range,则最多返回版本号范围内从新到旧指定数量版本的数据。

time_range

读取版本号范围或特定版本号的数据。更多信息,请参见TimeRange

重要

max_versiontime_range必须至少设置一个。

  • 如果仅设置max_version,则最多返回所有版本中从新到旧指定数量版本的数据。

  • 如果仅设置time_range,则返回该范围内所有数据或指定版本数据。

  • 如果同时设置max_versiontime_range,则最多返回版本号范围内从新到旧指定数量版本的数据。

  • 如果要查询一个范围的数据,则需要设置start_timeend_time。start_timeend_time分别表示起始时间戳和结束时间戳,范围为前闭后开区间,即[start_time, end_time)

  • 如果要查询特定版本号的数据,则需要设置specific_time。specific_time表示特定的时间戳。

specific_time[start_time, end_time)中只需要设置一个。

时间戳的单位为毫秒,最小值为0,最大值为INT64.MAX

transaction_id

局部事务ID。使用局部事务功能读取数据时必须设置此参数。

示例

以下示例用于读取表中一行数据。

# 主键的第一列是gid,值是整数1,第二列是uid,值是整数101。
primary_key = [('gid', 1), ('uid', 101)]

# 需要返回的属性列name、growth、type。如果columns_to_get为[],则返回所有属性列。
columns_to_get = ['name', 'growth', 'type']

# 设置过滤器,增加列条件。过滤条件为growth列值不等于0.9且name列值等于'杭州'。
cond = CompositeColumnCondition(LogicalOperator.AND)
cond.add_sub_condition(SingleColumnCondition("growth", 0.9, ComparatorType.NOT_EQUAL))
cond.add_sub_condition(SingleColumnCondition("name", '杭州', ComparatorType.EQUAL))

try:
    # 调用get_row接口查询数据。
    # 配置数据表名称,最后一个参数值1表示只需要返回一个版本的值。
    consumed, return_row, next_token = client.get_row('<table_name>', primary_key, columns_to_get, cond, 1)
    print('Read succeed, consume %s read cu.' % consumed.read)
    print('Value of primary key: %s' % return_row.primary_key)
    print('Value of attribute: %s' % return_row.attribute_columns)
    for att in return_row.attribute_columns:
        # 打印每一列的key、value和version值。
        print('name:%s\tvalue:%s\ttimestamp:%d' % (att[0], att[1], att[2]))
# 客户端异常,一般为参数错误或者网络异常。
except OTSClientError as e:
    print('get row failed, http_status:%d, error_message:%s' % (e.get_http_status(), e.get_error_message()))
# 服务端异常,一般为参数错误或者流控错误。
except OTSServiceError as e:
    print('get row failed, http_status:%d, error_code:%s, error_message:%s, request_id:%s' % (e.get_http_status(), e.get_error_code(), e.get_error_message(), e.get_request_id()))

详细代码请参见GetRow@GitHub

批量读取数据

调用BatchGetRow接口一次请求读取多行数据,也支持一次对多张表进行读取。BatchGetRow由多个GetRow子操作组成。构造子操作的过程与使用GetRow接口时相同。

BatchGetRow的各个子操作独立执行,表格存储会分别返回各个子操作的执行结果。

注意事项

  • 由于批量读取可能存在部分行失败的情况,失败行的错误信息在返回的BatchGetRowResponse中,但并不抛出异常。因此调用BatchGetRow接口时,需要检查返回值,判断每行的状态是否成功。

  • 批量读取的所有行采用相同的参数条件,例如ColumnsToGet=[colA],表示要读取的所有行都只读取colA列。

  • BatchGetRow操作单次支持读取的最大行数为100行。

接口

"""
说明:批量获取多行数据。
request = BatchGetRowRequest()
request.add(TableInBatchGetRowItem(myTable0, primary_keys, column_to_get=None, column_filter=None))
request.add(TableInBatchGetRowItem(myTable1, primary_keys, column_to_get=None, column_filter=None))
request.add(TableInBatchGetRowItem(myTable2, primary_keys, column_to_get=None, column_filter=None))
request.add(TableInBatchGetRowItem(myTable3, primary_keys, column_to_get=None, column_filter=None))
response = client.batch_get_row(request)
``response``为返回的结果,类型为tablestore.metadata.BatchGetRowResponse。
"""
def batch_get_row(self, request):                    
  

参数

更多信息,请参见读取单行数据参数

示例

以下示例用于批量一次读取多个表中的3行数据。

# 设置需要返回的列。
columns_to_get = ['name', 'mobile', 'address', 'age']
# 读取3行。
rows_to_get = []
for i in range(0, 3):
    primary_key = [('gid', i), ('uid', i + 1)]
    rows_to_get.append(primary_key)

# 设置过滤器,增加列条件。过滤条件为name列值等于'John'且address列值等于'China'。
cond = CompositeColumnCondition(LogicalOperator.AND)
cond.add_sub_condition(SingleColumnCondition("name", "John", ComparatorType.EQUAL))
cond.add_sub_condition(SingleColumnCondition("address", 'China', ComparatorType.EQUAL))

# 构造批量读请求。
request = BatchGetRowRequest()

# 增加指定表中需要读取的行,最后一个参数1表示读取最新的一个版本。
request.add(TableInBatchGetRowItem('<table_name1>', rows_to_get, columns_to_get, cond, 1))

# 增加另一个表中需要读取的行。
request.add(TableInBatchGetRowItem('<table_name2>', rows_to_get, columns_to_get, cond, 1))

try:
    result = client.batch_get_row(request)
    print('Result status: %s' % (result.is_all_succeed()))

    table_result_0 = result.get_result_by_table('<table_name1>')
    table_result_1 = result.get_result_by_table('<table_name2>')
    print('Check first table\'s result:')
    for item in table_result_0:
        if item.is_ok:
            print('Read succeed, PrimaryKey: %s, Attributes: %s' % (item.row.primary_key, item.row.attribute_columns))
        else:
            print('Read failed, error code: %s, error message: %s' % (item.error_code, item.error_message))
    print('Check second table\'s result:')
    for item in table_result_1:
        if item.is_ok:
            print('Read succeed, PrimaryKey: %s, Attributes: %s' % (item.row.primary_key, item.row.attribute_columns))
        else:
            print('Read failed, error code: %s, error message: %s' % (item.error_code, item.error_message))
# 客户端异常,一般为参数错误或者网络异常。
except OTSClientError as e:
    print('get row failed, http_status:%d, error_message:%s' % (e.get_http_status(), e.get_error_message()))
# 服务端异常,一般为参数错误或者流控错误。
except OTSServiceError as e:
    print('get row failed, http_status:%d, error_code:%s, error_message:%s, request_id:%s' % (e.get_http_status(), e.get_error_code(), e.get_error_message(), e.get_request_id()))

详细代码请参见BatchGetRow@GitHub

范围读取数据

调用GetRange接口读取一个范围内的数据。

GetRange操作支持按照确定范围进行正序读取和逆序读取,可以设置要读取的行数。如果范围较大,已扫描的行数或者数据量超过一定限制,会停止扫描,并返回已获取的行和下一个主键信息。您可以根据返回的下一个主键信息,继续发起请求,获取范围内剩余的行。

说明

表格存储表中的行都是按照主键排序的,而主键是由全部主键列按照顺序组成的,所以不能理解为表格存储会按照某列主键排序,这是常见的误区。

注意事项

GetRange操作遵循最左匹配原则,读取数据时,依次比较第一主键列到第四主键列。例如表的主键包括PK1、PK2、PK3三个主键列,读取数据时,优先比较PK1是否在开始主键与结束主键的范围内,如果PK1在设置的主键范围内,则不会再比较其他的主键,返回在PK1主键范围内的数据;如果PK1在设置的主键边界上,则继续比较PK2是否在开始主键与结束主键的范围内,以此类推。关于范围查询原理的更多信息,请参见GetRange范围查询详解

GetRange操作可能在如下情况停止执行并返回数据。

  • 扫描的行数据大小之和达到4 MB。

  • 扫描的行数等于5000。

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

  • 当前剩余的预留读吞吐量已全部使用,余量不足以读取下一条数据。

当使用GetRange扫描的数据量较大时,表格存储每次请求仅会扫描一次(行数大于5000或者大小大于4 MB停止扫描),超过限制的数据不会继续返回,需要通过翻页继续获取后面的数据。

接口

"""
说明:根据范围条件获取多行数据。
``table_name``是数据表名称。
``direction``表示范围读取的读取方向,字符串格式,取值包括'FORWARD'和'BACKWARD'。
``inclusive_start_primary_key``表示范围的起始主键(在范围内)。
``exclusive_end_primary_key``表示范围的结束主键(不在范围内)。
``columns_to_get``是可选参数,表示要获取的列的名称列表,类型为list;如果不填,表示获取所有列。
``limit``是可选参数,表示最多读取多少行;如果不填,则没有限制。
``column_filter``是可选参数,表示读取指定条件的行。
``max_version``是可选参数,表示返回的最大版本数目,max_version与time_range必须至少存在一个。
``time_range``是可选参数,表示返回的版本的范围,max_version与time_range必须至少存在一个。
``start_column``是可选参数,用于宽行读取,表示本次读取的起始列。
``end_column``是可选参数,用于宽行读取,表示本次读取的结束列。
``token``是可选参数,用于宽行读取,表示本次读取的起始列位置,内容被二进制编码,来源于上次请求的返回结果中。

返回:符合条件的结果列表。
``consumed``表示本次操作消耗的CapacityUnit,是tablestore.metadata.CapacityUnit类的实例。
``next_start_primary_key``表示下次get_range操作的起始点的主健列,类型为dict。
``row_list``表示本次操作返回的行数据列表,格式为:[Row, ...]。  
"""
def get_range(self, table_name, direction,
             inclusive_start_primary_key,
             exclusive_end_primary_key,
             columns_to_get=None,
             limit=None,
             column_filter=None,
             max_version=None,
             time_range=None,
             start_column=None,
             end_column=None,
             token=None):

参数

参数

说明

table_name

数据表名称。

direction

读取方向。

  • 如果值为正序(FORWARD),则起始主键必须小于结束主键,返回的行按照主键由小到大的顺序进行排列。

  • 如果值为逆序(BACKWARD),则起始主键必须大于结束主键,返回的行按照主键由大到小的顺序进行排列。

假设同一表中有两个主键AB,A小于B,如果正序读取[A, B),则按从AB的顺序返回主键大于等于A且小于B的行数据;如果逆序读取[B, A),则按从BA的顺序返回大于A且小于等于B的行数据。

inclusive_start_primary_key

本次范围读的起始主键和结束主键,起始主键和结束主键需要是有效的主键或者是由INF_MININF_MAX类型组成的虚拟点,虚拟点的列数必须与主键相同。

其中INF_MIN表示无限小,任何类型的值都比它大;INF_MAX表示无限大,任何类型的值都比它小。

  • inclusive_start_primary_key表示起始主键,如果该行存在,则返回结果中一定会包含此行。

  • exclusive_end_primary_key表示结束主键,无论该行是否存在,返回结果中都不会包含此行。

数据表中的行按主键从小到大排序,读取范围是一个左闭右开的区间,正序读取时,返回的是大于等于起始主键且小于结束主键的所有的行。

exclusive_end_primary_key

limit

数据的最大返回行数,此值必须大于 0。

表格存储按照正序或者逆序返回指定的最大返回行数后即结束该操作的执行,即使该区间内仍有未返回的数据。此时可以通过返回结果中的next_start_primary_key记录本次读取到的位置,用于下一次读取。

columns_to_get

读取的列集合,列名可以是主键列或属性列。

  • 如果不设置返回的列名,则返回整行数据。

  • 如果设置了返回的列名,当某行中指定的列均不存在时,则不返回该行,即返回值为null;当某行中存在部分指定的列时,则返回该行且只返回存在的列。

说明
  • 查询一行数据时,默认返回此行所有列的数据。如果需要只返回特定列,可以通过设置columns_to_get参数限制。如果将col0col1加入到columns_to_get中,则只返回col0col1列的值。

  • 如果某行数据的主键属于读取范围,但是该行数据不包含指定返回的列,那么返回结果中不包含该行数据。

  • columns_to_getcolumn_filter同时使用时,执行顺序是先获取columns_to_get指定的列,再在返回的列中进行条件过滤。

max_version

最多读取的版本数。

重要

max_versiontime_range必须至少设置一个。

  • 如果仅设置max_version,则最多返回所有版本中从新到旧指定数量版本的数据。

  • 如果仅设置time_range,则返回该范围内所有数据或指定版本数据。

  • 如果同时设置max_versiontime_range,则最多返回版本号范围内从新到旧指定数量版本的数据。

time_range

读取版本号范围或特定版本号的数据。更多信息,请参见TimeRange

重要

max_versiontime_range必须至少设置一个。

  • 如果仅设置max_version,则最多返回所有版本中从新到旧指定数量版本的数据。

  • 如果仅设置time_range,则返回该范围内所有数据或指定版本数据。

  • 如果同时设置max_versiontime_range,则最多返回版本号范围内从新到旧指定数量版本的数据。

  • 如果要查询一个范围的数据,则需要设置start_timeend_time。start_timeend_time分别表示起始时间戳和结束时间戳,范围为前闭后开区间,即[start_time, end_time)

  • 如果要查询特定版本号的数据,则需要设置specific_time。specific_time表示特定的时间戳。

specific_time[start_time, end_time)中只需要设置一个。

时间戳的单位为毫秒,最小值为0,最大值为INT64.MAX

column_filter

使用过滤器,在服务端对读取结果再进行一次过滤,只返回符合过滤器中条件的数据行。更多信息,请参见过滤器

说明

columns_to_getcolumn_filter同时使用时,执行顺序是先获取columns_to_get指定的列,再在返回的列中进行条件过滤。

next_start_primary_key

根据返回结果中的next_start_primary_key判断数据是否全部读取。

  • 当返回结果中next_start_primary_key不为空时,可以使用此返回值作为下一次GetRange操作的起始点继续读取数据。

  • 当返回结果中next_start_primary_key为空时,表示读取范围内的数据全部返回。

示例

以下示例用于按照第一个主键列确定范围、第二个主键列从最小值(INF_MIN)到最大值(INF_MAX)进行正序读取,判断nextStartPrimaryKey是否为null,读取完范围内的全部数据。

# 设置范围读的起始主键。
inclusive_start_primary_key = [('gid', 1), ('uid', INF_MIN)]

# 设置范围读的结束主键。
exclusive_end_primary_key = [('gid', 5), ('uid', INF_MAX)]

# 查询所有列。
columns_to_get = []

# 每次最多返回90行,如果总共有100个结果,首次查询时指定limit=90,则第一次最多返回90,最少可能返回0个结果,但是next_start_primary_key不为None。
limit = 90

# 设置过滤器,增加列条件。过滤条件为address列值等于'China'且age列值小于50。
cond = CompositeColumnCondition(LogicalOperator.AND)
# 如果某行不存在对应列时,您需要配置pass_if_missing参数来确定该行是否满足过滤条件。
# 当不设置pass_if_missing或者设置pass_if_missing为True时,表示当某行不存在该列时,该行满足过滤条件。
# 当设置pass_if_missing为False时,表示当某行不存在该列时,该行不满足过滤条件。
cond.add_sub_condition(SingleColumnCondition("address", 'China', ComparatorType.EQUAL, pass_if_missing = False))
cond.add_sub_condition(SingleColumnCondition("age", 50, ComparatorType.LESS_THAN, pass_if_missing = False))

try:
    # 调用get_range接口。
    consumed, next_start_primary_key, row_list, next_token = client.get_range(
        '<table_name>', Direction.FORWARD,
        inclusive_start_primary_key, exclusive_end_primary_key,
        columns_to_get,
        limit,
        column_filter=cond,
        max_version=1,
        time_range = (1557125059000, 1557129059000)  # start_time大于等于1557125059000,end_time小于1557129059000。
    )

    all_rows = []
    all_rows.extend(row_list)

    # 当next_start_primary_key不为空时,则继续读取数据。
    while next_start_primary_key is not None:
        inclusive_start_primary_key = next_start_primary_key
        consumed, next_start_primary_key, row_list, next_token = client.get_range(
            '<table_name>', Direction.FORWARD,
            inclusive_start_primary_key, exclusive_end_primary_key,
            columns_to_get, limit,
            column_filter=cond,
            max_version=1
        )
        all_rows.extend(row_list)

    # 打印主键和属性列。
    for row in all_rows:
        print(row.primary_key, row.attribute_columns)
    print('Total rows: ', len(all_rows))
# 客户端异常,一般为参数错误或者网络异常。
except OTSClientError as e:
    print('get row failed, http_status:%d, error_message:%s' % (e.get_http_status(), e.get_error_message()))
# 服务端异常,一般为参数错误或者流控错误。
except OTSServiceError as e:
    print('get row failed, http_status:%d, error_code:%s, error_message:%s, request_id:%s' % (e.get_http_status(), e.get_error_code(), e.get_error_message(), e.get_request_id()))

详细代码请参见GetRange@GitHub

常见问题

相关文档

  • 如果要使用索引技术加速数据查询,您可以通过二级索引或者多元索引功能实现。更多信息,请参见二级索引或者多元索引

  • 如果要可视化展示表中数据,您可以通过对接DataV或者Grafana工具实现。更多信息,请参见数据可视化

  • 如果要下载表中数据到本地,您可以通过DataX、表格存储命令行CLI工具实现。更多信息,请参见将表格存储数据下载到本地文件

  • 如果要计算与分析表中数据,您可以通过表格存储SQL查询实现。更多信息,请参见SQL查询

    说明

    您还可以通过MaxCompute、Spark、Hive或者HadoopMR、函数计算、Flink等计算引擎实现表中数据的计算与分析。具体操作,请参见计算与分析