初級読了 3 分

DynamoDB を降順にクエリする方法

デフォルトでは DynamoDB の Query はアイテムを昇順のソートキー順で返します。しかし たいていの「最新をくれ」というアクセスパターンは、その逆——新しい順を望みます。つまみは Query 上の単一のブール値、ScanIndexForward です。これを false に設定すると、同じ クエリがパーティションを逆向きに読みます。

パラメータは1つですが、人をつまずかせます。事後に_結果_をソートすること (DynamoDB は それをしません) と混同しやすく、名前が制御する内容とは逆向きに読めるからです。

DynamoDB を降順にクエリするにはどうしますか?

QueryScanIndexForward=false を設定します。デフォルトでは DynamoDB は アイテムを昇順のソートキー順で返します。この単一のブール値を反転させるとパーティションを 逆向きに読み、ソートキーがタイムスタンプやシーケンスのときに新しい順の結果が得られます。 変わるのは順序だけで、どのアイテムが一致するかは変わらず、逆向きの読み取りは順方向と まったく同じコストです。

  • ScanIndexForward=true (デフォルト) → 昇順のソートキー順。
  • ScanIndexForward=false → 降順——ソートキーがタイムスタンプやシーケンスのときは 新しい順。
  • 影響するのは順序だけで、どのアイテムが一致するかではありません——それはやはりキー 条件が決めます。
  • 無料です。 逆順は順方向と同じコストです。DynamoDB はどちらにせよパーティションの 格納順を読みます。
  • Limit と併用して、「最新の N 件」を1回の安い読み取りで得ましょう。

問題:「最新を先に見せて」

マルチプレイヤーのリーダーボードを運営していて、各プレイヤーのスコアイベントを1つの パーティションキーの下に、増加するタイムスタンプでソートして格納しているとします。

PK: GAME#42   SK: SCORE#2026-06-27T10:00:00Z   points
PK: GAME#42   SK: SCORE#2026-06-27T10:05:00Z   points
PK: GAME#42   SK: SCORE#2026-06-27T10:09:00Z   points

ダッシュボードは最新のスコアを必要とします。GAME#42 への素の Query はそれらを 古い順に返すので、すべてを読んでアプリで反転したくなります——無駄で、Limit を追加した 瞬間に壊れます。DynamoDB は直接それらを新しい順で返せます。

ScanIndexForward の仕組み

パーティション内のアイテムは、物理的にソートキーで順序付けて格納されます。Query は その順序を歩き、ScanIndexForward は歩く方向を選ぶだけです。

  • true (デフォルト) — 最も低いソートキーから始めて、上へ歩く (昇順)。
  • false — 最も高いソートキーから始めて、下へ歩く (降順)。

肝心なのは、これは読み取りの性質であって、テーブルの性質ではないことです——同じ アイテム、同じキー条件で、逆にするだけです。そして DynamoDB はすでにソートされたデータに 対して方向を選んでいるだけなので、降順の読み取りは昇順と まったく同じくらい安い です。Limit=10 と組み合わせれば、「最新の 10 件のスコアイベント」を単一の最小コストの Query で得られます。

true(既定)falseQuery GAME#42ScanIndexForward?古いスコアが先新しいスコアが先

1つの微妙な点:降順の結果セットを後方にページングするとき、 LastEvaluatedKey/ExclusiveStartKey のカーソルはやはり機能します——ただし同じクエリの すべてのページを通じて ScanIndexForward=false を一貫させてください。さもないとカーソルの 方向と順序が食い違います。

DynoTable でクエリを組み立てる

キー条件そのものを組み立てる (そして対応する属性名/値のマップを見る) には、 DynamoDB 式ビルダーを使いましょう。リクエスト全体 — インデックス、LimitScanIndexForward を含めて — は、 クエリビルダーが Query を組み立て、実行可能な SDK v3、CLI、boto3 のプログラムを出力します。

DynoTable では、選んだキーでタブを読み、タブのソート方向をトグルで設定します—— ScanIndexForward を手書きする必要はありません。反転させて新しい順の結果をプレビュー しましょう。

DynoTable でクエリタブを降順 (新しい順) に切り替えている様子。
DynoTable でクエリタブを降順 (新しい順) に切り替えている様子。

