これを理解するには、そもそも読み書きがシンプルでないケースについて学ぶのが良いと思います。
シンプルでない書き込みの典型的な例がトランザクションです。トランザクションを使うと、複数の箇所に書き込みを行ってもコミットという特殊な操作を明示的に行うまではそれらの書き込みが他の人からも見えず、更には途中で中止や電源断が起きたら勝手に元通りに戻ります。
これを実現するためには必然的にコミット前と後の両方の情報を他者が復元できる形で永続化する必要があり、読み出しを行う際にも他人が書きかけであるかどうかを認識して読まないor読んで良いものだけ読むというトリックが必要です。これらの実現手段には様々なバリエーションがあり、どこのレイヤーで実現するかによっても効率は大きく変わるのですが総じて読み書きに必要なやり取りの量は増えざるを得ず高いパフォーマンスを出すのが難しくなります。
https://docs.aws.amazon.com/ja_jp/amazondynamodb/latest/developerguide/transaction-apis.html
https://docs.aws.amazon.com
DynamoDBは実はトランザクションをサポートしており、コーナーケースを無視すればそれっぽい動きはするようです。ただし「トランザクションの項目ごとに 2 つの読み取りまたは書き込みオペレーションを実行するのに十分なスループット容量をプロビジョニング」と書いてあるところを見るにおよそ倍のスループット容量を消費するつもりで総量を設計する必要があるようです。つまりトランザクションを行うと悪くて1/2の性能になると言っています。
シンプルでない読み出しの一例がジョインです。RDBMSで複数のテーブルを内部のデータに基づいて結合する操作ですが、テーブルが大きくなると効率的にそれを処理する方法は多岐に渡ります。例えば5000万人の顧客を抱える携帯電話サービスで家族内で余剰な通信容量(通称ギガ)を分け合えるサービスを実施するとして、5000万行の顧客テーブルと3000万行の家族テーブルがあり、全部の顧客は一つの家族IDを持つことで対応する家族テーブルのどれか1行に紐付けられ(家族は同一の行に紐付けられる)ギガ残量は顧客毎に存在します。顧客テーブルを1行1000バイトと見積もると5000万行は50ギガバイトとなり普通のマシンのメモリには乗りません(今どきは電気屋でも64GBとか128GB積んだマシンは買えますが)。
1人の顧客としてあなたは「自分が今月あと何GBまで(家族のシェア分含めて)使えるのか」を知りたくなって問い合わせを行うと、サービス側はあなたの顧客IDを用いて5000万行の中から索引し、そこから分かった家族IDを用いて再び顧客IDに対して貼ったセカンダリインデックスを用いてあなたの家族全員を探し、それらのギガ残量を合計して返す、という処理を行う事になります。インデックスのお陰で全件を走査せずには済みますが発生するIO処理は何往復にも渡り結構な負荷がかかります。更に毎月、ギガを超過した分などを精算し料金を請求する必要がありますのでそれを5000万人の顧客全員に対して実行すると1人あたり0.01秒で済んでも138時間(5.7日)かかります。シンプルに見えますがこれを間違いなく実施する事は遥かに大変で携帯キャリア各社は何億円も設備投資してこの計算を行っています。
DynamoDBはジョイン操作や集計などの処理をサポートしていないため、当然ながらDynamoDBの外でサービスに必要な集計などを行う必要があります。大抵のRDBMSはそれらを効率的に実行できるように工夫が凝らされているので原則としてはRDBMSのオプティマイザを頼って全部依頼するのが定石の一つですが、扱っているデータや処理量が大き過ぎる場合はDynamoDBなどをデータ置き場として利用するだけにとどめ、集計に相当する処理をプログラマが実装せざるを得ない事もあります。サービスとして必要な処理はDBなりアプリサーバなりがどうにか実行しなくてはならない以上、どこで実施するのが一番効率的でメンテしやすく経済的かつ変更に強いかを加味しながらバランスの良い設計をするのがソフトウェアエンジニアの腕の見せ所、というのがデータ指向アプリケーションデザイン(通称イノシシ本)の主張です。まぁ大抵はSQLで行けるとこまで行くのがおすすめですが…。