读取数据

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

说明

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

注意事项

当要读取带有自增主键列的表数据时,请确保已获取到包含自增主键列值在内的完整主键。更多信息,请参见主键列自增

重要

如果未记录自增主键列的值,您可以使用范围读取数据按照第一个主键列确定范围读取数据。

读取单行数据

调用GetRow接口读取一行数据。适用于能确定完整主键且要读取行数较少的场景。

读取单行数据时,您可以配置如下条件过滤所需数据。

  • 系统默认返回所有列,您可以配置只返回指定列的数据。

  • 使用过滤器获取符合过滤条件的行数据。更多信息,请参见过滤器

  • 如果为数据表配置了数据多版本,则您可以配置最多读取几个版本数据、读取指定时间范围或者指定版本号的数据。关于数据多版本的更多信息,请参见数据版本和生命周期

读取结果可能有如下两种情况:

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

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

批量读取数据

调用BatchGetRow接口一次请求读取多行数据或者一次对多张表进行读取。适用于能确定完整主键,且要读取行数较多或者要读取多个表中数据的场景。

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

批量读取数据时,您可以配置如下条件过滤所需数据。

  • 一次请求中读取多张表中的数据。

    单次请求中支持读取的最大行数为100行。

  • 系统默认返回所有列,您可以配置只返回指定列的数据。

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

  • 使用过滤器获取符合过滤条件的行数据。更多信息,请参见过滤器

  • 如果为数据表配置了数据多版本,则您可以配置最多读取几个版本数据、读取指定时间范围或者指定版本号的数据。关于数据版本的更多信息,请参见数据版本和生命周期

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

范围读取数据

调用GetRange接口读取一个范围内的数据。适用于能确定完整主键范围或者主键前缀的场景。

说明

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

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

范围读取数据时,您可以配置如下条件过滤所需数据。

  • 指定主键前缀后其他主键列使用虚拟点INF_MIN(无穷小)和INF_MAX(无穷大)读取数据,或者指定完整主键范围读取数据。

    重要

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

    如果范围较大,已扫描的行数或者数据量超过一定限制,会停止扫描,并返回已获取的行和下一个主键信息。您可以根据返回的下一个主键信息,继续发起请求,获取范围内剩余的行。

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

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

    • 扫描的行数等于5000。

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

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

  • 按照正序或者逆序读取最多指定个数的行数据,例如按照正序读取最多5行数据。

  • 系统默认返回所有列,您可以配置只返回指定列的数据。

  • 使用过滤器获取符合过滤条件的行数据。更多信息,请参见过滤器

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

  • 如果为数据表配置了数据多版本,则您可以配置最多读取几个版本数据、读取指定时间范围或者指定版本号的数据。关于数据版本的更多信息,请参见数据版本和生命周期

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

使用方式

使用控制台

您可以使用控制台进行单行查询数据或范围查询数据。

  1. 登录表格存储控制台

  2. 概览页面,单击实例操作列的实例管理

  3. 实例详情页签的数据表列表区域,单击数据表操作列的查询/搜索

  4. 数据管理页签,单击查询数据,根据实际选择单行读取数据或者范围读取数据。

    读取单行数据

    1. 查询数据对话框,选择查询范围单行查询,并选择要查询的表。

    2. 系统默认返回所有列。如需显示指定属性列,请关闭获取所有列并输入需要返回的属性列。

      多个属性列之间用半角逗号(,)隔开。

    3. 输入目标行的主键值

      主键值的完整性和准确性均会影响查询。

    4. 输入最大版本数,指定需要返回的版本数。

    5. 单击确定

    范围读取数据

    1. 查询数据对话框,选择查询范围范围查询,并选择要查询的表。

    2. 系统默认返回所有列。如需显示指定属性列,请关闭获取所有列并输入需要返回的属性列。

      多个属性列之间用半角逗号(,)隔开。

    3. 输入起始主键列和结束主键列。

    4. 重要
      • 范围查询优先使用第一个主键值进行查询,当设置的第一个主键值一致时,系统会使用第二个主键值进行查询,其他主键的查询规则同上。

      • 读取范围是前开后闭的区间。

    5. 输入最大版本数,指定需要返回的版本数。

    6. 设置查询结果的排序方向,可选正序查询逆序查询

    7. 单击确定

