检测并修复亚马逊文档数据库中的低基数索引

Amazon DocumentDB( 兼容 MongoDB )是一个完全托管的原生 JSON 文档数据库,可以轻松且经济高效地在几乎任何规模上运行关键文档工作负载,而无需管理基础设施。最佳做法是创建索引以提高查询性能,尤其是在数据库大小非常大的情况下。如果没有索引,查询必须运行更长的时间才能筛选出不符合条件的文档。另一种最佳做法是让数据库在高基数或具有大量唯一值的字段上创建索引。这篇文章介绍了如何主动检测和修复所有 DocumentDB 数据库和集合中的低基数索引。

亚马逊文档数据库 使用 B 树数据结构 作为其索 引。B 树索引使用分层结构,该结构按排序顺序将数据存储在其节点中。以这种方式保持数据排序允许以节省内存的方式读取、插入和删除数据。写入新数据时,除了修改集合中的文档外,索引也会更新,这可能会影响写入延迟并增加 IOPS。通过选择具有高基数的字段(具有大量唯一值的字段),例如标识字段,可以提高索引选择性。相反,选择低基数字段(例如布尔值),其中只有两个唯一值,可以检索到比所需更多的信息,这会增加内存使用量和进入分布式存储卷的风险。索引选择性的目标是允许查询预先过滤尽可能多的数据,从而减少查询处理器的工作量。

当您运行数十或数百个 Amazon DocumentDB 集群时,主动检测和监控基数变化非常重要。尽管在某些情况下可能需要低基数索引,或者集合足够小以至于目前不会造成任何问题,但在许多情况下,大型集合的低基数索引会导致性能问题。在这篇文章中,我们将介绍审查和修复现有 Amazon DocumentDB 集群的低基数索引的步骤。

为了演示这一点,我们使用 Amazon DocumentDB 示例存储库 中提供的示例数据集 和以下 GitHub 存储库 中提供的实用程序 来查找基数较低的索引。

低基数检测实用程序概述

此实用程序可以对 DocumentDB 集群的每个集合中的文档(默认每个索引 100K)进行采样,以创建基数报告。然后,用户可以查看此报告,重点关注低于建议的 1% 基数的指数。该脚本会对每个集合的随机样本进行集合扫描,根据样本大小和实例类型,它可能会影响持续的工作负载。你可以在非生产环境中运行它,也可以使用不主动提供流量的读取器实例。

GitHub 存储库包含有关如何加载示例数据、创建测试索引和运行基数测试的说明。如果你在自己的集群上运行它,你可以跳到自文件中记录的步骤 6。

下表汇总了基数测试脚本支持的参数。除了 --connection-string 之外 ,其余都是可选参数。默认情况下,基数测试在所有数据库和集合上运行。您可以通过传入--database 或 --collections 参数将测试范围缩小到单个数据库 集合

Parameter Details Default
--uri Connection string of Amazon DocumentDB instance. N/A
--max-collections Maximum number of collections to scan in a database. 100
--threshold Index cardinality threshold percentage. Indexes with less than this percentage will be reported. Value should be numeric integers or decimal type. 1
--databases Command separated list of databases to check cardinality. All
--collections Command separated list of collections to check cardinality. All
--sample-count Max documents to sample for each index. Increasing this limit may result in higher IOPS cost and extended runtime. 100000

先决条件

用于运行该实用程序的主机必须满足以下先决条件:

  • 通过 ssh-tunnel 或在同一 VPC 内的 亚马逊弹性计算云(亚马逊 EC2) 实例外壳中通过 CLI 访问 DocumentDB 集群。
    • Python 3.9+ 安装了 Pandas
  • Mongo 客户端 4.0+

设置并运行基数检测实用程序

