ページの作成
親となるページを選択してください。
親ページに紐づくページを子ページといいます。
例: 親=スポーツ, 子1=サッカー, 子2=野球
子ページを親ページとして更に子ページを作成することも可能です。
例: 親=サッカー, 子=サッカーのルール
親ページはいつでも変更することが可能なのでとりあえず作ってみましょう!
| この記事の要点 |
|
原則: まず計測する
「重い」と言われたら勘で改善しないこと。プロファイラ・APM・ブラウザ DevTools でどこに時間がかかっているかを特定してから打ち手を選びます。
| 区間 | 計測方法 | 典型的な原因 |
|---|---|---|
| TTFB(サーバー初動) | DevTools Network、curl -w | DB / 外部 API / レンダリング |
| サーバー処理時間 | APM (New Relic / Datadog) / xhprof / Laravel Telescope | DB クエリ / N+1 / 外部 API |
| ダウンロード時間 | DevTools Network Waterfall | ファイルサイズ / 帯域 / 距離 |
| レンダリング | DevTools Performance / Lighthouse | JS 重い / Render-Blocking CSS |
DB が原因(最多パターン)
Web アプリの遅さの 7 割は DB に起因します。優先順位はこの順:
1. インデックスがあるか EXPLAIN で確認
-- MySQL / PostgreSQL
EXPLAIN SELECT * FROM orders WHERE user_id = 42 AND status = 'paid';
-- type=ALL や Seq Scan が出たらインデックス不足
-- type=ref / Index Scan を目指す
-- 複合インデックス作成
CREATE INDEX idx_orders_user_status ON orders (user_id, status);
-- 実際に使われたか
EXPLAIN ANALYZE SELECT ...; -- PostgreSQL
EXPLAIN FORMAT=JSON SELECT ...; -- MySQL
2. N+1 クエリの解消
// ❌ N+1 (100 ユーザーなら 1 + 100 = 101 クエリ)
$users = User::all();
foreach ($users as $u) {
echo $u->posts->count(); // SELECT * FROM posts WHERE user_id = ?
}
// ✅ Eager Loading (2 クエリ)
$users = User::with('posts')->get();
foreach ($users as $u) {
echo $u->posts->count();
}
// ✅ さらに最適化(集計だけなら withCount)
$users = User::withCount('posts')->get();
foreach ($users as $u) {
echo $u->posts_count;
}
3. スロークエリログ
# MySQL: 1 秒以上のクエリをログに
# my.cnf
[mysqld]
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 1
log_queries_not_using_indexes = 1
# PostgreSQL: log_min_duration_statement = 1000 (1 秒)
# 解析
mysqldumpslow -s t /var/log/mysql/slow.log | head -20
pt-query-digest /var/log/mysql/slow.log # Percona Toolkit
キャッシュ層導入
| レベル | 用途 | 選択肢 |
|---|---|---|
| クエリ結果 | 重い集計・人気記事一覧 | Redis / Memcached |
| セッション | ユーザー認証情報 | Redis |
| レンダー結果 | HTML フラグメント全体 | Redis / Varnish |
| HTTP キャッシュ | API レスポンス | CDN / Cache-Control |
| アプリ内 | 同一リクエスト内 | memoize / static 変数 |
// Laravel: Cache::remember で 5 分キャッシュ
$articles = Cache::remember('articles.popular', 300, function () {
return Article::orderBy('views', 'desc')->take(10)->get();
});
// 更新時にキャッシュ無効化
Cache::forget('articles.popular');
// タグ付け(Redis のみ)
Cache::tags(['articles'])->remember('popular', 300, fn() => ...);
Cache::tags(['articles'])->flush();
CDN と静的ファイル配信
- CloudFront / Cloudflare / Fastly: 画像・CSS・JS をエッジから配信、TTFB を 100ms 以下に
- Cache-Control: public, max-age=31536000, immutable: 1 年キャッシュ(ファイル名にハッシュを入れる)
- Stale-While-Revalidate: 期限切れでも一旦古いものを返しつつバックグラウンド更新
- S3 + CloudFront で安価な無限スケール配信
画像と転送量最適化