使用命令行工具CLI

您可以使用命令行工具执行如下命令读取数据。

  • 执行get命令读取单行数据。更多信息,请参见读取数据

    以下示例用于读取第一主键列值为“86”,第二主键列值为6771的行数据。

    get --pk '["86",6771]'
  • 执行scan命令范围读取数据。更多信息,请参见导出数据

    以下示例用于逆序读取["86",7000]["86",6770]主键范围之间的行数据,且只返回pid列。

    scan --begin '["86",7000]' --end '["86",6770]' --backward --columns pid

使用SDK

您可以使用Java SDKGo SDKPython SDKNode.js SDK.NET SDKPHP SDK读取数据。此处以Java SDK为例介绍读取数据的使用。

读取单行数据

读取数据时,您可以指定要读取的数据版本、要读取的列、过滤器、正则过滤等。

  • 读取最新版本数据和指定列

    以下示例用于读取数据表中的一行数据,设置读取最新版本的数据和读取指定的列。

    private static void getRow(SyncClient client, String pkValue) {
        //构造主键。
        PrimaryKeyBuilder primaryKeyBuilder = PrimaryKeyBuilder.createPrimaryKeyBuilder();
        primaryKeyBuilder.addPrimaryKeyColumn("pk", PrimaryKeyValue.fromString(pkValue));
        PrimaryKey primaryKey = primaryKeyBuilder.build();
    
        //读取一行数据,设置数据表名称。
        SingleRowQueryCriteria criteria = new SingleRowQueryCriteria("<TABLE_NAME>", primaryKey);
        //设置读取最新版本。
        criteria.setMaxVersions(1);
        GetRowResponse getRowResponse = client.getRow(new GetRowRequest(criteria));
        Row row = getRowResponse.getRow();
    
        System.out.println("读取完毕,结果为: ");
        System.out.println(row);
    
        //设置读取某些列。
        criteria.addColumnsToGet("Col0");
        getRowResponse = client.getRow(new GetRowRequest(criteria));
        row = getRowResponse.getRow();
    
        System.out.println("读取完毕,结果为:");
        System.out.println(row);
    } 
  • 读取数据时使用过滤器

    以下示例用于读取数据表中的一行数据,设置读取最新版本的数据以及根据Col0列的值过滤数据。

    private static void getRow(SyncClient client, String pkValue) {
        //构造主键。
        PrimaryKeyBuilder primaryKeyBuilder = PrimaryKeyBuilder.createPrimaryKeyBuilder();
        primaryKeyBuilder.addPrimaryKeyColumn("pk", PrimaryKeyValue.fromString(pkValue));
        PrimaryKey primaryKey = primaryKeyBuilder.build();
    
        //读取一行数据,设置数据表名称。
        SingleRowQueryCriteria criteria = new SingleRowQueryCriteria("<TABLE_NAME>", primaryKey);
        //设置读取最新版本。
        criteria.setMaxVersions(1);
    
        //设置过滤器,当Col0列的值为0时,返回该行。
        SingleColumnValueFilter singleColumnValueFilter = new SingleColumnValueFilter("Col0",
                SingleColumnValueFilter.CompareOperator.EQUAL, ColumnValue.fromLong(0));
        //如果Col0列不存在,则不返回该行。
        singleColumnValueFilter.setPassIfMissing(false);
        criteria.setFilter(singleColumnValueFilter);
    
        GetRowResponse getRowResponse = client.getRow(new GetRowRequest(criteria));
        Row row = getRowResponse.getRow();
    
        System.out.println("读取完毕,结果为: ");
        System.out.println(row);
    }
  • 读取数据时使用正则过滤

    以下示例用于读取数据表一行中Col1列的数据,并对该列的数据执行正则过滤。

    private static void getRow(SyncClient client, String pkValue) {
        //设置数据表名称。
        SingleRowQueryCriteria criteria = new SingleRowQueryCriteria("<TABLE_NAME>");
     
        //构造主键。
        PrimaryKey primaryKey = PrimaryKeyBuilder.createPrimaryKeyBuilder()
            .addPrimaryKeyColumn("pk", PrimaryKeyValue.fromString(pkValue))
            .build();
        criteria.setPrimaryKey(primaryKey);
     
        // 设置读取最新版本。
        criteria.setMaxVersions(1);
     
        // 设置过滤器,当cast<int>(regex(Col1)) > 100时,返回该行。
        RegexRule regexRule = new RegexRule("t1:([0-9]+),", RegexRule.CastType.VT_INTEGER);
        SingleColumnValueRegexFilter filter =  new SingleColumnValueRegexFilter("Col1",
            regexRule,SingleColumnValueRegexFilter.CompareOperator.GREATER_THAN, ColumnValue.fromLong(100));
        criteria.setFilter(filter);
     
        GetRowResponse getRowResponse = client.getRow(new GetRowRequest(criteria));
        Row row = getRowResponse.getRow();
    
        System.out.println("读取完毕,结果为: ");
        System.out.println(row);
    }

