[アップデート] Amazon DocumentDBで部分インデックスがサポートされました

Amazon DocumentDBで部分インデックスがサポートされたので試してみました。
2024.02.27

こんにちは。サービス開発室の武田です。

Amazon DocumentDBで部分インデックスがサポートされました。エンジンバージョンが5.0以降、インスタンスベースクラスターのみとなっています!

ちなみにMongoDBでは3.2からサポートされていました。もともとオンプレなどの環境で使用していた方は待望のアップデートでしょうか。

検証環境の構築

検証環境としてDocumentDBクラスター、接続するためのサーバーが必要となります。今回はDocumentDBへ接続する環境としてCloud9を利用します。

DocumentDBはインスタンスベースであること、エンジンバージョンが5.0.0であることに注意しましょう。インスタンスクラスなどは検証なので低いものにしておきます。

Cloud9は同じVPC内に構築します。設定はすべてデフォルトで問題ありません。

Cloud9の環境作成後、DocumentDBへ接続できるようにセキュリティグループの設定を変更する必要があります。Cloud9構築時にアタッチされたセキュリティグループがありますので、DocumentDBクラスターに紐づいているセキュリティグループのインバウンドに許可設定を追加します。

以上の設定が完了したらCloud9 IDEを開きましょう。

Cloud9からDocumentDBに接続する

それではさっそくDocumentDBに接続し、部分インデックスを試してみましょう。

DocumentDBはMongoDB互換のため、各種エコシステムを利用できます。MongoDBにはREPL環境であるMongoDB Shell(mongosh)がありますのでこれを使用しましょう。mongoshはいくつかの提供形態がありますが、今回はyumを使用します。次の内容で/etc/yum.repos.d/mongodb-org-7.0.repoを作成します。

/etc/yum.repos.d/mongodb-org-7.0.repo

[mongodb-org-7.0]
name=MongoDB Repository
baseurl=https://repo.mongodb.org/yum/amazon/2023/mongodb-org/7.0/x86_64/
gpgcheck=1
enabled=1
gpgkey=https://pgp.mongodb.com/server-7.0.asc

ファイルが準備できたら、次のコマンドでmongoshをインストールします。

sudo yum install -y mongodb-mongosh-shared-openssl3

続いてDocumentDBに接続していきます。まず次のコマンドを実行して証明書をダウンロードします。

wget https://truststore.pki.rds.amazonaws.com/global/global-bundle.pem

ダウンロードできたらmongoshを起動しましょう。USERNAMEPASSWORDは自分の環境に合わせてください(もちろんホスト名も)。

mongosh --tls --host docdb-2024-02-27-01-48-01.cjjms3a2tkhy.ap-northeast-1.docdb.amazonaws.com:27017 --tlsCAFile global-bundle.pem  --retryWrites=false --username USERNAME --password PASSWORD

部分インデックス試してみた

接続できたらいくつかクエリを実行して動作を確認しましょう。まずはデータの準備です。次のようなワンライナーで100件のサンプルデータを投入しました。

> db.users.insertMany([...Array(100).keys()].map((n) => {return { userid: n * 1000, name: `hoge${n}`, age: Math.floor(Math.random() * 60) + 15 }}));

このようなデータが作成されます。

> db.users.find().limit(3)
[
  {
    _id: ObjectId('65dd7d669fdeb2000428c539'),
    userid: 0,
    name: 'hoge0',
    age: 43
  },
  {
    _id: ObjectId('65dd7d669fdeb2000428c53a'),
    userid: 1000,
    name: 'hoge1',
    age: 31
  },
  {
    _id: ObjectId('65dd7d669fdeb2000428c53b'),
    userid: 2000,
    name: 'hoge2',
    age: 56
  }
]

投入できたらクエリおよび実行計画を確認します。

> db.users.find({ userid: 30000 }).explain();
{
  queryPlanner: {
    plannerVersion: 1,
    namespace: 'test.users',
    winningPlan: { stage: 'COLLSCAN' }
  },
  serverInfo: { host: 'docdb-2024-02-27-01-48-01', port: 27017, version: '5.0.0' },
  ok: 1,
  operationTime: Timestamp({ t: 1709013613, i: 1 })
}

> db.users.find({ userid:{ $gte: 30000 }, age: { $gt: 40 } }).explain();
{
  queryPlanner: {
    plannerVersion: 1,
    namespace: 'test.users',
    winningPlan: { stage: 'COLLSCAN' }
  },
  serverInfo: { host: 'docdb-2024-02-27-01-48-01', port: 27017, version: '5.0.0' },
  ok: 1,
  operationTime: Timestamp({ t: 1709013676, i: 1 })
}

注目は winningPlan: { stage: 'COLLSCAN' } の部分です。これはいわゆるフルテーブルスキャンに相当するもので、コレクションすべてを走査します。

次に部分インデックスを作成します。今回はageが40より大きいドキュメントに対してインデックスを張ります。

> db.users.createIndex({ userid: 1 }, { partialFilterExpression: { age: { $gt: 40 } } });

それでは先ほどと同じクエリを実行してみます。

> db.users.find({ userid: 30000 }).explain();
{
  queryPlanner: {
    plannerVersion: 1,
    namespace: 'test.users',
    winningPlan: { stage: 'COLLSCAN' }
  },
  serverInfo: { host: 'docdb-2024-02-27-01-48-01', port: 27017, version: '5.0.0' },
  ok: 1,
  operationTime: Timestamp({ t: 1709013708, i: 1 })
}

> db.users.find({ userid:{ $gte: 30000 }, age: { $gt: 40 } }).explain();
{
  queryPlanner: {
    plannerVersion: 1,
    namespace: 'test.users',
    winningPlan: { stage: 'IXSCAN', indexName: 'userid_1', direction: 'forward' }
  },
  serverInfo: { host: 'docdb-2024-02-27-01-48-01', port: 27017, version: '5.0.0' },
  ok: 1,
  operationTime: Timestamp({ t: 1709014383, i: 1 })
}

find({ userid: 30000 })COLLSCAN のままです。一方でfind({ userid:{ $gte: 30000 }, age: { $gt: 40 } })のクエリは IXSCAN に変わっています。これはインデックスが正しく使用されていることを示しています。

まとめ

DocumentDBで部分インデックスがサポートされました。現在稼働している環境があれば、ぜひインデックスの見直しなどしてみてください。