落とし穴と次のステップ

  • ScanIndexForward は反転するのであって、任意の属性でソートするのではない。 順序は 常にソートキーによります——他の何かでソートするには、その属性を (しばしば GSI経由で) ソートキー_として_持つ必要があります。
  • アプリで全部読んで反転しない。 フラグを設定して Limit を追加しましょう。
  • ページング中はフラグを一貫させる。 複数ページのクエリで、さもないとカーソルが順序と 争います。
  • 数値で新しい順にしたい? Number 型のソートキーはすでに数値でソートされます。数値を 文字列のソートキーに埋め込んだ場合にのみ、辞書順が一致するよう ゼロ埋めする必要があります。
  • 関連:ソートキー戦略ページネーション

API パラメータに触れずに結果の順序を反転したいですか? DynoTable をダウンロードして、自分のテーブルを直接クエリしましょう。

複合ソートキーと数値ソートキー

降順は「最新」というこちらの頭の中のモデルではなく、ソートキーの型のルールに従います。

ソートキーの保存形式降順で得られるもの落とし穴
ISO-8601 の UTC 文字列 2026-06-27T10:09:00Z最も新しいタイムスタンプが先頭タイムゾーンを固定すれば、辞書順が時系列と一致する
ゼロ埋めしたエポック文字列 00000000001009最も大きいシーケンスが先頭ゼロ埋めしない数値は誤って並ぶ("9" > "10")— ゼロ埋めを参照
Number 型 N最も大きい数値が先頭文字列ではなく、自然な数値順
ステータス接頭辞 STATUS#open#...SK 全体に対する逆辞書順接尾辞に符号化していない限り、「最近開いた順」とは別物

「最新」がソートキー以外の何か(たとえば同じゲームのパーティション内で points 順)を意味する なら、その指標はソートキーの中(あるいはソートキーが points の GSI)に必要であって、 アプリケーションコードでのクエリ後のソートでは足りません。

降順の読み取りにおける Limit

Limit が上限を設けるのは評価されたアイテム数であって、フィルター後に返るアイテム数では ありません。時系列のソートキーに対して ScanIndexForward=falseLimit=10 を組み合わせれば、 1 回のパーティション読み取りで直近 10 件のイベントを取得できます。

コストの例: 1 回の降順 Query で 2 KB のアイテム 10 件は 20 KB に触れ、結果整合性で 3 RCU に なります(4 KB ブロック単位に切り上げ)。アプリケーションコードで反転するために 10,000 件の イベントを持つパーティション全体を読むと、およそ 20 MB に触れ、同じ UI ウィジェットのために 数千 RCU がかかります。Limit を決める前に、アイテムサイズ計算ツールで パーティションの大きさをモデリングしましょう。

ページングも方向を保つ

ExclusiveStartKey でページングするときは、すべてのリクエストで ScanIndexForward を同じに 保ってください。ページの途中でフラグを反転すると、カーソルの意味が逆になります — 行を飛ばしたり 重複させたりする可能性があります。

「もっと読み込む」を公開する API では、LastEvaluatedKey を不透明な base64 として符号化しましょう。 クライアントがソートキーの構成要素を書き換えるべきではありません。トークンのパターンについては ページネーションを参照してください。

PartiQL と SDK の対応

PartiQL の ExecuteStatement クエリは、実行系がキー条件による読み取りに対応づけられる場合、 下層の Query パラメータを通じて同じ順序のセマンティクスを受け取ります。 クエリビルダーScanIndexForward を明示的に組み込んだ SDK v3、CLI、boto3 のプログラムを出力します — チームが PartiQL のアドホックなクエリと本番の SDK コードを併用している場合に役立ちます。

降順を使うアクセスパターン

  • アクティビティフィードSK は ISO のタイムスタンプ。降順と Limit で直近のウィンドウが 得られます。
  • リーダーボード — 数値のソートキー score。パーティションキーが 1 つのゲームやシーズンに 絞られていれば、降順で上位スコアが浮かび上がります。
  • 監査ログ — 追記のみの EVENT#<ts> ソートキー。GSI なしで、降順が最新のイベントを先頭に 表示します。

UI が昇順の履歴(「古い順に表示」)も必要とする場合、同じクエリを ScanIndexForward=true で 実行すれば、データを二重に持ったりインデックスを 2 本維持したりせずに済みます。

実データでトグルを試す

DynoTable を接続し、時系列のソートキーを持つパーティションでクエリタブを開き、昇順と降順を 切り替えて、API パラメータを編集せずにグリッドが並び替わるのを見てください。オペレーション ログで消費キャパシティを比べましょう — 同じ Limit での順方向と逆方向の読み取りは一致するはずです。

更新日