全部产品
Search
文档中心

表格存储:读取数据

更新时间:Oct 07, 2023

表格存储提供了GetRow接口用于读取单行数据以及BatchGetRow、GetRange等接口用于读取多行数据。

查询方式

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

重要

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

查询方式

说明

适用场景

读取单行数据

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

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

批量读取数据

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

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

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

范围读取数据

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

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

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

重要

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

迭代读取数据

调用GetRangeIterator接口迭代读取数据。

适用于能确定完整主键范围或者主键前缀,且需要迭代读取的场景。

前提条件

  • 已初始化Client,详情请参见初始化
  • 已创建数据表并写入数据。

读取单行数据

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

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

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

接口

/// <summary>
/// 根据给定的主键读取单行数据。
/// </summary>
/// <param name="request">查询数据的请求</param>
/// <returns>GetRow的响应</returns>
public GetRowResponse GetRow(GetRowRequest request);

/// <summary>
/// GetRow的异步形式。
/// </summary>
public Task<GetRowResponse> GetRowAsync(GetRowRequest request);          

参数

参数

说明

tableName

数据表名称。

primaryKey

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

重要

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

columnsToGet

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

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

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

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

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

maxVersions

最多读取的版本数。

重要

maxVersions与timeRange必须至少设置一个。

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

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

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

timeRange

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

重要

maxVersions与timeRange必须至少设置一个。

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

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

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

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

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

SpecificTime和[StartTime, EndTime)中只需要设置一个。

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

filter

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

说明

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

示例

读取一行数据

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

    //定义行的主键,必须与创建表时的TableMeta中定义的一致。
    PrimaryKey primaryKey = new PrimaryKey();
    primaryKey.Add("pk0", new ColumnValue(0));
    primaryKey.Add("pk1", new ColumnValue("abc"));

    try
    {
        //构造查询请求对象,此处未指定读取的列,默认读取整行数据。
        var request = new GetRowRequest(TableName, primaryKey);

        //调用GetRow接口查询数据。
        var response = otsClient.GetRow(request);

        //输出此行的数据,此处省略,详见示例代码的GitHub链接。

        //如果没有抛出异常,则说明执行成功。
        Console.WriteLine("Get row succeeded.");
    }
    catch (Exception ex)
    {
        //如果抛出异常,则说明执行失败,处理异常。
        Console.WriteLine("Update table failed, exception:{0}", ex.Message);
    }
            

详细代码请参见GetRow@GitHub

使用过滤器读取一行数据

使用过滤器读取一行数据。

以下示例用于查询数据后只返回col0和col1的数据,同时在col0列和col1列进行过滤。过滤条件是col0等于5或者col1不等于ff。

    //定义行的主键,必须与创建表时的TableMeta中定义的一致。
    PrimaryKey primaryKey = new PrimaryKey();
    primaryKey.Add("pk0", new ColumnValue(0));
    primaryKey.Add("pk1", new ColumnValue("abc"));

    var rowQueryCriteria = new SingleRowQueryCriteria("SampleTable");
    rowQueryCriteria.RowPrimaryKey = primaryKey;

    //条件1为col0列的值等于5。
    var filter1 = new RelationalCondition("col0",
                RelationalCondition.CompareOperator.EQUAL,
                new ColumnValue(5));

    //条件2为col1列的值不等于ff。
    var filter2 = new RelationalCondition("col1", RelationalCondition.CompareOperator.NOT_EQUAL, new ColumnValue("ff"));

    //构造组合条件,包括条件1和条件2,关系是OR。
    var filter = new CompositeCondition(CompositeCondition.LogicOperator.OR);
    filter.AddCondition(filter1);
    filter.AddCondition(filter2);

    rowQueryCriteria.Filter = filter;

    //设置要查询和返回的行,查询和过滤的顺序是先在行的[col0,col1]列上查询,然后再按条件过滤。
    rowQueryCriteria.AddColumnsToGet("col0");
    rowQueryCriteria.AddColumnsToGet("col1");

    //构造GetRowRequest。
    var request = new GetRowRequest(rowQueryCriteria);

    try
    {
        //查询。
        var response = otsClient.GetRow(request);

        //输出数据或者相关逻辑操作,此处省略。

        //如果没有抛出异常,则说明执行成功。
        Console.WriteLine("Get row with filter succeeded.");
    }
    catch (Exception ex)
    {
        //如果抛出异常,则说明执行失败,处理异常。
        Console.WriteLine("Get row with filter failed, exception:{0}", ex.Message);
    }          

详细代码请参见GetRowWithFilter@GitHub

批量读取数据

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

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

注意事项

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

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

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

接口

/// <summary>
/// <para>批量读取一个或多个表中的若干行数据。</para>
/// <para>BatchGetRow操作可视为多个GetRow操作的集合,各个操作独立执行,独立返回结果,独立计算服务能力单元。</para>
/// 与执行大量的GetRow操作相比,使用BatchGetRow操作可以有效减少请求的响应时间,提高数据的读取速率。
/// </summary>
/// <param name="request">请求实例</param>
/// <returns>响应实例</returns>
public BatchGetRowResponse BatchGetRow(BatchGetRowRequest request);

/// <summary>
/// BatchGetRow的异步形式。
/// </summary>
public Task<BatchGetRowResponse> BatchGetRowAsync(BatchGetRowRequest request);            

示例

以下示例用于批量一次读取10行。

//构造批量读的请求对象,设置10行数据的主键。
List<PrimaryKey> primaryKeys = new List<PrimaryKey>();
for (int i = 0; i < 10; i++)
{
    PrimaryKey primaryKey = new PrimaryKey();
    primaryKey.Add("pk0", new ColumnValue(i));
    primaryKey.Add("pk1", new ColumnValue("abc"));
    primaryKeys.Add(primaryKey);
}

