amazon-web-services - DynamoDB分层数据和条件表设计
问题描述
我在设计 DynamoDB 表以支持相当简单的访问模式时遇到问题。我希望你能帮助我一点:)
我有 4 种不同的产品类型(A、B、C 和 D),它们有价格和位置(国家#国家#城市)。
访问模式是:
- 按产品类型过滤
- 按产品类型和位置过滤
- 按产品类型、位置和价格筛选
- 按产品类型、位置和价格过滤并按价格排序
问题是位于 USA#NY#NY 的产品必须在 USA#NY 和美国也有售。此外,用户需要能够按价格过滤并首先按贵/便宜排序。
例子:
数据:
产品:ID_1 | A型 | 地点美国#NY#NY | 价格 100 美元 产品:ID_2 | A型 | 地点 USA#NY#NY | 价格 200 美元
用例:
- 用户 U1 在 USA#NY#NY 首先搜索价格 < 500$ 的产品类型 A
- 用户 U2 在 USA#NY 搜索价格 < 250 美元的产品类型 A 最便宜
预期结果:
- U1 应该得到 ID_2,ID_1
- U2 应该得到 ID_1、ID_2
两种产品都应该以正确的顺序显示给两个用户,即使他们在不同的区域进行搜索。
为了能够按位置和价格过滤并按价格排序,我想出了这个解决方案,但是,很多数据被重复了,我相信一定有更好的解决方案:
PK | SK & GSI PK | GSI SK | 其他产品详情(重复数据) -------------------------------------------------- ------------------------- 身份证 | 类型 | 价格 | 图片、名称等 身份证 | 类型#美国 | 价格 | 图片、名称等 身份证 | 类型#USA#NY | 价格 | 图片、名称等 身份证 | 类型#USA#NY#NY | 价格 | 图片、名称等
这解决了每个访问模式:
按产品类型过滤
GSI PK = 类型
按产品类型和位置过滤
GSI PK = begin_with(TYPE#USA#NY#...)
按产品类型、位置和价格筛选
GSI PK = TYPE#USA & GSI SK > 150
GSI PK = TYPE#USA#NY & GSI SK > 150
按产品类型、位置和价格过滤并按价格排序
GSI PK = TYPE#USA & GSI SK > 150 ScanIndexForward true/false
GSI PK = TYPE#USA#NY & GSI SK > 150 ScanIndexForward 真/假
读取效率很高,但大量数据会重复(价格和产品详细信息),更新商品需要多次写入。
是否可以在不复制所有产品细节的情况下实现这一目标?
解决方案
我认为您误解了分层模式
您只需要
Table
PK = ID
GSI
PK = 类型
SK = 国家#州#城市
然后,您可以查询 GSI
- 查询(GSI,PK = 'TYPEA')
- 查询(GSI,PK = 'TYPEA',SK 以'USA#'开头)
- 查询(GSI,PK = 'TYPEA',SK 以'USA#NY#'开头)
- 查询(GSI,PK = 'TYPEA',SK 以'USA#NY#NY#'开头)
可以将价格过滤添加到上述任何查询中。
查询(GSI, PK = 'TYPEA', SK 以'USA#NY#NY#'开头, 过滤价格 > 100.00)
请注意,这种过滤方式不会节省任何读取容量,简单地过滤客户端可能更有效。
关键是您只需要(并且允许)表中每行 GSI 中的 1 行
唯一的问题是,您是否期望任何类型的数据超过 10GB?GSI,如 DDB 表本身每个分区有 10GB 的限制。如果您确实希望每种类型超过 10GB,我会重新考虑类型是有效访问模式的想法。没有人会滚动浏览 10GB 的数据。
老实说,我不喜欢不处理至少一种预期访问模式的 DDB 表。如果类型是驱动程序那么大,我会考虑这样的表:
Table
PK = TYPE
SK = ID
LSI
PK = (同表)
SK = COUNTRY#STATE#CITY
现在您的查询变为
- 查询(表,PK = 'TYPEA')
- 查询(LSI,PK = 'TYPEA',SK 以'USA#'开头)
- 查询(LSI,PK = 'TYPEA',SK 以'USA#NY#'开头)
- 查询(LSI,PK = 'TYPEA',SK 以'USA#NY#NY#'开头)
而且您不必为 GSI 支付额外费用。
编辑
在考虑价格过滤器时,它真的会对性能或成本产生很大影响吗?无论返回的数据是 1 行还是 100 行,您都需要为每个 1MB RCU 的数据付费。那么,您的行有多大,您希望过滤的价格差有多大?
除了发电机之外,您是否考虑过其他选择?Aurora RDS 肯定会提供您似乎需要的查询的灵活性,这要容易得多。或者也许在 DDB 之外添加 Elasticsearch。
推荐阅读
- reactjs - React-Bootstrap 需要 npm install bootstrap 和 bootstrap CDN 还是其中之一?
- kubernetes - Airflow 无法将日志写入 s3 (v1.10.9)
- php - Foreach 循环仅将数组中的最后一个值添加到表中
- r - 在 R 中,向量和数据帧被认为是有序集还是无序集?
- authentication - 发布/订阅请求身份验证作为服务(或通过服务密钥)而不是 Auth0 临时密钥
- google-apps-script - 忽略空单元格并跳过 Google 表格/日历同步中的重复条目
- c# - 如何打印数组?
- chart.js - Chart.js 仅绘制 y 轴直到点
- swift - 如何检查一个字符串是否包含另一个字符串但字符可以变化?
- php - 使用 PHP 以百分比形式获取磁盘使用率(负载)