上限は950MB/sでした。
その「○秒」という数字、どのサイズで、何回目に測ったものですか。
同じツール・同じファイルでも、この2つを変えると勝敗はひっくり返ります。連載で出してきた実測を並べ直すと、向きが変わる境界線がはっきり4本見えました。
今回は連載の締めとして、その4本——「対応容量」という表記が意味しないこと、索引が終わるまで先頭しか見えない設計、秒数より「何回読むか」、そしてログではない巨大テキスト——を、数字の読み方として整理します。
- 先に結論: UwView は 258.68GB・45億行の1ファイルを、索引作成中から末尾まで読めます(索引の完了まで5分28秒=約789MB/s)。Pro は索引と圧縮を保存するので、2回目以降は行番号付きで瞬時に開き直せます(47.73GBのテキストで実測0.02〜0.07秒)。ただし「開くだけ」の速度では klogg に負けています(51GBで52.55秒 対 100.6秒)。いずれも特定環境での測定例で、環境により異なります。詳細は記事末尾
- 1. 「対応容量」は、調査できる容量ではない
- 2. 索引が終わるまで、先頭しか見えない
- 3. 速さより「何回読むか」
- 4. 巨大テキストは、ログだけではない
- 4つに共通していたもの
- 使っている道具
- リンク
先に結論: UwView は 258.68GB・45億行の1ファイルを、索引作成中から末尾まで読めます(索引の完了まで5分28秒=約789MB/s)。Pro は索引と圧縮を保存するので、2回目以降は行番号付きで瞬時に開き直せます(47.73GBのテキストで実測0.02〜0.07秒)。ただし「開くだけ」の速度では klogg に負けています(51GBで52.55秒 対 100.6秒)。いずれも特定環境での測定例で、環境により異なります。詳細は記事末尾
本記事の数字はすべて、測定に使った1台・1本のファイルでの結果です。ディスクの種類・接続方式・ファイルシステム・ページキャッシュの状態で大きく変わるため、そのまま一般の性能比較として読まないでください。
1. 「対応容量」は、調査できる容量ではない
状況
48GBのファイルを渡されました。使っているエディタの仕様表には「ファイルサイズ無制限」と書いてあります。安心して開きます。
開きました。先頭が表示されます。
末尾へ飛ぼうとしたら、行けません。 見えているのは18,951行まで。ファイル全体は約8.92億行あります。
なぜ起きるか
「開ける」という言葉が、製品ごとに違う意味で使われているからです。
仕様表の「対応最大サイズ」は、たいてい「クラッシュせずに読み込みを開始できるか」を指しています。「読み込みが終わるまでどこまで操作できるか」は別の話で、そこは書かれていません。
約48GB・約8.92億行のOpenStreetMap日本データを Windows ノートPC(Core i7-1165G7・RAM 16GB・内蔵SSD)で開いたときの実測です。全体を読み込んでから操作させる作りのエディタでは、読み込み進捗がこう進みました。
- 1分14秒:29%
- 2分35秒:50%
- 4分06秒:100% ← ここでようやくファイル全域へ移動できる
- 索引作成の完了までは246秒
これは「普通のエディタの動作例」として読んでください。 巨大ファイル専用のモードを持つ製品もあり、そちらを有効にしたときの挙動は測っていないので、特定の製品名は出しません。 ここで言いたいのは製品の優劣ではなく、指標の話です。
つまり、仕様表の「無制限」と、作業を始められるまでの4分06秒は、まったく別の指標です。 そして後者のほうが、調査の体感を決めます(第1回)。
汎用ツールでの対処と限界
待たずに済ませたいなら、全体を開かないのが定石です。
# サイズと行数の見当をつける(行数の確定には全走査が要る)
ls -l osm-japan.osm
wc -l osm-japan.osm # 48GB では数分かかる
# 末尾だけ見る
tail -n 200 osm-japan.osm
# 必要な範囲だけ切り出す
split -b 2G osm-japan.osm part-
これで「見る」までは到達できます。
限界は3つ。
ひとつめ、split は原本を増やすこと。48GBを2GB刻みにすれば、24本と48GBの空き容量が必要です。そして分割点は内容を無視するので、XMLのタグやレコードの途中で切れます。
ふたつめ、tail で末尾は見えても、検索できないこと。末尾200行の外に答えがあれば、また全体に戻ります。
みっつめ、仕様表からは判断できないこと。「対応容量」「最大行数」の欄を比べても、4分06秒は出てきません。自分のファイルで測るしかないのが現状です。
2. 索引が終わるまで、先頭しか見えない
状況
ログビューアで50GBのログを開きます。プログレスバーが出ます。スクロールバーのつまみが、じわじわ小さくなっていきます。
見たいのは末尾です。障害は直前に起きているからです。
終わるまで、末尾に何が書いてあるかは分かりません。
なぜ起きるか
N行目へ跳ぶには、N行目が何バイト目から始まるかの表(索引)が要るからです。
テキストファイルに行の区切りはありません。改行を数えるまで「1億行目」の位置は分かりません。だから設計は3択になります。
- 全部作ってから見せる — 行番号は正確。ただし完成まで待つ
- 作らずに逐次読む — すぐ見える。ただし行番号が出ず、位置も分からない(
lessがこれに近い) - 裏で作りながら、全域を見せる — 待たない。ただし実装が難しい
多くのビューアが1番目を選ぶので、「索引が終わるまで先頭しか見えない」が起きます。
ここで大事なのは、待ち時間の大半はツールの怠慢ではないことです。klogg で 51.25GB のファイルを開くと 52.55秒。読み出し速度に直すと 930MB/s です。同じディスクの素読みが約 950MB/s なので、ほぼ出し切っています。
速度では、もうこれ以上縮みません。縮められるのは「待つかどうか」=設計のほうだけです。
汎用ツールでの対処と限界
末尾を先に見るなら、こうなります。
# 末尾から遡って読む
tac huge.log | head -n 500
# less は末尾へ行くとき全体を読む(G は待たされる)
less +G huge.log
# 行数を数えずに、末尾のバイトだけ取る
tail -c 5000000 huge.log | less
末尾は見えます。
限界は3つ。
ひとつめ、行番号が原本と一致しないこと。tail -c で切った先頭行は途中から始まっているので、そこを1行目と数えると全部ずれます。報告書には書けません(第24回)。
ふたつめ、「末尾のあたり」と「末尾から30分前」は別の問題だということ。時刻で遡りたいのに、手がかりがバイト位置しかありません(第7回)。
みっつめ、色分けも保存された検索条件も、そこには無いこと。素早く末尾を見る手段はあっても、見方を持ち込む手段がありません(第22回)。
3. 速さより「何回読むか」
状況
nginx のアクセスログから 5xx を追います。手順はいつもどおりです。
grepで 5xx を数えて当たりをつける- ビューアで同じファイルを開く
- ビューアの検索でその時刻へ行く
- 前後を読む
各手順は数十秒です。なのに、終わって時計を見ると1時間経っています。
なぜ起きるか
同じファイルを、何度も先頭から読んでいるからです。
50GB・950MB/s なら、1回の全走査は約54秒が物理的な下限です。手順1で1回、手順2で1回、手順3でもう1回読めば、それだけで約2分40秒。どれだけコマンドを磨いても、この回数は減りません。
実測でも同じ形になります。51GBで「探して、画面で読む」までの通し時間です。
| 51GB | |
|---|---|
| klogg(開く52.55秒 + 検索55.59秒) | 108.14秒 |
klogg は、開くのに1回、探すのにもう1回、ファイルを読みます。 1回あたりは930MB/s近くまで出ているので、遅いのではありません。読む回数が2回だから2倍かかる、というだけのことです。
ここが、単発コマンドの秒数比較では見えない部分です。grep 単体の速さを1割縮めるより、読む回数を2回から1回にするほうが効きます(第15回)。
汎用ツールでの対処と限界
回数を減らす方向の定石は、小さくしてから渡すことです。
# 5xx だけ、原本の行番号を付けて抜く
grep -n -E ' (5[0-9]{2}) ' access.log > 5xx.txt
# 件数と時刻の分布を見る(ここまでで原本は1回読み)
awk '{print $4}' 5xx.txt | cut -c2-15 | uniq -c | sort -rn | head
# 気になった行の前後を、原本の座標のまま見る
awk 'NR>=41284440 && NR<=41284470 { printf "%d\t%s\n", NR, $0 }' access.log
うまくいきます。grep -n で行番号を持ち回るだけで、後段が原本を指し直せます。
限界は3つ。
ひとつめ、最後の awk でまた1回読むこと。行番号が分かっていても、そこへ跳ぶ手段が標準ツールにはありません。「もう少し前も見たい」と思うたびに54秒です。
ふたつめ、中間ファイルが増えること。5xx.txt は原本ではありません。これを配ると、どのファイルのどの範囲を抜いたものかが、すぐ分からなくなります(第24回)。
みっつめ、パイプでは回数が減らないこと。grep | awk | sort は1回読みですが、質問が変われば、また先頭から読み直します。 2問目・3問目のたびに全走査が走るのが、この経路の構造です。
4. 巨大テキストは、ログだけではない
状況
地図データを調べることになりました。OpenStreetMap のアメリカ全土(PBF形式・約11GB)を、osmium cat でXMLに展開します。約15分後、出てきたのがこれです。
us-260726.osm
258,679,440,228 byte = 258.68 GB(240.9 GiB)
分割されていない、1本のXMLファイルです。 行数は 4,509,830,821行(45億行)。ログではないので、ローテートもされません。
なぜ起きるか
交換フォーマットは、人間が途中を覗く前提で設計されていないからです。
ログはローテートされ、日付で切られます。ところが地図データ、SQLダンプ、NDJSON、シミュレーション出力は、1本で完結していることに意味があるので、切られません。そして展開すると数百GBになります。
- XMLは1要素1行になりがち — 45億行という数は、行が短いことの裏返しです
- 専用ツールは「処理」が前提 —
osmiumもxmlstarletもjqも、変換や抽出には強いのに、まず目で見るのには向きません(第9回) splitが構造を壊す — バイト数で切れば、タグの途中で切れます
このサイズでの実測も出しておきます。macOS 実機で、258.68GB を全走査して索引を作り終えるまで 5分28秒(328秒)=約789MB/s。索引完了後の全文検索「New York」が 34.8秒 / 100,492件ヒットでした。
汎用ツールでの対処と限界
生のまま覗くなら、ストリームで流すのが基本です。
# 先頭だけ見て構造を確かめる
head -c 200000 us-260726.osm | xmlstarlet fo 2>/dev/null | head -60
# 特定のタグだけ数える(全走査1回)
grep -c '<way ' us-260726.osm
# 変換せずに目的地の見当をつける
grep -n -m 5 '"New York"' us-260726.osm
判断はできます。
限界は3つ。
ひとつめ、確認1回ごとに全走査が要ること。「行数を数える」だけで数分、質問が変わればまた数分です。
ふたつめ、jq や osmium に渡す前の目視が抜けること。スキーマの推測を間違えたまま処理を走らせると、数十分後に気づきます。
みっつめ、PBFに戻れないこと。元の11GBは圧縮バイナリなので、テキストとして読むには展開が要り、展開すると258GBになります。「小さいまま読む」という選択肢が、この経路にはありません(第8回)。
4つに共通していたもの
| 検証 | 出た数字 | 数字が言っていること | 向きが変わる条件 |
|---|---|---|---|
| 48GBを開く | 全域移動まで4分06秒/索引246秒 | 「対応容量」は作業開始時間を保証しない | ファイルサイズ(小さければ差は消える) |
| 51GBを開く | 52.55秒=930MB/s(素読み約950MB/s) | 待ちの大半は物理。速度では縮まない | 設計(待たせるか、裏で作るか) |
| 探して読むまで | 108.14秒(開く+検索の2回読み) | 秒数より読む回数が効く | 質問の回数(1問なら差は小さい) |
| 258.68GBの索引 | 328秒=約789MB/s/45億行 | 確認1回ごとに全走査が要る構造 | 2回目があるか(索引が残るか) |
4つとも、下限を決めているのは同じ式です。
1回の全走査にかかる時間 = ファイルサイズ ÷ ディスクの読み出し速度。
50GB・950MB/s なら約54秒。この54秒は、どんなツールでも消えません。だから比較で意味を持つのは、次の3つを添えた数字だけです。
- サイズ — 3GBの結果は50GBでは逆転します。メモリに収まるかどうかで別の競技になります
- 回数 — 1問だけなら、索引を作る側が損をします。同じファイルに2回以上聞くときだけ得をします
- ディスク — 内蔵SSDと外付けUSB SSDとネットワーク共有では、律速している場所そのものが違います(第17回)
裏を返せば、勝てる余地は2か所しかありません。待たせないこと(走査の完了を待たずに全域を見せる)と、2回目を無料にすること(索引を残す)です。
冒頭の「上限は950MB/s」に戻ります。あれは負けの報告ではなく、この上限を前提にして何を設計するかという話でした。連載25回ぶん、扱ってきたのは全部その1点です。
使っている道具
私が開発している UwView(無料)は、巨大なテキストを開いた瞬間から表示・スクロール・検索できるビューアです。ファイル全体をメモリへ読み込まないので、RAM より大きいファイルでも開けます。索引はバックグラウンドで作られ、完成すると行番号が付きます。
- 索引の完了を待たずに全域が見えます: 1章・2章に直接効きます。開いた直後に末尾へ移動でき、50%付近を確認でき、検索も始められます。258.68GB・45億行のXMLでも、索引作成が10%の時点で中身を読めています(258GBの実測記事)
- 同じ48GBでの比較: 索引作成74秒(同環境のEmEditor Professional 26.2.5 は246秒)、「東京」の全文検索12.5秒(同160秒)。Windows 11・Core i7-1165G7・RAM 16GB・内蔵SSD・x64版どうしでの測定例です。EmEditor 側は Large File option 未使用——有効にしたときの挙動は測っていません(48GB比較の実測記事)
- 色分けと検索結果の保存: 3章の5xx調査はここに乗ります。ステータスコードのプリセットで塊を目で追い、検索結果を原本の行番号付きで別ファイルへ出せます(5xx調査の記事)
- 処理はすべて手元のマシンで完結します。調査対象のファイルを外部のサービスへ送りません
ここから先が UwView Pro の領分です。
- 索引と圧縮を
.uwvzとして保存します: 4章の「確認1回ごとに全走査」が消えます。一度開いたファイルは2回目以降行番号付きのまま瞬時に開き直せます(47.73GBのテキストで実測0.02〜0.07秒。特定環境での測定例です) - 保管サイズは約1/9になります: 258.68GB のファイルに対して
.uwvzサイドカーは28.61GB でした。圧縮したまま検索できるので、展開して読む必要がありません(第8回) - 検索は2回目以降、最大約9倍(圧縮キャッシュ経由・実測条件つき)。3章の「2問目・3問目のたびに全走査」が効かなくなるのはここです
- 多段階検索で、絞り込んだ先も原本の行番号が残ります(多段階検索の記事)
正直に書いておきます。開くだけの速度では負けています。
- 51.25GBを「ただ開く」だけは、v1.6.5 では klogg のほうが速いでした(52.55秒 対 100.6秒)。v1.6.6 で逆転しています——50.44秒(3GB 2.99秒・10GB 10.13秒も klogg より速い)。読み出しは 967/966/969 MB/s で、媒体の速度そのものです。通しも索引の完成を待たずに検索を始められるようになって 53.7秒——klogg の 108.14秒に対して約2倍、コマンドの
uvf … -open(v1.6.6 で 50.76秒)とほぼ同じところまで来ました(差は約3秒)(v1.6.6 の実測) - 初回の完全な読み込み・完全索引には物理時間がかかります。 258.68GBで328秒というのは、速いのではなく「走査しながら読める」だけです
- 初回の検索は、生ファイルを1回走査します。 ただし v1.6.6 からは開くのと同時に走るので、開き終わってから改めて走査を待つわけではありません——50GB で通し 53.7秒です。瞬時に返るようになるのは2回目以降(圧縮キャッシュ経由)という点は変わりません
- 構造の解析はしません。 XMLの整形やクエリ、JSONの抽出は
xmlstarletやjqの仕事で、置き換えるものではありません - 扱うのはテキストです。 PBFのような圧縮バイナリは対象外なので、展開が前提になります
- 記事中の数字はすべて特定環境での測定例です。 同じ結果を保証するものではありません
コマンドラインから同じことをする
v1.6.0 で uvp コマンドが付きました(無料版には uvf)。GUI と同じ .uwvz を使うので、CLI で作った索引はそのまま GUI でも効きます。この記事の4章に対応させると、こう書きます。
# 1章: 開いて待つ前に、目的の語があるかだけ確かめる
uvp osm-japan.osm '東京'
# 2章: 末尾側の異常を、行番号付きで文脈ごと見る
uvp huge.log 'FATAL' -C 5
# 3章: 5xx の分布を1回読みで出す(2問目から索引が効く)
uvp access.log -uniq ' (5[0-9]{2}) ' -head 20
# 4章: 258GB級から該当箇所だけ書き出す
uvp us-260726.osm '"New York"' -C 2 -out survey/ny.txt.gz
# 行番号ジャンプ・色分け・文字コード切り替えは GUI 側の機能。続きはここで渡す
uvp access.log ' 503 ' -open
終了コードは grep と同じ 0=あり・1=なしに、2=上限に当たって打ち切った(既定は無制限。-limit N で上限を決めたときだけ)が加わります。if uvp access.log ' 503 '; then がそのまま書けます。
正直に書くと、1問目は uvp が ripgrep より少し遅くなります——.uwvz(圧縮+索引)を先に作るぶんで、50GB なら 59.0秒 対 54.9〜55.8秒=6〜7%。v1.6.6.1 で「作ってから探し直す」のをやめ、作りながら探すようにしたぶん 6.7秒 縮みました。効いてくるのは2問目からで、同じ 50GB の検索が 6.6秒、ripgrep の 55〜57秒に対して 8.4倍です。3GB のような小さいファイルでは同等——索引を引く意味が薄くなります。無料の uvf は、どのサイズでも ripgrep と同等です(実測記事。Mac M4・外付けUSB SSD・OpenStreetMap XML での測定例で、環境により異なります)。
この連載は今回で25回目、最後の回です。読んでいただきありがとうございました。次に巨大ファイルの比較記事を見かけたら、サイズ・回数・ディスクの3つが書いてあるかだけ確かめてみてください。それだけで、その数字が自分の現場に当てはまるかどうかが分かります。
そして、ストレージを専有している巨大ログを圧縮して保管し、さらに高速に検索したいなら UwView Pro をどうぞ。永続索引・圧縮キャッシュ検索・約1/9保管で、開き直しも検索も一段速くなります(全OS対応・買い切り/月額プランあり)。
リンク
- 第1回: 巨大ファイルに沈む4つの定番ツールと、その先: https://uvp.y42u.net/blog/uwview-ps01-huge-file-tool-limits/
- 第7回: タイムスタンプを武器にする4つの読み方: https://uvp.y42u.net/blog/uwview-ps07-timestamp-driven-triage/
- 第8回: 圧縮保管と検索の両立: https://uvp.y42u.net/blog/uwview-ps08-compressed-archive-search/
- 第9回: 構造化データを生のまま読む4場面: https://uvp.y42u.net/blog/uwview-ps09-read-raw-structured-data/
- 第15回: コマンドライン職人芸の限界線4本: https://uvp.y42u.net/blog/uwview-ps15-cli-craft-limits/
- 第17回: 開発環境とログの4つの摩擦: https://uvp.y42u.net/blog/uwview-ps17-dev-env-log-friction/
- 第22回: 引き継げるチームの4つの工夫: https://uvp.y42u.net/blog/uwview-ps22-shareable-log-investigation/
- 第24回: 原本に書き込まない4つの作法: https://uvp.y42u.net/blog/uwview-ps24-never-modify-the-original/
- 48GB・8.92億行での比較(EmEditor との実測): https://uvp.y42u.net/blog/uwview-emeditor-48gb-comparison/
- 258.68GB・45億行を開く(実測): https://uvp.y42u.net/blog/uwview-osm-usa-258gb/
- アクセスログの5xxを1本の線でつなぐ: https://uvp.y42u.net/blog/uwview-access-log-5xx-workflow/
- 3サイズでのベンチマーク: https://uvp.y42u.net/blog/uwview-pro-benchmark-3sizes/
- 絞り込んだ先からさらに絞り込む(多段階検索): https://uvp.y42u.net/blog/uvp-drilldown-search/
- uvp コマンドを付けました(ripgrep との実測比較): https://uvp.y42u.net/blog/uvp-cli-release-vs-ripgrep/
- ソースコード(GitHub): https://github.com/amru195704/UwView
開発者より: アプリ・Kindle本・公開プロジェクトの一覧は GitHub: amru195704 にまとめています。
お願い
本記事の情報は参考目的で掲載しており、正確性・完全性を保証するものではありません。記載した実測値はすべて特定の1環境・1本のファイルでの測定例であり、同じ結果を保証するものではありません。ディスクの種類・接続方式・ファイルシステム・ページキャッシュの状態・同時に動いている他のプロセス・各製品のバージョンと設定により、結果は大きく変わります。他製品の数値は当方の環境で測定したものであり、それぞれの製品の性能を一般的に代表するものではありません。各製品には本記事で扱っていない機能・長所が多数あります。コマンド例は環境(GNU/BSD、awk・grep・split・xmlstarlet・osmiumの実装差、シェルの種類)により調整が必要です。オプション名や既定値は必ず手元のmanで確認してください。OpenStreetMap のデータは ODbL のもとで提供されており、利用の際はライセンス条件に従ってください。ログの取り扱い・持ち出しの可否は、所属組織および委託元の規程、ならびに適用される法令に従ってください。誤記・不正確な情報がございましたら、コメント欄よりご指摘いただければ、確認のうえ修正いたします。