サーバー圧縮 / HTTP/2 / HTTP/3
# nginx.conf
http {
# Gzip
gzip on;
gzip_comp_level 6;
gzip_types text/css application/javascript application/json text/html;
# Brotli (要 ngx_brotli モジュール)
brotli on;
brotli_comp_level 6;
brotli_types text/css application/javascript application/json text/html;
server {
listen 443 ssl http2;
# listen 443 quic reuseport; # HTTP/3
# add_header Alt-Svc 'h3=":443"; ma=86400';
}
}
コードレベルのプロファイリング
// PHP: xhprof / xdebug profiler / Tideways
// Laravel Telescope
composer require laravel/telescope --dev
php artisan telescope:install
// Laravel Debugbar (開発用)
composer require barryvdh/laravel-debugbar --dev
// → ブラウザ下部にバーが出て SQL / リクエスト時間 / メモリ全部見える
// 手動計測
$start = microtime(true);
$result = doHeavyTask();
$elapsed = microtime(true) - $start;
Log::info("doHeavyTask: {$elapsed}s");
APM (本番監視)
| 製品 | 得意分野 |
|---|---|
| New Relic | PHP / Java / Ruby / Node の APM 老舗 |
| Datadog | APM + Infra + Log 統合 |
| Sentry | エラートラッキング + Performance |
| Tideways | PHP 特化(プロダクションプロファイラ) |
| AWS X-Ray | AWS ネイティブ・分散トレース |
フロントエンド最適化
- Lighthouse で Core Web Vitals (LCP / INP / CLS) を計測
- JS バンドル分割 (Code Splitting)、Tree Shaking、minify
- Critical CSS インライン化、残りは defer
- サードパーティスクリプト遅延読み込み (analytics.js, ads)
- preconnect / preload / dns-prefetch を要所に
インフラスケール
- DB のリードレプリカで読み取り分散
- アプリサーバーの水平スケール (ALB + Auto Scaling)
- 非同期処理 (キュー: SQS / Redis / RabbitMQ) で重い処理をバックグラウンドへ
- セッションを Redis に外出しすることでアプリサーバーをステートレス化
FAQ
Q: 何から手をつければ良いか
A: APM か Telescope で「最も時間かかっている処理」を特定。8 割は DB クエリ起因なので、EXPLAIN とインデックスから着手すれば大体直ります。
Q: キャッシュ vs インデックス、どちらが先か
A: インデックスが先。基本クエリが速くなれば、無理にキャッシュを増やさなくても十分なケースが多いです。キャッシュは複雑化と一貫性問題を伴うので最後の手段。
Q: フロントが遅いのかバックが遅いのか分からない
A: ブラウザ DevTools の Network タブで、TTFB(リクエスト送信からレスポンスの最初の 1 バイトまで)を見てください。TTFB が大きければバック、ダウンロードや描画が大きければフロント・配信側の問題です。
ページの作成
親となるページを選択してください。
親ページに紐づくページを子ページといいます。
例: 親=スポーツ, 子1=サッカー, 子2=野球
子ページを親ページとして更に子ページを作成することも可能です。
例: 親=サッカー, 子=サッカーのルール
親ページはいつでも変更することが可能なのでとりあえず作ってみましょう!
子ページ
子ページはありません
同階層のページ
- ブラウザゲームの公開
- 重い場合の対処法
人気ページ
- 1 Eclipseで「サーバーに追加または除去できるリソースがありません。」の原因と対処法
- 2 tomcat の起動 / 停止ログと catalina.log・catalina.out の違い
- 3 JavaScript base URL 取得方法|window.location.origin と SSR/Node.js 対応
- 4 YouTube Data API v3 エラー一覧|403/400/404 の主要原因と切り分け
- 5 Spring Frameworkのアノテーション一覧
- 6 Laravel エラー一覧|500/Blade/DB 接続/ルーティングの代表エラー
- 7 3Dグラフィックスとは|モデリング/レンダリング/主要ソフトウェア (Blender / Maya)
- 8 【Spring】@Valueアノテーションとは
- 9 CATALINA_HOME の確認方法 (Linux / Mac)
- 10 【Spring】@Autowiredアノテーションとは
最近更新/作成されたページ
- Laravel キャッシュクリア完全ガイド(cache:clear / config:clear / 2026-05-18 07:42:07
- プロジェクトの作成と削除 2026-05-18 07:42:07
- インストール直後にNetbeansが反応しない 2026-05-18 07:42:07
- 動画やチャンネルの検索 2026-05-18 07:42:07
- APIキー取得方法 2026-05-18 07:42:07
- チャンネル情報の取得 2026-05-18 07:42:07
- API 入門 — Web API(REST / GraphQL / gRPC / 2026-05-18 07:42:07
- インストール(eclipseプラグイン) 2026-05-18 07:42:07
- Laravel「Dotenv values containing spaces must be surrounded 2026-05-18 07:42:07
- エラー一覧 2026-05-18 07:42:07
- curl: (51) SSL: certificate subject name '~' does not match 2026-05-18 07:42:07
- インストール方法(Windows版) 2026-05-18 07:42:07
- JSONから配列に変換 2026-05-18 07:42:07
- 処理を一定時間待つ 2026-05-18 07:42:07
- A non well formed numeric value encountered 2026-05-18 07:42:07
コメントを削除してもよろしいでしょうか?