当我们将更多数据放入表中时,DynamodB查询开始花费更多时间

时间:2019-03-26 08:50:15

标签: amazon-dynamodb dynamodb-queries

我们有一个具有以下结构的dynamoDb表。

userId - partition key- number
yearOfBirth -attribute number
dateOfBirth - attribute(number in millisecond)
loginTime - attribute(number in millisecond)

以及以下gsi-user_gsi

yearOfBirth - partition key- number
dateOfBirth - sort key (number -in millisecond)
loginTime - attribute(number in millisecond)

我们正在使用java aws sdk查询表。 我们的查询要求是查询两个dateOfBirth之间和两个loginTime之间的所有用户。 我们从dateofBirth范围中获取所有年份,并在单独的线程中查询每年,然后加入每个线程返回的结果。

以下代码用于查询单个yearOfBirth-

public Set<Long> queryForSingleBirthYear(Long startDateDob, Long endDateDob,Long minLoginTime, Long maxLoginTime, int yearOfBirth){
        Set<Long> userIds = new HashSet<>();

        Map<String, AttributeValue> lastEvaluatedKey = null;
        do{
            QueryRequest queryRequest = new QueryRequest().withTableName("user");
            queryRequest
                    .withIndexName("user_gsi")
                    .withExclusiveStartKey(lastEvaluatedKey);

            Condition keyCond = new Condition().withComparisonOperator(ComparisonOperator.EQ)
                    .withAttributeValueList(new AttributeValue().withN(Integer.toString(yearOfBirth)));

            String startDate = startDateDob.toString();
            String endDate = endDateDob.toString();

            Condition dobCond = new Condition().withComparisonOperator(ComparisonOperator.BETWEEN)
                    .withAttributeValueList(new AttributeValue().withN(startDate), new AttributeValue().withN(endDate));

            Map<String, Condition> keyCondMap = new HashMap<>();
            keyCondMap.put("yearOfBirth", keyCond);
            keyCondMap.put("dateOfBirth", dobCond);

            queryRequest.setKeyConditions(keyCondMap);
            Map<String,String> attrNames = new HashMap<>();
            attrNames.put("#loginTime","loginTime");
            Map<String,AttributeValue> attrvalues = new HashMap<>();
            attrvalues.put(":v_minLoginTime",new AttributeValue().withN(minLoginTime.toString()));
            attrvalues.put(":v_maxLoginTime",new AttributeValue().withN(maxLoginTime.toString()));

            String queryFilter = "#loginTime > :v_minLoginTime and #loginTime <= :v_maxLoginTime";

            queryRequest.withFilterExpression(queryFilter)
                    .withExpressionAttributeNames(attrNames)
                    .withExpressionAttributeValues(attrvalues);;

            QueryResult queryResult = amazonDynamoDB.query(queryRequest);
            List<Map<String, AttributeValue>> items = queryResult.getItems();
            for (Map<String, AttributeValue> item : items) {
                String id = item.get("userId").getN();
                userIds.add(Long.valueOf(id));
            }
            lastEvaluatedKey = queryResult.getLastEvaluatedKey();
        }while (lastEvaluatedKey != null);
        return basicFilterRes;
    }

在进行负载测试时,随着将更多数据加载到表中,查询开始花费时间。 对于200K条记录以及大约25年的出生日期范围的dateOfBirth,大约需要2-3秒。 如果我们将表中的记录数增加到150万,则开始大约需要15-20秒。我们尝试增加RCU甚至将RCU更改为按需模式,但是时间保持不变。

编辑

以下是查询每年打印时间后的结果-

yearOfBirth=1972, resultSize=110, timeMs=56
yearOfBirth=1977, resultSize=199, timeMs=54
yearOfBirth=1971, resultSize=89, timeMs=59
yearOfBirth=1973, resultSize=113, timeMs=60
yearOfBirth=1974, resultSize=143, timeMs=60
yearOfBirth=1978, resultSize=266, timeMs=59
yearOfBirth=1998, resultSize=3524, timeMs=612
yearOfBirth=1993, resultSize=3923, timeMs=677
yearOfBirth=1995, resultSize=4569, timeMs=714
yearOfBirth=1994, resultSize=4688, timeMs=777

1 个答案:

答案 0 :(得分:1)

loginTime范围是多少?如果gsi小于dateOfBirth范围,请考虑将gsi切换为indexTime上的索引。

具有150万条记录和25年的查询,每个查询将必须读取约60,000条记录,这需要花费一些时间,因为每个页面都是按顺序加载的。通过将startDateDobendDateDob之间的范围分成较小的非重叠范围,可以同时查询每年的一部分,从而使每年查询并行化。例如如果startDateDob和endDateDob涵盖整个一年,则分为12个查询,每个月查询一次。