try
{
    BatchGetRowRequest request = new BatchGetRowRequest();
    request.Add(TableName, primaryKeys);

    //调用BatchGetRow接口查询10行数据。
    var response = otsClient.BatchGetRow(request);
    var tableRows = response.RowDataGroupByTable;
    var rows = tableRows[TableName];

    //输出rows中的数据,此处省略,详见示例代码的GitHub链接。

    //批量操作可能部分成功部分失败,需要检查每行的状态是否成功,详见示例代码的GitHub链接。
}
catch (Exception ex)
{
    //如果抛出异常,则说明执行失败,处理异常。
    Console.WriteLine("Batch get row failed, exception:{0}", ex.Message);
}            

详细代码请参见BatchGetRow@GitHub

范围读取数据

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

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

说明

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

注意事项

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

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

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

  • 扫描的行数等于5000。

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

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

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

接口

/// <summary>
/// 根据范围条件获取多行数据。
/// </summary>
/// <param name="request">请求实例</param>
/// <returns>响应实例</returns>
public GetRangeResponse GetRange(GetRangeRequest request);

/// <summary>
/// GetRange的异步版本。
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
public Task<GetRangeResponse> GetRangeAsync(GetRangeRequest request);              

参数

参数

说明

tableName

数据表名称。

direction

读取方向。

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

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

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

inclusiveStartPrimaryKey

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

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

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

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

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

exclusiveEndPrimaryKey

limit

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

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

columnsToGet

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

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

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

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

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

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

maxVersions

最多读取的版本数。

重要

maxVersions与timeRange必须至少设置一个。

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

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

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

timeRange

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

重要

maxVersions与timeRange必须至少设置一个。

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

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

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

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

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

SpecificTime和[StartTime, EndTime)中只需要设置一个。

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

filter

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

说明

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

nextStartPrimaryKey

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

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

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

示例

以下示例用于按照范围读取数据。

//读取(0, INF_MIN)到(100, INF_MAX)范围内的所有行。
var inclusiveStartPrimaryKey = new PrimaryKey();
inclusiveStartPrimaryKey.Add("pk0", new ColumnValue(0));
inclusiveStartPrimaryKey.Add("pk1", ColumnValue.INF_MIN);

var exclusiveEndPrimaryKey = new PrimaryKey();
exclusiveEndPrimaryKey.Add("pk0", new ColumnValue(100));
exclusiveEndPrimaryKey.Add("pk1", ColumnValue.INF_MAX);

try
{
    //构造范围读的请求对象。
    var request = new GetRangeRequest(TableName, GetRangeDirection.Forward,
                    inclusiveStartPrimaryKey, exclusiveEndPrimaryKey);

    var response = otsClient.GetRange(request);

    //如果一次没有返回所有数据,则需要继续查询。
    var rows = response.RowDataList;
    var nextStartPrimaryKey = response.NextPrimaryKey;
    while (nextStartPrimaryKey != null)
    {
        request = new GetRangeRequest(TableName, GetRangeDirection.Forward,
                        nextStartPrimaryKey, exclusiveEndPrimaryKey);
        response = otsClient.GetRange(request);
        nextStartPrimaryKey = response.NextPrimaryKey;
        foreach (RowDataFromGetRange row in response.RowDataList)
        {
            rows.Add(row);
        }
    }

    //输出rows中的数据,此处省略,详见示例代码的GitHub链接。

    //如果没有抛出异常,则说明执行成功。
    Console.WriteLine("Get range succeeded");
}
catch (Exception ex)
{
    //如果抛出异常,则说明执行失败,处理异常。
    Console.WriteLine("Get range failed, exception:{0}", ex.Message);
}            

详细代码请参见GetRange@GitHub

迭代读取数据

调用GetRangeIterator接口迭代读取数据。

接口

/// <summary>
/// 根据范围条件获取多行数据,返回用来迭代每一行数据的迭代器。
/// </summary>
/// <param name="request"><see cref="GetIteratorRequest"/></param>
/// <returns>返回<see cref="RowDataFromGetRange"/>的迭代器。</returns>
public IEnumerable<RowDataFromGetRange> GetRangeIterator(GetIteratorRequest request);           

示例

以下示例用于迭代读取(0, "a")(1000, "xyz")范围内的所有行。

//读取(0, "a")到(1000, "xyz")范围内的所有行。
PrimaryKey inclusiveStartPrimaryKey = new PrimaryKey();
inclusiveStartPrimaryKey.Add("pk0", new ColumnValue(0));
inclusiveStartPrimaryKey.Add("pk1", new ColumnValue("a"));

PrimaryKey exclusiveEndPrimaryKey = new PrimaryKey();
exclusiveEndPrimaryKey.Add("pk0", new ColumnValue(1000));
exclusiveEndPrimaryKey.Add("pk1", new ColumnValue("xyz"));

//构造一个CapacityUnit,用于记录迭代过程中消耗的CU值。
var cu = new CapacityUnit(0, 0);

try
{
    //构造一个GetIteratorRequest,也支持使用过滤条件。
    var request = new GetIteratorRequest(TableName, GetRangeDirection.Forward, inclusiveStartPrimaryKey,
                                                exclusiveEndPrimaryKey, cu);

    var iterator = otsClient.GetRangeIterator(request);
    //遍历迭代器,读取数据。
    foreach (var row in iterator)
    {
        //处理逻辑。
    }

    Console.WriteLine("Iterate row succeeded");
} 
catch (Exception ex)
{
    Console.WriteLine("Iterate row failed, exception:{0}", ex.Message);
}            

详细代码请参见GetRangeIterator@GitHub