AI支援によるパフォーマンス最適化
AIを使用してコードのパフォーマンスボトルネックを特定して修正します。より高速で効率的なアプリケーションのための実践的なテクニックを学びます。
AI支援によるパフォーマンス最適化
パフォーマンスの問題は、診断に時間がかかり、見つけにくいことがあります。AIアシスタントは、コードパターンの分析、ボトルネックの特定、最適化の提案に優れています。このガイドでは、パフォーマンス作業にAIを活用する方法を示します。
AI支援パフォーマンス分析
パフォーマンスレビューのリクエスト
あなた:この関数のパフォーマンス問題を分析してください:
function processOrders(orders) {
const results = [];
for (const order of orders) {
const user = users.find(u => u.id === order.userId);
const products = order.items.map(item =>
products.find(p => p.id === item.productId)
);
results.push({ order, user, products });
}
return results;
}
Claude:いくつかのパフォーマンス問題を特定しました:
1. **O(n²)の計算量** - ループ内の`users.find()`
2. **O(n³)の計算量** - map内のネストされた`products.find()`
3. **早期終了なし** - 制限が必要でもすべての注文を処理
O(n)の計算量を持つ最適化されたバージョンは以下です...
/perf スキルの使用
hljs bash# ファイルを分析
/perf src/services/orderService.js
# 特定のフォーカスで分析
/perf --focus memory src/utils/dataProcessor.js
# パフォーマンスレポートを生成
/perf --report src/
一般的なパフォーマンスパターン
パターン1:ループの最適化
最適化前(O(n²)):
hljs javascriptfunction findMatches(items, targets) {
return items.filter(item =>
targets.includes(item.id) // 各アイテムに対してO(n)
);
}
最適化後(O(n)):
hljs javascriptfunction findMatches(items, targets) {
const targetSet = new Set(targets); // 一度だけO(n)
return items.filter(item =>
targetSet.has(item.id) // 各アイテムに対してO(1)
);
}
パターン2:メモ化
最適化前:
hljs javascriptfunction fibonacci(n) {
if (n <= 1) return n;
return fibonacci(n - 1) + fibonacci(n - 2);
}
// fibonacci(40)は約1秒かかる
最適化後:
hljs javascriptfunction fibonacci(n, memo = {}) {
if (n in memo) return memo[n];
if (n <= 1) return n;
memo[n] = fibonacci(n - 1, memo) + fibonacci(n - 2, memo);
return memo[n];
}
// fibonacci(40)は約0.001msかかる
パターン3:遅延読み込み
最適化前:
hljs javascript// すべてを事前に読み込む
import { Chart, Table, Form, Modal, DatePicker } from 'heavy-ui-lib';
最適化後:
hljs javascript// 必要なときだけ読み込む
const Chart = lazy(() => import('heavy-ui-lib/Chart'));
const Table = lazy(() => import('heavy-ui-lib/Table'));
パターン4:データベースクエリの最適化
最適化前(N+1問題):
hljs javascriptconst orders = await Order.findAll();
for (const order of orders) {
order.user = await User.findById(order.userId); // Nクエリ
}
最適化後(Eager Loading):
hljs javascriptconst orders = await Order.findAll({
include: [{ model: User, as: 'user' }] // JOINを使用した1クエリ
});
Reactパフォーマンス最適化
再レンダリング問題の特定
Claudeにコンポーネントのレンダリングを分析してもらう:
あなた:このコンポーネントが過度に再レンダリングされる理由は?
function ProductList({ products, onSelect }) {
return (
<ul>
{products.map(product => (
<li key={product.id} onClick={() => onSelect(product)}>
{product.name}
</li>
))}
</ul>
);
}
Claude:再レンダリングの問題を特定しました:
1. **インラインアロー関数**:各レンダリングで新しい関数を作成
2. **メモ化なし**:productsが変更されていなくても再レンダリング
最適化されたバージョン:
hljs typescriptimport { memo, useCallback } from 'react';
const ProductList = memo(({ products, onSelect }) => {
return (
<ul>
{products.map(product => (
<ProductItem
key={product.id}
product={product}
onSelect={onSelect}
/>
))}
</ul>
);
});
const ProductItem = memo(({ product, onSelect }) => {
const handleClick = useCallback(() => {
onSelect(product);
}, [product, onSelect]);
return (
<li onClick={handleClick}>
{product.name}
</li>
);
});
useMemoとuseCallbackの使用
hljs typescript// ❌ 悪い例:毎回再計算
function ExpensiveComponent({ items }) {
const total = items.reduce((sum, item) => sum + item.price, 0);
const average = total / items.length;
return <div>平均: {average}</div>;
}
// ✅ 良い例:メモ化された計算
function ExpensiveComponent({ items }) {
const total = useMemo(
() => items.reduce((sum, item) => sum + item.price, 0),
[items]
);
const average = useMemo(
() => total / items.length,
[total, items.length]
);
return <div>平均: {average}</div>;
}
仮想化の実装
hljs typescriptimport { FixedSizeList } from 'react-window';
// ❌ 悪い例:10,000アイテムをすべてレンダリング
function LargeList({ items }) {
return (
<div>
{items.map(item => (
<div key={item.id}>{item.name}</div>
))}
</div>
);
}
// ✅ 良い例:表示されているアイテムのみレンダリング
function LargeList({ items }) {
return (
<FixedSizeList
height={600}
itemCount={items.length}
itemSize={50}
width="100%"
>
{({ index, style }) => (
<div style={style}>{items[index].name}</div>
)}
</FixedSizeList>
);
}
バックエンドパフォーマンス最適化
データベースインデックス
hljs sql-- ❌ 悪い例:インデックスなし
SELECT * FROM users WHERE email = 'user@example.com';
-- 実行時間:500ms(100万行)
-- ✅ 良い例:インデックス付き
CREATE INDEX idx_users_email ON users(email);
SELECT * FROM users WHERE email = 'user@example.com';
-- 実行時間:5ms
クエリの最適化
hljs javascript// ❌ 悪い例:すべてのフィールドを選択
const users = await db.query('SELECT * FROM users');
// ✅ 良い例:必要なフィールドのみ選択
const users = await db.query('SELECT id, name, email FROM users');
// ❌ 悪い例:ループ内でクエリ
for (const userId of userIds) {
const user = await User.findById(userId);
users.push(user);
}
// ✅ 良い例:単一クエリ
const users = await User.findAll({
where: { id: { [Op.in]: userIds } }
});
キャッシング戦略
hljs typescriptimport Redis from 'ioredis';
const redis = new Redis();
// シンプルなキャッシング
async function getUser(id: string) {
// キャッシュを確認
const cached = await redis.get(`user:${id}`);
if (cached) return JSON.parse(cached);
// データベースから取得
const user = await User.findById(id);
// キャッシュに保存(1時間)
await redis.setex(`user:${id}`, 3600, JSON.stringify(user));
return user;
}
// キャッシュ無効化
async function updateUser(id: string, data: any) {
const user = await User.update(id, data);
// キャッシュを無効化
await redis.del(`user:${id}`);
return user;
}
接続プーリング
hljs typescript// ❌ 悪い例:各リクエストで新しい接続
async function query(sql: string) {
const connection = await mysql.createConnection(config);
const result = await connection.query(sql);
await connection.end();
return result;
}
// ✅ 良い例:接続プール
const pool = mysql.createPool({
host: 'localhost',
user: 'root',
database: 'mydb',
connectionLimit: 10,
queueLimit: 0
});
async function query(sql: string) {
const connection = await pool.getConnection();
try {
const result = await connection.query(sql);
return result;
} finally {
connection.release();
}
}
フロントエンドパフォーマンス最適化
バンドルサイズの削減
hljs bash# バンドルサイズを分析
npm run build -- --analyze
# 未使用のコードを削除
npm install -g depcheck
depcheck
# Tree shakingを有効化
# webpack.config.js
module.exports = {
mode: 'production',
optimization: {
usedExports: true,
sideEffects: false
}
};
コード分割
hljs typescript// ❌ 悪い例:すべてを1つのバンドルに
import Dashboard from './Dashboard';
import Analytics from './Analytics';
import Settings from './Settings';
// ✅ 良い例:ルートベースのコード分割
const Dashboard = lazy(() => import('./Dashboard'));
const Analytics = lazy(() => import('./Analytics'));
const Settings = lazy(() => import('./Settings'));
function App() {
return (
<Suspense fallback={<Loading />}>
<Routes>
<Route path="/dashboard" element={<Dashboard />} />
<Route path="/analytics" element={<Analytics />} />
<Route path="/settings" element={<Settings />} />
</Routes>
</Suspense>
);
}
画像の最適化
hljs typescript// ❌ 悪い例:最適化されていない画像
<img src="/images/hero.jpg" alt="Hero" />
// ✅ 良い例:最適化された画像
import Image from 'next/image';
<Image
src="/images/hero.jpg"
alt="Hero"
width={1200}
height={600}
loading="lazy"
placeholder="blur"
/>
リソースのプリロード
hljs html<!-- 重要なリソースをプリロード -->
<link rel="preload" href="/fonts/main.woff2" as="font" type="font/woff2" crossorigin>
<link rel="preload" href="/critical.css" as="style">
<!-- DNSプリフェッチ -->
<link rel="dns-prefetch" href="https://api.example.com">
<!-- プリコネクト -->
<link rel="preconnect" href="https://cdn.example.com">
パフォーマンス測定
Web Vitalsの監視
hljs typescriptimport { getCLS, getFID, getFCP, getLCP, getTTFB } from 'web-vitals';
function sendToAnalytics(metric: any) {
// 分析サービスに送信
console.log(metric);
}
getCLS(sendToAnalytics); // Cumulative Layout Shift
getFID(sendToAnalytics); // First Input Delay
getFCP(sendToAnalytics); // First Contentful Paint
getLCP(sendToAnalytics); // Largest Contentful Paint
getTTFB(sendToAnalytics); // Time to First Byte
カスタムパフォーマンス測定
hljs typescript// パフォーマンスマーカー
performance.mark('data-fetch-start');
await fetchData();
performance.mark('data-fetch-end');
performance.measure('data-fetch', 'data-fetch-start', 'data-fetch-end');
const measure = performance.getEntriesByName('data-fetch')[0];
console.log(`データ取得時間: ${measure.duration}ms`);
// パフォーマンスオブザーバー
const observer = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
console.log(`${entry.name}: ${entry.duration}ms`);
}
});
observer.observe({ entryTypes: ['measure', 'navigation'] });
プロファイリング
hljs typescript// React Profilerを使用
import { Profiler } from 'react';
function onRenderCallback(
id: string,
phase: 'mount' | 'update',
actualDuration: number,
baseDuration: number,
startTime: number,
commitTime: number
) {
console.log(`${id} (${phase}): ${actualDuration}ms`);
}
function App() {
return (
<Profiler id="App" onRender={onRenderCallback}>
<Dashboard />
</Profiler>
);
}
AIを使用したパフォーマンス最適化
パフォーマンスレビューのリクエスト
あなた:このコンポーネントのパフォーマンスを最適化してください:
[コードを貼り付け]
以下に焦点を当ててください:
1. 不要な再レンダリング
2. メモリリーク
3. 計算量
4. バンドルサイズへの影響
Claude:分析と最適化を提供します...
ボトルネックの特定
あなた:このアプリケーションが遅い理由を特定してください。
プロファイリングデータ:
[パフォーマンスデータを貼り付け]
Claude:ボトルネックを分析します...
最適化の提案
あなた:このデータ処理パイプラインを最適化する方法を提案してください:
[コードを貼り付け]
制約:
- メモリ使用量を最小限に
- リアルタイム処理が必要
- 既存のAPIを維持
Claude:最適化戦略を提供します...
パフォーマンスベストプラクティス
1. 早期最適化を避ける
まず動作させ、次に測定し、その後最適化します。
2. 測定してから最適化
推測ではなく、データに基づいて最適化します。
3. 低い果実から始める
最大の影響を与える最適化に焦点を当てます。
4. ユーザー体験を優先
技術的なメトリクスよりもユーザーが感じるパフォーマンスを重視します。
5. 継続的に監視
パフォーマンスは一度限りのタスクではなく、継続的なプロセスです。
パフォーマンスチェックリスト
フロントエンド
- バンドルサイズを最小化
- コード分割を実装
- 画像を最適化
- 遅延読み込みを使用
- 不要な再レンダリングを削減
- Web Vitalsを監視
バックエンド
- データベースクエリを最適化
- インデックスを追加
- キャッシングを実装
- 接続プーリングを使用
- N+1問題を解決
- APIレスポンスを圧縮
一般
- パフォーマンステストを実行
- プロファイリングを実施
- ボトルネックを特定
- 最適化を測定
- 継続的に監視
- ドキュメント化
まとめ
パフォーマンス最適化は、測定、分析、改善の継続的なサイクルです。AIアシスタントは、ボトルネックの特定、最適化の提案、ベストプラクティスの適用に役立ちます。
効果的なパフォーマンス最適化のために:
- 測定してから最適化
- 最大の影響を与える問題に焦点を当てる
- AIを使用してパターンを特定
- 継続的に監視
- ユーザー体験を優先
次へ:チームコラボレーションでCCJKをチームで効果的に使用する方法を学びます。
よくある質問
パフォーマンス最適化はいつ行うべきですか?
パフォーマンス問題を測定して確認した後です。早期最適化は避けてください。
最も重要なパフォーマンスメトリクスは?
Web Vitals(LCP、FID、CLS)とユーザーが感じる応答時間です。
AIはパフォーマンス問題を自動的に修正できますか?
AIは問題を特定して提案できますが、最終的な決定と実装は開発者が行う必要があります。
パフォーマンステストはどのくらいの頻度で実行すべきですか?
CI/CDパイプラインの一部として、各デプロイ前に実行してください。
関連記事
AI支援開発のためのセキュリティベストプラクティス
AIコーディングアシスタントを安全に使用するための必須セキュリティガイドライン。コードベース、認証情報、機密データを保護します。