表格存储提供了单行读取、批量读取和范围读取的查询方式用于读取数据表中数据。当要读取单行数据或者批量读取表中数据时,您必须指定行的完整主键;当要范围读取表中数据时,您需要指定完整主键范围或者主键前缀。读取数据时支持配置返回指定属性列、指定数据版本个数、指定数据时间范围或者满足过滤条件的数据。
如果需要了解表格存储各场景的应用案例,请参见快速玩转Tablestore入门与实战。
查询方式
表格存储提供的数据读取接口包括GetRow、BatchGetRow和GetRange。读取数据时,请根据实际查询场景使用相应查询方式。
当要读取带有自增主键列的表数据时,请确保已获取到包含自增主键列值在内的完整主键。更多信息,请参见主键列自增。如果未记录自增主键列的值,您可以使用范围读取数据按照第一个主键列确定范围读取数据。
查询方式 | 说明 | 适用场景 |
调用GetRow接口读取一行数据。 | 适用于能确定完整主键且要读取行数较少的场景。 | |
调用BatchGetRow接口一次请求读取多行数据或者一次对多张表进行读取。 BatchGetRow操作由多个GetRow子操作组成,构造子操作的过程与使用GetRow接口时相同。 | 适用于能确定完整主键,且要读取行数较多或者要读取多个表中数据的场景。 | |
调用GetRange接口读取一个范围内的数据。 GetRange操作支持按照确定范围进行正序读取和逆序读取,可以设置要读取的行数。如果范围较大,已扫描的行数或者数据量超过一定限制,会停止扫描,并返回已获取的行和下一个主键信息。您可以根据返回的下一个主键信息,继续发起请求,获取范围内剩余的行。 | 适用于能确定完整主键范围或者主键前缀的场景。 重要 如果不能确定主键前缀,您也可以通过设置完整主键范围均为虚拟点INF_MIN和INF_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 | 读取的列集合,列名可以是主键列或属性列。
说明
|
column_filter | 使用过滤器,在服务端对读取结果再进行一次过滤,只返回符合过滤器中条件的数据行。更多信息,请参见过滤器。 说明 当columns_to_get和column_filter同时使用时,执行顺序是先获取columns_to_get指定的列,再在返回的列中进行条件过滤。 |
max_version | 最多读取的版本数。 重要 max_version与time_range必须至少设置一个。
|
time_range | 读取版本号范围或特定版本号的数据。更多信息,请参见TimeRange。 重要 max_version与time_range必须至少设置一个。
specific_time和 时间戳的单位为毫秒,最小值为0,最大值为 |
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 | 读取方向。
假设同一表中有两个主键A和B,A小于B,如果正序读取 |
inclusive_start_primary_key | 本次范围读的起始主键和结束主键,起始主键和结束主键需要是有效的主键或者是由INF_MIN和INF_MAX类型组成的虚拟点,虚拟点的列数必须与主键相同。 其中INF_MIN表示无限小,任何类型的值都比它大;INF_MAX表示无限大,任何类型的值都比它小。
数据表中的行按主键从小到大排序,读取范围是一个左闭右开的区间,正序读取时,返回的是大于等于起始主键且小于结束主键的所有的行。 |
exclusive_end_primary_key | |
limit | 数据的最大返回行数,此值必须大于 0。 表格存储按照正序或者逆序返回指定的最大返回行数后即结束该操作的执行,即使该区间内仍有未返回的数据。此时可以通过返回结果中的next_start_primary_key记录本次读取到的位置,用于下一次读取。 |
columns_to_get | 读取的列集合,列名可以是主键列或属性列。
说明
|
max_version | 最多读取的版本数。 重要 max_version与time_range必须至少设置一个。
|
time_range | 读取版本号范围或特定版本号的数据。更多信息,请参见TimeRange。 重要 max_version与time_range必须至少设置一个。
specific_time和 时间戳的单位为毫秒,最小值为0,最大值为 |
column_filter | 使用过滤器,在服务端对读取结果再进行一次过滤,只返回符合过滤器中条件的数据行。更多信息,请参见过滤器。 说明 当columns_to_get和column_filter同时使用时,执行顺序是先获取columns_to_get指定的列,再在返回的列中进行条件过滤。 |
next_start_primary_key | 根据返回结果中的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。