批量读取数据

以下示例用于读取10行,设置版本条件、要读取的列、过滤器等。

private static void batchGetRow(SyncClient client) {
    //设置数据表名称。
    MultiRowQueryCriteria multiRowQueryCriteria = new MultiRowQueryCriteria("<TABLE_NAME>");
    //加入10个要读取的行。
    for (int i = 0; i < 10; i++) {
        PrimaryKeyBuilder primaryKeyBuilder = PrimaryKeyBuilder.createPrimaryKeyBuilder();
        primaryKeyBuilder.addPrimaryKeyColumn("pk", PrimaryKeyValue.fromString("pk" + i));
        PrimaryKey primaryKey = primaryKeyBuilder.build();
        multiRowQueryCriteria.addRow(primaryKey);
    }
    //添加条件。
    multiRowQueryCriteria.setMaxVersions(1);
    multiRowQueryCriteria.addColumnsToGet("Col0");
    multiRowQueryCriteria.addColumnsToGet("Col1");
    SingleColumnValueFilter singleColumnValueFilter = new SingleColumnValueFilter("Col0",
            SingleColumnValueFilter.CompareOperator.EQUAL, ColumnValue.fromLong(0));
    singleColumnValueFilter.setPassIfMissing(false);
    multiRowQueryCriteria.setFilter(singleColumnValueFilter);

    BatchGetRowRequest batchGetRowRequest = new BatchGetRowRequest();
    //BatchGetRow支持读取多个表的数据,一个multiRowQueryCriteria对应一个表的查询条件,可以添加多个multiRowQueryCriteria。
    batchGetRowRequest.addMultiRowQueryCriteria(multiRowQueryCriteria);

    BatchGetRowResponse batchGetRowResponse = client.batchGetRow(batchGetRowRequest);

    System.out.println("是否全部成功:" + batchGetRowResponse.isAllSucceed());
    System.out.println("读取完毕,结果为: ");
    for (BatchGetRowResponse.RowResult rowResult : batchGetRowResponse.getSucceedRows()) {
        System.out.println(rowResult.getRow());
    }
    if (!batchGetRowResponse.isAllSucceed()) {
        for (BatchGetRowResponse.RowResult rowResult : batchGetRowResponse.getFailedRows()) {
            System.out.println("失败的行:" + batchGetRowRequest.getPrimaryKey(rowResult.getTableName(), rowResult.getIndex()));
            System.out.println("失败原因:" + rowResult.getError());
        }

        /**
         * 可以通过createRequestForRetry方法再构造一个请求对失败的行进行重试。此处只给出构造重试请求的部分。
         * 推荐的重试方法是使用SDK的自定义重试策略功能,支持对batch操作的部分行错误进行重试。设置重试策略后,调用接口处无需增加重试代码。
         */
        BatchGetRowRequest retryRequest = batchGetRowRequest.createRequestForRetry(batchGetRowResponse.getFailedRows());
    }
}

