# 測定データの補足

2026-10-28実験。PostgreSQL 16.13、Python 3.11.2、asyncpg 0.31.0、Linux/aarch64、Raspberry Pi 5。
同一マシン内のUnixソケットで接続。DBは0.5 CPU / 768 MiB、クライアントも別に0.5 CPU / 256 MiB。
CPU制限周期は10ms。20,000行のデータをウォームアップした読み取り専用の実験です。
shared_buffers=64MiB、work_mem=1MiB、JIT無効、並列クエリ無効、max_connections=110で固定。
接続プール5/20/100は、測定前に指定本数すべてを確立・事前実行してから使用しています。

## ファイルと列

- summary.csv: 条件別の全測定値を集約。lightは各7,200件、heavy/heavy_burstは各1,440件。
- runs.csv: 27回の集約値。run_idで全リクエストと対応。
- requests.csv: 30,240件の生データ。内部ホスト、アカウント、絶対時刻、認証情報は含まない。

light: 主キー1行検索を5msごと（200件/秒）。
heavy: 2,000行のMD5集約を25msごと（40件/秒）。
heavy_burst: 同じ集約を10件ずつ250msごと（40件/秒）。
各回2秒ウォームアップ後に12秒の予定送信を実行。条件ごとに3回、プール順序をローテーション。
すべての予定リクエストを完了まで観測。件数/秒は観測秒数で割った値であり、最大処理能力ではない。

scheduled_s、start_s、end_sは各回開始からの相対秒数。
latency_msは予定送信からプール返却完了まで。
schedule_lag_ms、pool_wait_ms、query_roundtrip_ms、release_msの合計がlatency_ms。
query_roundtripはクライアントから見た往復時間で、DB内部の純粋なSQL実行時間ではない。
releaseにはasyncpgの標準接続リセットを含む。workerは互換用の列で0固定。

本文の「遅い側の応答時間」は、測定値を昇順に並べ、`ceil(件数×0.99)`番目を取ったもの。
CSVでは既存の列名`latency_p99_ms`などに収めています。列名と数値は変更していません。
summary.csvの値は条件ごとの3回全件から計算し、各回の値の平均ではありません。
`run_p99_min_ms`と`run_p99_max_ms`は、各回に同じ方法で求めた値の最小・最大で、信頼区間ではありません。
区間の平均は全件の算術平均。各区間の遅い側の値を足して、全体の遅い側の応答時間を求めることはできません。

db_cpu_coresとclient_cpu_coresは1コア=1。usage_usecの増分を観測秒数で割る。
条件別CPUは観測秒数で重み付け。db_cpu_quota_percentは0.5コア上限=100%。
db_throttled_periods_percentはcpu.statのnr_throttled増分 / nr_periods増分。遅延時間の割合ではない。
db_memory_mibは各回のmemory.current開始・終了値の平均をさらに3回で平均したもの。
共有メモリやページキャッシュなどを含み、接続1本あたりの固有メモリではない。
max_concurrent_query_roundtrips_derivedはクライアント区間から求めた最大同時往復数で、DB内で同時にCPUを使った数ではない。

## 測定ブロックの境界

r01〜r11の後、安全監視で停止。r12〜r27は同設定・データの一時DBを作り直して実行。
再開時に変更したのは測定後の接続切断を順次行う点。測定中のSQL・送信予定・資源上限・ウォームアップは同じ。
完全に連続した1回の実験ではなく、共有ホストの変動も分離していない点に注意。
これ以前のclosed-loop予備試行は集計に含まない。

## SQL

```sql
CREATE UNLOGGED TABLE pool_lab (
  id integer PRIMARY KEY, balance integer NOT NULL, payload text NOT NULL
);
INSERT INTO pool_lab
SELECT i, i % 1000, repeat(md5(i::text), 4)
FROM generate_series(1, 20000) AS i;
VACUUM ANALYZE pool_lab;
```

軽い検索は `SELECT balance FROM pool_lab WHERE id = $1`。
重い検索は `SELECT sum(length(md5(payload || id::text))) FROM pool_lab WHERE id BETWEEN $1 AND $1+1999`。
各回のリクエスト連番sequenceから、lightでは `(sequence*193)%20000+1`、その他では `(sequence*193)%18001+1` を$1に使う。
両方のSQLを混在させず、条件ごとに測る。

仕様の参照先: [asyncpg](https://magicstack.github.io/asyncpg/current/api/index.html#connection-pools)、
[PostgreSQL 16](https://www.postgresql.org/docs/16/runtime-config-connection.html)、
[Linux cgroup v2](https://docs.kernel.org/admin-guide/cgroup-v2.html#cpu-interface-files)。