要配置和使用该实用程序,请执行以下操作:

  1. 通过 mongo 外壳连接到亚马逊 DocumentDB(确保您的集合中有索引)。你可以在 mongo shell 中运行以下查询:
    
    db.getCollectionNames () .foreach(函数(集合){print(集合 + “:” + db [集合] .getIndexes () .length + ',计数:'+ db [collection] .count ());输出显示集合列表、索引

    总数和每个集合中的文档总数。 我们的示例 数据库 只有一个名为 sample collection 的集合,包含 6 个索引和超过 300, 000 个文档。请注意,其中包括 _id 索引,该索引作为基数检测的一部分被排除在外。

  2. 从 GitHub 下载项目和 DocumentDB 连接证书。
    
    git clone https://github.com/awslabs/amazon-documentdb-tools.git cd 性能/索引基数检测 wget https://truststore.pki.rds.amazonaws.com/global/global-bundle.pem 
     
    
  3. 在亚马逊文档数据库控制台上查找亚马逊 DocumentDB 集群或读取器终端节点。导航到您的数据库,然后选择 “ 配置 ” 选项卡。复制并保存该端点。
  4. 运行该实用程序,将变量 [DOCDB-USER] 、[DOCDB-PASS] 和 [DOCDB-ENDPOINT] 替换为集群的信息
    
    Python3 detect-cardinality.py —uri “mongodb://[DOCDB-USER]: [DOCDB-PASS] @ [DOCDB-ENDPOINT]: 27017/?

    tls=true&tlscafile=Global-bundle.pem” 脚本可能需要几分钟才能完成。 输出将与以下屏幕截图类似:

    在此示例
    中,脚本发现 5 个索引中,有 3 个(忽略 _id 索引)低于 1% 的低基数阈值。该脚本还将包含详细报告的 CSV 文件保存在当前目录中,该文件类似于以下屏幕截图:

该报告显示,C ase_Type 省份_类型 国家/地区 是基数较低的指数 ,可能不是索引的理想候选指标。

此实用程序可能会读取大量数据(每个索引有 100,000 个文档),因此建议在 QA 或代表性环境中运行此脚本。为了安全起见,你可以在非高峰时段运行它。您也可以 克隆 生产集群并在克隆集群上运行基数检测。

修复低基数指数

本节介绍如何修复索引基数检测实用程序生成的报告中发现的低基数索引。

删除未使用的索引

索引通常处于未使用状态,因为要求已更改或创建索引是错误的。Amazon DocumentDB 会统计索引的使用次数。有关如何查找和删除未使用的索引的说明,请参阅 如何分析索引使用情况和识别未使用的索引? 建议删除已使用的索引,无论其基数是否低。

如果可能,建立复合索引

在这篇文章中提到的示例中,我们检查了 样本收集 指数的基数,发现三个基数较低的索引:案例类型、国家/地区和省份。 如果用户同时搜索所有三个搜索子句,则构建复合索引而不是添加多个搜索子句是有意义的。你可以用下面的代码来做到这一点:

db.samplecollection.createIndex({
 'Case_Type':1,
 'Country_Region':1,
 'Province_State':1
})

为了确保复合索引得到利用,查询中提供的字段的顺序必须与索引的顺序相同。根据集合的大小,可能需要几分钟到几小时才能完成索引的创建。如 管理 Amazon DocumentDB 索引 中所述,您可以通过增加后台工作的工作人员来加快流程。成功的构建与以下屏幕截图类似:

创建索引后,您可以查看解释 E xecutationStats 状态的查询,以确保索引已被使用,并且 nRetur ned 属性 显示的数字较小

您可以使用类似于以下内容的查询进行测试:

db.samplecollection.find( {
'Case_Type':'Confirmed',
'Country_Region': 'China',
'Province_State': 'Guizhou'
}).explain('executionStats')


前面的查询大规模运行的成本较低。确认索引已创建后,您可以保留复合索引并删除不再使用的索引。这还有助于减少存储空间并可能提高数据采集性能。

清理

以下命令将删除作为Github项目中描述的说明的一部分而创建的数据库、集合和索引。如果您没有使用所使用的示例数据库,请跳过此测试。

use sampledatabase; 
db.dropDatabase();

结论

当您的集合大小开始增长到数百万个文档,并且您必须不断扩展实例以满足内存和 CPU 要求时,低基数通常会成为一个问题。这使得基数卫生对于大型馆藏非常重要,但也最好密切关注小型馆藏的基数,因为它们将来可能会带来问题。在这篇文章中,我们解释了如何使用 基数检测脚本 来主动监控索引的运行状况,并在基数阈值低于建议值时向应用程序团队报告。

在评论部分发布您的问题或反馈,或者创建一个 Github 问题,建议对脚本进行改进。


作者简介

Puneet Rawal 是一位驻芝加哥的高级解决方案架构师,专门研究 亚马逊云科技 数据库。他在架构和管理大型数据库系统方面拥有 20 多年的经验。