Table 在 DynamoDB 中设计
Table design in DynamoDB
我是 NoSQL DB 和 Serverless 的初学者。我的应用有一个名为 Trips
的 table。 table的参数是{id, route, cost, selling, type, date, LR, asset }
和一堆其他不相关的文档号,其中id由uuid生成。
现在我想查询数据库给我
- Return 使用日期参数的日期范围内的所有行程。
- Return 使用日期和资产参数在给定时间段内资产的所有行程。
- Return 使用日期路线参数在给定时间段内路线的所有行程。
2 和 3 使用 keyConditionExpression 工作正常,但对于 1,我需要在扫描中使用 filterExpression 而不是查询,这可能会使它相对较慢,因为它是在查询完成后执行的。有没有更好的方法来形成模式?
在 Trips
table 中,架构是这样的
tripTable:
Type: "AWS::DynamoDB::Table"
Properties:
AttributeDefinitions:
[
{ "AttributeName": "id", "AttributeType": "S" },
{ "AttributeName": "date", "AttributeType": "S" },
{ "AttributeName": "Asset", "AttributeType": "S" },
{ "AttributeName": "Route", "AttributeType": "S" },
]
KeySchema:
[
{ "AttributeName": "date", "KeyType": "HASH" },
{ "AttributeName": "id", "KeyType": "RANGE" },
]
ProvisionedThroughput:
ReadCapacityUnits: 5
WriteCapacityUnits: 5
StreamSpecification:
StreamViewType: "NEW_AND_OLD_IMAGES"
TableName: ${self:provider.environment.TRIPS}
GlobalSecondaryIndexes:
- IndexName: TripsVSAssets
KeySchema:
- AttributeName: asset
KeyType: HASH
- AttributeName: date
KeyType: RANGE
Projection:
ProjectionType: ALL
ProvisionedThroughput:
ReadCapacityUnits: "5"
WriteCapacityUnits: "5"
GlobalSecondaryIndexes:
- IndexName: RoutesVSAssets
KeySchema:
- AttributeName: route
KeyType: HASH
- AttributeName: date
KeyType: RANGE
Projection:
ProjectionType: ALL
ProvisionedThroughput:
ReadCapacityUnits: "5"
WriteCapacityUnits: "5"
您还需要一个索引列,其中分区键(哈希类型)将是一个随机数,比方说从 0 到 20。排序键(范围类型),再次将日期放在那里。
所以要查询某个时间段内的所有行程,需要并行查询20次,partition Key为0到20之间的每个数字,Sort Key为时间范围。
https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/bp-modeling-nosql-B.html
检查上面的指南,转到页面末尾的 table 并检查第 5 个条目
如果您在此处进行扫描,那么 dynamoDB 将针对每个分区键向您收费。在上面提到的并行查询技术中,您只需为 N 个查询付费(在上述情况下为 20 个)。
我最近遇到了类似的问题,并选择使用 year
作为分区键和日期作为排序键。这对我的数据量来说是正确的,让我可以按日期查询,而且大多数情况下只是 运行 单个查询。如果您有大量数据,也许 month
甚至 week
会更合适(或完全不同)。
然后,使用我的方法,我只需要检查我想要查看的日期范围是否跨越两年,在这些情况下(即很少),Lambda 会进行两次查询并合并结果。我在下面包含了一些代码草案,以防它有用(可能有更好的方法,但这对我有用!)我还推荐快速阅读:https://aws.amazon.com/blogs/database/choosing-the-right-dynamodb-partition-key/.
module.exports.getLatest = async event => {
// some date and formatting code here not included
var params1 = {
ExpressionAttributeNames: { "#date": "date", "#year": "year" },
ExpressionAttributeValues: {
':d': isoDate,
':y1': y1
},
KeyConditionExpression: '#year = :y1 AND #date > :d',
TableName: process.env.HEADLINES_TABLE
}
if (y1 != y2) {
// define var params2 (the same as params1 except it uses y2)
}
try {
let result;
// if the date range cuts across partitions (years), fire off two queries and wait for both
if(y1 != y2) {
let resultPromise1 = client.query(params1).promise();
let resultPromise2 = client.query(params2).promise();
const [result1, result2] = await Promise.all([resultPromise1,resultPromise2]);
result = [...result1.Items, ...result2.Items];
} else {
result = await client.query(params1).promise();
}
return {
// stringify and return result.Items, statuscode 200 etc.
}
}
// catch {} code here (irrelevant for the answer)
}
我是 NoSQL DB 和 Serverless 的初学者。我的应用有一个名为 Trips
的 table。 table的参数是{id, route, cost, selling, type, date, LR, asset }
和一堆其他不相关的文档号,其中id由uuid生成。
现在我想查询数据库给我
- Return 使用日期参数的日期范围内的所有行程。
- Return 使用日期和资产参数在给定时间段内资产的所有行程。
- Return 使用日期路线参数在给定时间段内路线的所有行程。
2 和 3 使用 keyConditionExpression 工作正常,但对于 1,我需要在扫描中使用 filterExpression 而不是查询,这可能会使它相对较慢,因为它是在查询完成后执行的。有没有更好的方法来形成模式?
在 Trips
table 中,架构是这样的
tripTable:
Type: "AWS::DynamoDB::Table"
Properties:
AttributeDefinitions:
[
{ "AttributeName": "id", "AttributeType": "S" },
{ "AttributeName": "date", "AttributeType": "S" },
{ "AttributeName": "Asset", "AttributeType": "S" },
{ "AttributeName": "Route", "AttributeType": "S" },
]
KeySchema:
[
{ "AttributeName": "date", "KeyType": "HASH" },
{ "AttributeName": "id", "KeyType": "RANGE" },
]
ProvisionedThroughput:
ReadCapacityUnits: 5
WriteCapacityUnits: 5
StreamSpecification:
StreamViewType: "NEW_AND_OLD_IMAGES"
TableName: ${self:provider.environment.TRIPS}
GlobalSecondaryIndexes:
- IndexName: TripsVSAssets
KeySchema:
- AttributeName: asset
KeyType: HASH
- AttributeName: date
KeyType: RANGE
Projection:
ProjectionType: ALL
ProvisionedThroughput:
ReadCapacityUnits: "5"
WriteCapacityUnits: "5"
GlobalSecondaryIndexes:
- IndexName: RoutesVSAssets
KeySchema:
- AttributeName: route
KeyType: HASH
- AttributeName: date
KeyType: RANGE
Projection:
ProjectionType: ALL
ProvisionedThroughput:
ReadCapacityUnits: "5"
WriteCapacityUnits: "5"
您还需要一个索引列,其中分区键(哈希类型)将是一个随机数,比方说从 0 到 20。排序键(范围类型),再次将日期放在那里。
所以要查询某个时间段内的所有行程,需要并行查询20次,partition Key为0到20之间的每个数字,Sort Key为时间范围。
https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/bp-modeling-nosql-B.html
检查上面的指南,转到页面末尾的 table 并检查第 5 个条目
如果您在此处进行扫描,那么 dynamoDB 将针对每个分区键向您收费。在上面提到的并行查询技术中,您只需为 N 个查询付费(在上述情况下为 20 个)。
我最近遇到了类似的问题,并选择使用 year
作为分区键和日期作为排序键。这对我的数据量来说是正确的,让我可以按日期查询,而且大多数情况下只是 运行 单个查询。如果您有大量数据,也许 month
甚至 week
会更合适(或完全不同)。
然后,使用我的方法,我只需要检查我想要查看的日期范围是否跨越两年,在这些情况下(即很少),Lambda 会进行两次查询并合并结果。我在下面包含了一些代码草案,以防它有用(可能有更好的方法,但这对我有用!)我还推荐快速阅读:https://aws.amazon.com/blogs/database/choosing-the-right-dynamodb-partition-key/.
module.exports.getLatest = async event => {
// some date and formatting code here not included
var params1 = {
ExpressionAttributeNames: { "#date": "date", "#year": "year" },
ExpressionAttributeValues: {
':d': isoDate,
':y1': y1
},
KeyConditionExpression: '#year = :y1 AND #date > :d',
TableName: process.env.HEADLINES_TABLE
}
if (y1 != y2) {
// define var params2 (the same as params1 except it uses y2)
}
try {
let result;
// if the date range cuts across partitions (years), fire off two queries and wait for both
if(y1 != y2) {
let resultPromise1 = client.query(params1).promise();
let resultPromise2 = client.query(params2).promise();
const [result1, result2] = await Promise.all([resultPromise1,resultPromise2]);
result = [...result1.Items, ...result2.Items];
} else {
result = await client.query(params1).promise();
}
return {
// stringify and return result.Items, statuscode 200 etc.
}
}
// catch {} code here (irrelevant for the answer)
}