CLI命令 - Global Secondary Indexes

到目前为止,我们一直关注如何根据键属性访问数据。如果我们想根据非键属性查找项目,我们必须进行完整的表扫描并使用过滤条件来找到我们想要的内容,这对于大规模运营的系统来说既非常慢又非常昂贵。

DynamoDB提供了一个名为全局二级索引(GSI) 的功能,它可以自动将我们的数据围绕不同的分区和排序键进行转换。数据可以重新分组和重新排序,以允许更多的访问模式通过查询和扫描API快速提供服务。

回想一下之前的示例,我们想找到Reply表中由用户A发布的所有回复:

aws dynamodb scan \
    --table-name Reply \
    --filter-expression 'PostedBy = :user' \
    --expression-attribute-values '{
        ":user" : {"S": "User A"}
    }' \
    --return-consumed-capacity TOTAL

当运行该扫描操作时,我们可以看到返回的CountScannedCount不同。如果有10亿条回复项目,但只有3条是由用户A发布的,我们将不得不支付(时间和金钱)来扫描10亿个项目,只为找到我们想要的3个。

创建GSI

有了对GSI的这些了解,我们现在可以在Reply表上创建一个GSI来服务这个新的访问模式。 GSI可以随时创建和删除,即使表中已经有数据。

这个新的GSI将使用PostedBy属性作为分区(HASH)键,我们仍然将消息按ReplyDateTime排序作为排序(RANGE)键。 我们希望将表中的所有属性复制(投影)到GSI中,因此我们将使用ALL投影类型。 请注意,我们创建的索引名称为PostedBy-ReplyDateTime-gsi

aws dynamodb update-table \
    --table-name Reply \
    --attribute-definitions AttributeName=PostedBy,AttributeType=S AttributeName=ReplyDateTime,AttributeType=S \
    --global-secondary-index-updates '[{
        "Create":{
            "IndexName": "PostedBy-ReplyDateTime-gsi",
            "KeySchema": [
                {
                    "AttributeName" : "PostedBy",
                    "KeyType": "HASH"
                },
                {
                    "AttributeName" : "ReplyDateTime",
                    "KeyType" : "RANGE"
                }
            ],
            "ProvisionedThroughput": {
                "ReadCapacityUnits": 5, "WriteCapacityUnits": 5
            },
            "Projection": {
                "ProjectionType": "ALL"
            }
        }
    }
]'

在DynamoDB创建GSI并从表中回填数据到索引中可能需要一些时间。 我们可以从命令行观察并等待IndexStatus变为ACTIVE:

#获取状态
aws dynamodb describe-table --table-name Reply --query "Table.GlobalSecondaryIndexes[0].IndexStatus"

一旦GSI变为ACTIVE,继续进行下面

使用GSI

找到由用户A编写的所有回复,并按顺序排列。

在DynamoDB中使用GSI时,我们必须明确告诉DynamoDB表名和索引名。 对GSI运行query与对表运行没有什么不同,只是我们还需要使用--index-name选项指定要使用哪个GSI,并将GSI键属性用于KeyConditionExpression。

aws dynamodb query \
    --table-name Reply \
    --key-condition-expression 'PostedBy = :pb' \
    --expression-attribute-values '{
        ":pb" : {"S": "User A"}
    }' \
    --index-name PostedBy-ReplyDateTime-gsi \
    --return-consumed-capacity TOTAL

image-20241226155729289

注意输出中:

"Count": 3,
"ScannedCount": 3,

query无法比这更优化。即使表中有10亿条由其他用户发布的Reply项,这个查询也只会花费我们读取我们希望返回的3个确切项目(与scan不同)。

删除GSI:

aws dynamodb update-table \
    --table-name Reply \
    --global-secondary-index-updates '[{
        "Delete":{
            "IndexName": "PostedBy-ReplyDateTime-gsi"
        }
    }
]'