关系(SQL)数据库和 DynamoDB 在管理索引方面的差异 - Amazon DynamoDB

关系(SQL)数据库和 DynamoDB 在管理索引方面的差异

索引使您能够访问替代查询模式,并可以加快查询速度。本节将 SQL 和 Amazon DynamoDB 中的索引创建和使用进行了比较和对比。

无论您使用的是关系数据库还是 DynamoDB,在创建索引时都应谨慎。只要对表进行写入,就必须更新表的所有索引。在具有大型表的写入密集型环境中,这会占用大量系统资源。在只读环境或主读环境中,这算不上一个问题。但是,您应确保索引实际上由应用程序使用,而不只是占用空间。

关系(SQL)数据库和 DynamoDB 在创建索引方面的差异

将 SQL 中的 CREATE INDEX 语句与 Amazon DynamoDB 中的 UpdateTable 操作进行比较。

使用 SQL 创建索引

在关系数据库中,索引是一个数据结构,可让您对表中的不同的列执行快速查询。您可以使用 CREATE INDEX SQL 语句将索引添加到现有表,并指定要建立索引的列。在创建索引后,您可以照常查询表中的数据,但现在数据库可使用索引快速查找表中的指定行,而不是扫描整个表。

在创建一个索引后,数据库将为您维护此索引。只要您修改表中的数据,就会自动更改索引以反映表中的更改。

在 MySQL 中,您可以创建如下所示的索引。

CREATE INDEX GenreAndPriceIndex ON Music (genre, price);

在 DynamoDB 中创建索引

在 DynamoDB 中,您可以创建和使用二级索引来实现类似目的。

DynamoDB 中的索引与其关系对应项不同。当您创建二级索引时,必须指定其键属性—分区键和排序键。创建二级索引后,可以 QueryScan,就像对表一样。DynamoDB 没有查询优化程序,因此仅在 QueryScan 时使用二级索引。

DynamoDB 支持两种不同的索引:

  • 全局二级索引 – 索引的主键可以是其表中的任意两个属性。

  • 本地二级索引 – 索引的分区键必须与其表的分区键相同。不过,排序键可以是任何其他属性。

DynamoDB 确保二级索引中的数据最终与其表保持一致。您可以请求对表或本地二级索引执行强一致性 QueryScan 操作。但是,全局二级索引仅支持最终一致性。

可以使用 UpdateTable 操作并指定 GlobalSecondaryIndexUpdates,将全局二级索引添加到现有表。

{ TableName: "Music", AttributeDefinitions:[ {AttributeName: "Genre", AttributeType: "S"}, {AttributeName: "Price", AttributeType: "N"} ], GlobalSecondaryIndexUpdates: [ { Create: { IndexName: "GenreAndPriceIndex", KeySchema: [ {AttributeName: "Genre", KeyType: "HASH"}, //Partition key {AttributeName: "Price", KeyType: "RANGE"}, //Sort key ], Projection: { "ProjectionType": "ALL" }, ProvisionedThroughput: { // Only specified if using provisioned mode "ReadCapacityUnits": 1,"WriteCapacityUnits": 1 } } } ] }

您必须向 UpdateTable 提供以下参数:

  • TableName – 索引将关联到的表。

  • AttributeDefinitions – 索引的键架构属性的数据类型。

  • GlobalSecondaryIndexUpdates – 有关要创建的索引的详细信息:

    • IndexName – 索引的名称。

    • KeySchema – 用于索引主键的属性。

    • Projection – 表中要复制到索引的属性。在此情况下,ALL 意味着复制所有属性。

    • ProvisionedThroughput (for provisioned tables) – 每秒需对此索引执行的读取和写入次数。(它与表的预调配吞吐量设置是分开的。)

在此操作中,会将表中的数据回填到新索引。在回填期间,表保持可用。但索引未准备就绪,直至其 Backfilling 属性从 true 变为 false。您可以使用 DescribeTable 操作查看此属性。

关系(SQL)数据库和 DynamoDB 在查询和扫描索引方面的差异

将使用 SQL 中的 SELECT 语句查询并扫描索引与使用 Amazon DynamoDB 中的 QueryScan 操作查询并扫描索引进行比较。

使用 SQL 查询并扫描索引

在关系数据库中,不能直接使用索引。相反,您通过发出 SELECT 语句来查询表,查询优化程序可使用任何索引。

查询优化程序 是一个关系数据库管理系统 (RDBMS) 组件,它将评估可用索引并确定是否可使用这些索引来加快查询速度。如果索引可用来加快查询速度,则 RDBMS 会先访问索引,然后使用索引查找表中的数据。

以下几个 SQL 语句可使用 GenreAndPriceIndex 提高性能。我们假定 Music 表包含足够多的数据以促使查询优化程序决定使用此索引,而不是扫描整个表。

/* All of the rock songs */ SELECT * FROM Music WHERE Genre = 'Rock';
/* All of the cheap country songs */ SELECT Artist, SongTitle, Price FROM Music WHERE Genre = 'Country' AND Price < 0.50;

在 DynamoDB 中查询并扫描索引

在 DynamoDB 中,直接对索引执行 QueryScan 操作,就如同对表执行此操作一样。您可以使用 DynamoDB API 或 PartiQL(一种与 SQL 兼容的查询语言)来查询或扫描索引。您必须指定 TableNameIndexName

下面是一些 DynamoDB 中对 GenreAndPriceIndex 的查询。(此索引的键架构包含 GenrePrice。)

DynamoDB API
// All of the rock songs { TableName: "Music", IndexName: "GenreAndPriceIndex", KeyConditionExpression: "Genre = :genre", ExpressionAttributeValues: { ":genre": "Rock" }, };

此示例使用 ProjectionExpression 指示您只希望结果中显示部分而不是全部属性。

// All of the cheap country songs { TableName: "Music", IndexName: "GenreAndPriceIndex", KeyConditionExpression: "Genre = :genre and Price < :price", ExpressionAttributeValues: { ":genre": "Country", ":price": 0.50 }, ProjectionExpression: "Artist, SongTitle, Price" };

以下是对 GenreAndPriceIndex 进行的扫描。

// Return all of the data in the index { TableName: "Music", IndexName: "GenreAndPriceIndex" }
PartiQL for DynamoDB

使用 PartiQL,您可以使用 Select 语句来对索引执行查询和扫描。

// All of the rock songs SELECT * FROM Music.GenreAndPriceIndex WHERE Genre = 'Rock'
// All of the cheap country songs SELECT * FROM Music.GenreAndPriceIndex WHERE Genre = 'Rock' AND Price < 0.50

以下是对 GenreAndPriceIndex 进行的扫描。

// Return all of the data in the index SELECT * FROM Music.GenreAndPriceIndex
注意

有关使用 Select 的代码示例,请参阅 PartiQL for DynamoDB 的 Select 语句