范围读取数据

  • 按照确定范围读取数据

    以下示例用于按照确定范围进行正序读取,判断nextStartPrimaryKey是否为空,读取完范围内的全部数据。

    private static void getRange(SyncClient client, String startPkValue, String endPkValue) {
        //设置数据表名称。
        RangeRowQueryCriteria rangeRowQueryCriteria = new RangeRowQueryCriteria("<TABLE_NAME>");
    
        //设置起始主键。
        PrimaryKeyBuilder primaryKeyBuilder = PrimaryKeyBuilder.createPrimaryKeyBuilder();
        primaryKeyBuilder.addPrimaryKeyColumn("pk", PrimaryKeyValue.fromString(startPkValue));
        rangeRowQueryCriteria.setInclusiveStartPrimaryKey(primaryKeyBuilder.build());
    
        //设置结束主键。
        primaryKeyBuilder = PrimaryKeyBuilder.createPrimaryKeyBuilder();
        primaryKeyBuilder.addPrimaryKeyColumn("pk", PrimaryKeyValue.fromString(endPkValue));
        rangeRowQueryCriteria.setExclusiveEndPrimaryKey(primaryKeyBuilder.build());
    
        rangeRowQueryCriteria.setMaxVersions(1);
    
        System.out.println("GetRange的结果为:");
        while (true) {
            GetRangeResponse getRangeResponse = client.getRange(new GetRangeRequest(rangeRowQueryCriteria));
            for (Row row : getRangeResponse.getRows()) {
                System.out.println(row);
            }
    
            //如果NextStartPrimaryKey不为null,则继续读取。
            if (getRangeResponse.getNextStartPrimaryKey() != null) {
                rangeRowQueryCriteria.setInclusiveStartPrimaryKey(getRangeResponse.getNextStartPrimaryKey());
            } else {
                break;
            }
        }
    }         
  • 按照第一个主键列确定范围读取数据

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

    private static void getRange(SyncClient client, String startPkValue, String endPkValue) {
        //设置数据表名称。
        RangeRowQueryCriteria rangeRowQueryCriteria = new RangeRowQueryCriteria("<TABLE_NAME>");
        //设置起始主键,以两个主键为例。
        PrimaryKeyBuilder primaryKeyBuilder = PrimaryKeyBuilder.createPrimaryKeyBuilder();
        primaryKeyBuilder.addPrimaryKeyColumn("pk1", PrimaryKeyValue.fromString(startPkValue));//确定值。
        primaryKeyBuilder.addPrimaryKeyColumn("pk2", PrimaryKeyValue.INF_MIN);//最小值。
        rangeRowQueryCriteria.setInclusiveStartPrimaryKey(primaryKeyBuilder.build());
    
        //设置结束主键。
        primaryKeyBuilder = PrimaryKeyBuilder.createPrimaryKeyBuilder();
        primaryKeyBuilder.addPrimaryKeyColumn("pk1", PrimaryKeyValue.fromString(endPkValue));//确定值。
        primaryKeyBuilder.addPrimaryKeyColumn("pk2", PrimaryKeyValue.INF_MAX);//最大值。
        rangeRowQueryCriteria.setExclusiveEndPrimaryKey(primaryKeyBuilder.build());
    
        rangeRowQueryCriteria.setMaxVersions(1);
    
        System.out.println("GetRange的结果为:");
        while (true) {
            GetRangeResponse getRangeResponse = client.getRange(new GetRangeRequest(rangeRowQueryCriteria));
            for (Row row : getRangeResponse.getRows()) {
                System.out.println(row);
            }
    
            //如果nextStartPrimaryKey不为null,则继续读取。
            if (getRangeResponse.getNextStartPrimaryKey() != null) {
                rangeRowQueryCriteria.setInclusiveStartPrimaryKey(getRangeResponse.getNextStartPrimaryKey());
            } else {
                break;
            }
        }
    }    
  • 按照确定范围读取数据并对指定列使用正则过滤

    以下示例用于读取主键范围为["pk:2020-01-01.log", "pk:2021-01-01.log")Col1列的数据,并对该列的数据执行正则过滤。

    private static void getRange(SyncClient client) {
        //设置数据表名称。
        RangeRowQueryCriteria criteria = new RangeRowQueryCriteria("<TABLE_NAME>");
     
        //设置主键范围为["pk:2020-01-01.log", "pk:2021-01-01.log"),读取范围为左闭右开的区间。
        PrimaryKey pk0 = PrimaryKeyBuilder.createPrimaryKeyBuilder()
            .addPrimaryKeyColumn("pk", PrimaryKeyValue.fromString("2020-01-01.log"))
            .build();
        PrimaryKey pk1 = PrimaryKeyBuilder.createPrimaryKeyBuilder()
            .addPrimaryKeyColumn("pk", PrimaryKeyValue.fromString("2021-01-01.log"))
            .build();
        criteria.setInclusiveStartPrimaryKey(pk0);
        criteria.setExclusiveEndPrimaryKey(pk1);
     
        //设置读取最新版本。
        criteria.setMaxVersions(1);
     
        //设置过滤器,当cast<int>(regex(Col1)) > 100时,返回该行。
        RegexRule regexRule = new RegexRule("t1:([0-9]+),", RegexRule.CastType.VT_INTEGER);
        SingleColumnValueRegexFilter filter =  new SingleColumnValueRegexFilter("Col1",
            regexRule,SingleColumnValueRegexFilter.CompareOperator.GREATER_THAN,ColumnValue.fromLong(100));
        criteria.setFilter(filter);
    
        while (true) {
            GetRangeResponse resp = client.getRange(new GetRangeRequest(criteria));
            for (Row row : resp.getRows()) {
                // do something
                System.out.println(row);
            }
            if (resp.getNextStartPrimaryKey() != null) {
                criteria.setInclusiveStartPrimaryKey(resp.getNextStartPrimaryKey());
            } else {
                break;
            }
       }
    }

