DynamoDB中的Scan和Query有什么区别?何时使用Scan / Query?

113

根据DynamoDB文档所述:

查询操作仅搜索主键属性值,并支持对键属性值的一部分比较运算符以细化搜索过程。

而扫描操作:

扫描操作扫描整个表。在完成扫描后,您可以指定筛选器应用于结果以精细化返回给您的值。

基于性能和成本,哪种方法更好?

5个回答

76

创建Dynamodb表时,请选择主键和本地辅助索引(LSIs),以便查询操作返回您想要的项目。

查询操作仅支持对主键进行等值运算符的评估,但可以在排序键上进行条件(=、<、<=、>、>=、Between、Begin)。

扫描操作通常较慢且更昂贵,因为操作必须遍历表中的每个项目才能获取您请求的项目。

示例:

Table: CustomerId, AccountType, Country, LastPurchase

Primary Key: CustomerId + AccountType

在这个例子中,你可以使用查询操作来获取:

  1. 一个带有 AccountType 条件过滤器的 CustomerId

需要使用扫描操作来返回:

  1. 具有特定 AccountType 的所有客户
  2. 基于国家条件过滤器的项目,即来自美国的所有客户
  3. 基于最近购买条件过滤器的项目,即在最近一个月内进行购买的所有客户

为避免频繁使用扫描操作,在常用操作上创建本地辅助索引(LSI)或全局辅助索引(GSI)。

例如:

Table: CustomerId, AccountType, Country, LastPurchase

Primary Key: CustomerId + AccountType
GSI: AccountType + CustomerId
LSI: CustomerId + LastPurchase
在这个示例中,查询操作可以让您获取以下内容:
  1. 一个具有关于帐户类型的条件过滤器的客户ID
  2. [GSI] 特定帐户类型的客户ID上的条件过滤器
  3. [LSI] 具有关于最后购买的条件过滤器的客户ID

1
如果主键是:CustomerId + AccountType(我理解CustomerId是分区键,而AccountType是排序键),那么您只能通过CustomerId或者CustomerId + AccountType运行查询操作。如果您仅按AccountType搜索,则会进行全表扫描。 - Adil
1
谢谢 @Adil。你说得对,我已经编辑了我的回答以反映这一点。 - Kinman
GSI: https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GSI.html,而对于LSI:https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/LSI.html - Kinman

39

如果您将DynamoDB表的分区键/主键设为customer_country,那么在使用查询操作时,customer_country是必填字段。所有筛选器只能用于属于customer_country的项目。

如果您执行表扫描,则过滤器将执行在所有分区键/主键上。首先获取所有数据,然后在从表中获取到数据之后应用过滤器。

例如:

这里customer_country分区键/主键,而id则是排序键

-----------------------------------

customer_country | name   | id

-----------------------------------
VV               | Tom    | 1

VV               | Jack   | 2

VV               | Mary   | 4

BB               | Nancy  | 5

BB               | Lom    | 6

BB               | XX     | 7

CC               | YY     | 8

CC               | ZZ     | 9

------------------------------------
  • 如果您执行查询操作,则仅应用于 customer_country 值。该值应仅为等于操作符(=)。

  • 因此,仅获取与该分区键/主键值相等的项目。

  • 如果执行扫描操作,则会获取该表中的所有项目,并在提取数据后过滤数据。

注意:不要执行扫描操作,否则会超出您的 RCU。


请问您能否说明您答案的来源? - AlikElzin-kilaka
2
@AlikElzin-kilaka 来源: https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/bp-query-scan.html - OK200
上面的 customer_country 是分区键/主键 本身就是错误的陈述。在查看 customer_country 列中的重复值后,我不认为它是主键。 - ajaysinghnegi

15

这类似于关系型数据库。

如果在where条件中使用主键,那么您获取的query查询的计算复杂度为log(n),因为大多数键结构都是二叉树。

scan查询需要扫描整个表格,然后对每个单独的row应用过滤器以找到正确的结果。性能为O(n), 如果表很大,它会慢得多。

简而言之,如果您知道主键,请尝试使用query。只有在最坏的情况下才使用scan

此外,考虑使用全局辅助索引来支持不同类型的查询以获得更好的性能。


12

就性能而言,我认为设计表格时最好让应用程序使用查询(Query)而不是扫描(Scan)。因为扫描操作总是在过滤所需值之前扫描整个表,这意味着处理读、写和删除等数据操作需要更多的时间和空间。欲了解更多信息,请参阅官方文档


10

在性能方面,查询 (Query) 比扫描 (Scan) 要好得多。扫描会扫描整个表格,正如其名称所示。但是您必须熟悉表格键、排序键、索引以及相关的排序索引,才能知道是否可以使用查询。

  • 如果您使用以下过滤器进行查询:
  • 键 (key)
  • 键和键排序(key & key sort)
  • 索引 (index)
  • 索引及相关的排序键

请使用查询!否则使用扫描,它对于可以过滤的列更加灵活。

以下情况不能使用查询:

  • 过滤器中有超过 2 个字段(例如,键、排序和索引)。
  • 仅排序键(主键或索引)。
  • 常规字段(非键、索引或排序)。
  • 混合索引和排序 (index1 with sort of index2)。
  • ...

一个很好的解释:https://medium.com/@amos.shahar/dynamodb-query-vs-scan-sql-syntax-and-join-tables-part-1-371288a7cb8f


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接