计费说明

表格存储包括VCU模式(原预留模式)和CU模式(原按量模式)两种计费模式。使用不同的计费模式时,计算部分的计费方式不同。

计费模式

计算部分的计费说明

VCU模式(原预留模式)

以包年包月方式预先购买计算能力。计算能力中涵盖数据读的计算消耗。

CU模式(原按量模式)

根据实际计算消耗折算成CU进行计费。同时根据实例类型不同,计费时需要区分按量读写CU以及预留读写CU。

说明

关于实例类型和CU的更多信息,请分别参见实例读写吞吐量

读取数据时不消耗写CU,消耗的读CU计算规则如下:

  • GetRow操作消耗的读CU

    读取的行主键的数据大小与实际读取的属性列数据大小之和,按4 KB向上取整。如果操作指定的行不存在,则消耗1单位读CU。

  • BatchGetRow操作消耗的读CU

    按照将每个RowInBatchGetRowRequest视为一个GetRow操作独立计算读CU。

  • GetRange操作消耗的读CU

    从区间起始点到下一条未读数据的起始点,所有行主键数据大小与实际扫描的所有属性列数据大小之和按4 KB向上取整计算消耗的读CU。例如扫描范围中包含10行数据,每行主键数据大小与实际扫描的所有属性列数据之和为330 Byte,则消耗的读CU1(数据总和3.3 KB,除以4 KB向上取整为1)。