Cursor が巨大リポジトリで重い時の対処:インデックス最適化と部分学習のコツ

巨大なリポジトリで Cursor を使っていると、動作が重くて開発効率が下がってしまった経験はありませんか。特に数万ファイルを含むモノレポや、長年蓄積された大規模プロジェクトでは、Cursor のインデックス処理が追いつかずに、コード補完や解析機能が期待通りに動作しないことがあります。
しかし、適切な設定と最適化を行うことで、これらの問題は大幅に改善できます。本記事では、インデックス最適化と部分学習のテクニックを使って、巨大リポジトリでも Cursor を快適に使う方法をご紹介します。
巨大リポジトリでの Cursor 動作問題
巨大リポジトリで Cursor を使用する際、以下のような問題が発生することがあります。
Cursor は高度な AI 機能を提供するために、プロジェクト全体のコード構造を理解する必要があります。しかし、リポジトリサイズが一定を超えると、この処理がボトルネックとなり、ユーザー体験が著しく悪化します。
以下のような症状が現れた場合、最適化が必要です:
- Cursor の起動に数分かかる
- コード補完の反応が極端に遅い
- ファイル保存時にフリーズする
- メモリ使用量が異常に高い
- AI 機能が正常に動作しない
これらの問題を解決するには、Cursor がどのようにリポジトリを処理しているかを理解することが重要です。
mermaidflowchart TD
repo[巨大リポジトリ] -->|スキャン| cursor[Cursor]
cursor -->|インデックス作成| index[ファイルインデックス]
cursor -->|AI学習| ai[コンテキスト学習]
index -->|重い処理| slow[動作低下]
ai -->|メモリ消費| memory[メモリ不足]
slow --> problem[パフォーマンス問題]
memory --> problem
図解: Cursor が巨大リポジトリを処理する際の問題発生フロー
パフォーマンス低下の主な原因
インデックス処理の負荷
Cursor は効率的なコード解析のために、プロジェクト内のすべてのファイルをインデックス化します。このプロセスでは、以下の処理が実行されます。
javascript// Cursorが内部で行うインデックス処理の概念
const indexingProcess = {
fileScanning: 'プロジェクト内の全ファイルを走査',
syntaxAnalysis: '各ファイルの構文解析',
dependencyMapping: 'ファイル間の依存関係マッピング',
symbolExtraction: 'クラス、関数、変数の抽出',
};
巨大リポジトリでは、このインデックス処理が膨大な時間とリソースを消費します。特に以下のようなファイルが多数存在する場合、処理負荷は指数関数的に増加します:
ファイル種類 | 処理負荷 | 備考 |
---|---|---|
TypeScript/JavaScript | 高 | 複雑な構文解析が必要 |
node_modules | 極高 | 大量の依存関係ファイル |
ビルド成果物 | 中 | 不要だが処理される |
画像・動画 | 低 | バイナリファイルは軽微 |
ログファイル | 中 | サイズが大きい場合は負荷大 |
メモリ消費量の増大
Cursor は学習したコンテキスト情報をメモリ上に保持します。巨大リポジトリではこのメモリ使用量が急激に増加し、システム全体のパフォーマンスに影響を与えます。
typescript// メモリ使用量の概算
interface MemoryUsage {
indexData: number; // インデックスデータ: ~100MB-2GB
aiContext: number; // AI学習コンテキスト: ~500MB-5GB
fileCache: number; // ファイルキャッシュ: ~50MB-500MB
totalEstimate: number; // 合計推定値
}
const calculateMemoryUsage = (
fileCount: number
): MemoryUsage => {
return {
indexData: fileCount * 0.1, // ファイル数 × 100KB
aiContext: fileCount * 0.5, // ファイル数 × 500KB
fileCache: fileCount * 0.05, // ファイル数 × 50KB
totalEstimate: fileCount * 0.65, // 合計
};
};
メモリ不足により以下の問題が発生します:
- スワップファイルの使用によるディスク I/O 増加
- ガベージコレクションの頻発
- 他のアプリケーションの動作不良
- システム全体の応答性低下
ファイル数による制限
多くのファイルシステムや OS には、同時に開けるファイル数に制限があります。Cursor がこの制限に達すると、正常な動作ができなくなります。
bash# ファイル制限の確認方法(macOS/Linux)
ulimit -n # 現在の制限値を表示
# 通常は1024または8192
特に以下のような構成のプロジェクトでは制限に達しやすくなります:
- マイクロサービス構成のモノレポ
- 多言語対応プロジェクト
- 大量のテストファイルを含むプロジェクト
- 複数のフレームワークを併用するプロジェクト
mermaidgraph LR
files[ファイル数増加] --> limit[OS制限到達]
limit --> error[ファイルオープンエラー]
error --> failure[機能停止]
files --> memory[メモリ使用量増加]
memory --> swap[スワップ使用]
swap --> slow[動作低下]
図で理解できる要点:
- ファイル数増加が複数の制限を引き起こす
- OS 制限とメモリ制限は独立した問題
- 最終的にはパフォーマンス低下に収束する
インデックス最適化戦略
.cursorignore ファイルの効果的な設定
.cursorignore
ファイルは、Cursor のインデックス対象から特定のファイルやディレクトリを除外するための設定ファイルです。適切に設定することで、処理時間とメモリ使用量を大幅に削減できます。
プロジェクトルートに.cursorignore
ファイルを作成し、以下のような設定を行います:
text# Node.js プロジェクトの基本設定
node_modules/
dist/
build/
.next/
.nuxt/
# ログファイルとキャッシュ
*.log
logs/
.cache/
.tmp/
temp/
# ビルド成果物
*.min.js
*.min.css
*.bundle.js
coverage/
.nyc_output/
# IDEと開発ツール
.vscode/
.idea/
*.swp
*.swo
.DS_Store
# バージョン管理
.git/
.svn/
.hg/
# 環境固有ファイル
.env
.env.local
.env.production
# 大きなデータファイル
*.sql
*.dump
*.backup
data/
uploads/
効果的な除外パターンの選び方:
typescriptinterface IgnoreStrategy {
priority: 'high' | 'medium' | 'low';
pattern: string;
reason: string;
estimatedSavings: string;
}
const ignorePatterns: IgnoreStrategy[] = [
{
priority: 'high',
pattern: 'node_modules/',
reason: '大量の外部依存関係',
estimatedSavings: '80-90%のファイル数削減',
},
{
priority: 'high',
pattern: 'dist/',
reason: 'ビルド成果物(自動生成)',
estimatedSavings: '10-20%のファイル数削減',
},
{
priority: 'medium',
pattern: '*.log',
reason: 'ログファイル(大容量)',
estimatedSavings: 'メモリ使用量20-30%削減',
},
];
段階的インデックス構築
大きなプロジェクトでは、一度にすべてをインデックス化するのではなく、段階的にインデックスを構築することが効果的です。
Cursor の設定で段階的インデックスを有効にする方法:
json{
"cursor.indexing.mode": "incremental",
"cursor.indexing.batchSize": 100,
"cursor.indexing.delay": 50,
"cursor.indexing.priority": [
"src/",
"lib/",
"components/",
"utils/"
]
}
段階的インデックス構築の実装例:
javascript// インデックス優先度の設定
const indexingPriority = {
phase1: ['src/components/', 'src/utils/'], // 最優先
phase2: ['src/pages/', 'src/hooks/'], // 次優先
phase3: ['tests/', 'docs/'], // 最後
excluded: ['node_modules/', 'dist/', '.git/'], // 除外
};
// 段階的処理の実装
const processIndexingPhases = async () => {
for (const [phase, directories] of Object.entries(
indexingPriority
)) {
if (phase === 'excluded') continue;
console.log(`Starting ${phase}...`);
await indexDirectories(directories);
await new Promise((resolve) =>
setTimeout(resolve, 1000)
); // 1秒待機
}
};
この方法により、重要なファイルから優先的にインデックス化され、開発中に必要な機能をより早く利用できます。
キャッシュ最適化
Cursor は効率化のためにインデックス情報をキャッシュします。このキャッシュを適切に管理することで、起動時間とメモリ使用量を最適化できます。
キャッシュ設定の最適化:
json{
"cursor.cache.enabled": true,
"cursor.cache.maxSize": "2GB",
"cursor.cache.ttl": 3600,
"cursor.cache.compression": true,
"cursor.cache.strategy": "lru"
}
キャッシュ管理スクリプトの例:
bash#!/bin/bash
# キャッシュ最適化スクリプト
CACHE_DIR="$HOME/.cursor/cache"
MAX_CACHE_SIZE="2G"
# キャッシュサイズの確認
current_size=$(du -sh "$CACHE_DIR" | cut -f1)
echo "Current cache size: $current_size"
# 古いキャッシュファイルの削除(7日以上古い)
find "$CACHE_DIR" -type f -mtime +7 -delete
# キャッシュサイズが上限を超えている場合の処理
if [[ $(du -s "$CACHE_DIR" | cut -f1) -gt $(numfmt --from=iec "${MAX_CACHE_SIZE}") ]]; then
echo "Cache size exceeded limit. Cleaning up..."
# 最も古いファイルから削除
find "$CACHE_DIR" -type f -print0 | xargs -0 ls -lt | tail -n +100 | cut -d' ' -f9- | xargs rm -f
fi
定期的なキャッシュメンテナンス:
typescript// キャッシュメンテナンスの自動化
interface CacheMaintenanceConfig {
interval: number; // メンテナンス間隔(分)
maxAge: number; // 最大保持期間(時間)
maxSize: string; // 最大サイズ
compressionLevel: number; // 圧縮レベル(1-9)
}
const cacheConfig: CacheMaintenanceConfig = {
interval: 60, // 1時間ごと
maxAge: 24, // 24時間
maxSize: '2GB',
compressionLevel: 6,
};
const scheduleCacheMaintenance = (
config: CacheMaintenanceConfig
) => {
setInterval(async () => {
await cleanupOldCache(config.maxAge);
await compressCache(config.compressionLevel);
await enforceMaxSize(config.maxSize);
}, config.interval * 60 * 1000);
};
部分学習による効率化
ワークスペース分割のアプローチ
巨大リポジトリを機能別に分割し、必要な部分のみを Cursor に学習させることで、パフォーマンスを大幅に改善できます。
効果的なワークスペース分割の戦略:
typescript// ワークスペース分割の設定例
interface WorkspaceConfig {
name: string;
paths: string[];
dependencies: string[];
priority: number;
}
const workspaceConfigs: WorkspaceConfig[] = [
{
name: 'frontend',
paths: ['src/components/', 'src/pages/', 'src/hooks/'],
dependencies: ['shared/types/', 'shared/utils/'],
priority: 1,
},
{
name: 'backend',
paths: ['server/', 'api/', 'database/'],
dependencies: ['shared/types/', 'shared/constants/'],
priority: 2,
},
{
name: 'shared',
paths: ['shared/', 'types/', 'constants/'],
dependencies: [],
priority: 3,
},
];
VS Code のワークスペース設定(.vscode/workspace.code-workspace
):
json{
"folders": [
{
"name": "Frontend",
"path": "./src"
},
{
"name": "Backend",
"path": "./server"
},
{
"name": "Shared",
"path": "./shared"
}
],
"settings": {
"cursor.workspace.focus": "Frontend",
"cursor.learning.scope": ["Frontend", "Shared"],
"files.exclude": {
"**/node_modules": true,
"**/dist": true,
"server/**": true
}
}
}
動的ワークスペース切り替えスクリプト:
bash#!/bin/bash
# ワークスペース切り替えスクリプト
WORKSPACE_DIR=".vscode/workspaces"
CURRENT_WORKSPACE="$1"
if [ -z "$CURRENT_WORKSPACE" ]; then
echo "使用方法: switch-workspace.sh [frontend|backend|full]"
exit 1
fi
# ワークスペース設定の適用
case "$CURRENT_WORKSPACE" in
frontend)
cp "$WORKSPACE_DIR/frontend.code-workspace" ".vscode/workspace.code-workspace"
echo "フロントエンド開発環境に切り替えました"
;;
backend)
cp "$WORKSPACE_DIR/backend.code-workspace" ".vscode/workspace.code-workspace"
echo "バックエンド開発環境に切り替えました"
;;
full)
cp "$WORKSPACE_DIR/full.code-workspace" ".vscode/workspace.code-workspace"
echo "全体開発環境に切り替えました"
;;
*)
echo "不正なワークスペース名: $CURRENT_WORKSPACE"
exit 1
;;
esac
必要最小限のコンテキスト設定
Cursor の学習コンテキストを必要最小限に制限することで、メモリ使用量を削減し、応答速度を向上させます。
コンテキスト制御の設定:
json{
"cursor.context.maxFiles": 50,
"cursor.context.maxSize": "10MB",
"cursor.context.strategy": "relevant-only",
"cursor.context.excludePatterns": [
"**/*.min.js",
"**/*.bundle.js",
"**/dist/**",
"**/node_modules/**"
],
"cursor.context.includePatterns": [
"src/**/*.{ts,tsx,js,jsx}",
"types/**/*.ts",
"utils/**/*.ts"
]
}
動的コンテキスト調整の実装:
typescript// コンテキスト管理クラス
class ContextManager {
private maxContextSize: number;
private currentContext: Set<string>;
private relevanceScores: Map<string, number>;
constructor(maxSize: number = 50) {
this.maxContextSize = maxSize;
this.currentContext = new Set();
this.relevanceScores = new Map();
}
// 関連度に基づいてファイルを評価
calculateRelevance(
filePath: string,
currentFile: string
): number {
let score = 0;
// 同じディレクトリのファイル
if (
path.dirname(filePath) === path.dirname(currentFile)
) {
score += 10;
}
// インポート関係のあるファイル
if (this.hasImportRelation(filePath, currentFile)) {
score += 15;
}
// 最近編集されたファイル
const lastModified = fs.statSync(filePath).mtime;
const daysSinceModified =
(Date.now() - lastModified.getTime()) /
(1000 * 60 * 60 * 24);
score += Math.max(0, 5 - daysSinceModified);
return score;
}
// コンテキストの最適化
optimizeContext(currentFile: string): void {
const candidates = this.getAllCandidateFiles();
// 関連度の計算
candidates.forEach((file) => {
const relevance = this.calculateRelevance(
file,
currentFile
);
this.relevanceScores.set(file, relevance);
});
// 上位ファイルのみを選択
const sortedFiles = Array.from(
this.relevanceScores.entries()
)
.sort(([, a], [, b]) => b - a)
.slice(0, this.maxContextSize)
.map(([file]) => file);
this.currentContext = new Set(sortedFiles);
}
}
プロジェクト構造に応じた学習範囲調整
プロジェクトの構造を分析し、最適な学習範囲を自動で調整する機能を実装します。
プロジェクト構造分析:
typescript// プロジェクト構造の分析
interface ProjectStructure {
type: 'monorepo' | 'single-package' | 'micro-frontend';
packages: PackageInfo[];
dependencies: DependencyGraph;
hotspots: string[]; // よく変更されるファイル
}
interface PackageInfo {
name: string;
path: string;
size: number;
lastModified: Date;
importance: number;
}
class ProjectAnalyzer {
async analyzeStructure(
rootPath: string
): Promise<ProjectStructure> {
const packages = await this.discoverPackages(rootPath);
const dependencies = await this.buildDependencyGraph(
packages
);
const hotspots = await this.identifyHotspots(rootPath);
return {
type: this.inferProjectType(packages),
packages,
dependencies,
hotspots,
};
}
private async discoverPackages(
rootPath: string
): Promise<PackageInfo[]> {
const packages: PackageInfo[] = [];
const packageFiles = await glob('**/package.json', {
cwd: rootPath,
});
for (const packageFile of packageFiles) {
const packagePath = path.dirname(packageFile);
const stats = await fs.stat(
path.join(rootPath, packagePath)
);
const packageJson = JSON.parse(
await fs.readFile(
path.join(rootPath, packageFile),
'utf-8'
)
);
packages.push({
name:
packageJson.name || path.basename(packagePath),
path: packagePath,
size: await this.calculateDirectorySize(
path.join(rootPath, packagePath)
),
lastModified: stats.mtime,
importance: this.calculateImportance(
packageJson,
packages
),
});
}
return packages;
}
}
学習範囲の自動調整:
typescript// 学習範囲の最適化
class LearningOptimizer {
private projectStructure: ProjectStructure;
private memoryLimit: number;
constructor(
structure: ProjectStructure,
memoryLimitMB: number = 2048
) {
this.projectStructure = structure;
this.memoryLimit = memoryLimitMB * 1024 * 1024; // MBからバイトに変換
}
optimizeLearningScope(): string[] {
const packages = this.projectStructure.packages.sort(
(a, b) => b.importance - a.importance
);
const selectedPaths: string[] = [];
let currentMemoryUsage = 0;
for (const pkg of packages) {
const estimatedMemory = this.estimateMemoryUsage(pkg);
if (
currentMemoryUsage + estimatedMemory <=
this.memoryLimit
) {
selectedPaths.push(pkg.path);
currentMemoryUsage += estimatedMemory;
} else {
break;
}
}
// 必須パッケージの追加
this.addEssentialPaths(selectedPaths);
return selectedPaths;
}
private estimateMemoryUsage(pkg: PackageInfo): number {
// パッケージサイズベースのメモリ使用量推定
return pkg.size * 0.3; // 経験的な係数
}
private addEssentialPaths(paths: string[]): void {
const essentialPaths = [
'types/',
'shared/',
'utils/',
'constants/',
];
essentialPaths.forEach((path) => {
if (!paths.includes(path) && fs.existsSync(path)) {
paths.push(path);
}
});
}
}
mermaidgraph TD
project[プロジェクト分析] --> structure[構造把握]
structure --> packages[パッケージ発見]
structure --> deps[依存関係分析]
structure --> hotspots[ホットスポット特定]
packages --> importance[重要度計算]
deps --> importance
hotspots --> importance
importance --> selection[学習範囲選択]
selection --> memory[メモリ制限チェック]
memory --> optimize[最適化実行]
図で理解できる要点:
- プロジェクト分析から最適化まで段階的に処理
- 複数の指標を組み合わせて重要度を算出
- メモリ制限を考慮した現実的な選択
実践的な設定例とコード
設定ファイルの具体例
実際のプロジェクトで使用できる包括的な設定例をご紹介します。
Cursor 設定ファイル(.vscode/settings.json
):
json{
"cursor.general.enableLogging": true,
"cursor.performance.optimizeForLargeFiles": true,
"cursor.indexing.excludePatterns": [
"**/node_modules/**",
"**/dist/**",
"**/build/**",
"**/.git/**",
"**/*.log",
"**/coverage/**",
"**/.nyc_output/**"
],
"cursor.indexing.includePatterns": [
"src/**/*.{ts,tsx,js,jsx,vue}",
"lib/**/*.{ts,js}",
"types/**/*.ts",
"utils/**/*.{ts,js}",
"components/**/*.{ts,tsx,vue}",
"pages/**/*.{ts,tsx,js,jsx}",
"api/**/*.{ts,js}",
"server/**/*.{ts,js}",
"tests/**/*.{ts,js,spec.ts,test.ts}"
],
"cursor.context.maxTokens": 4000,
"cursor.context.maxFiles": 30,
"cursor.memory.maxUsageMB": 2048,
"cursor.cache.enabled": true,
"cursor.cache.maxSizeMB": 512,
"cursor.ai.model": "gpt-4",
"cursor.ai.temperature": 0.2,
"files.watcherExclude": {
"**/node_modules/**": true,
"**/dist/**": true,
"**/build/**": true,
"**/.git/**": true,
"**/logs/**": true,
"**/tmp/**": true,
"**/temp/**": true
},
"search.exclude": {
"**/node_modules": true,
"**/dist": true,
"**/build": true,
"**/.git": true,
"**/coverage": true,
"**/*.min.js": true,
"**/*.bundle.js": true
},
"files.exclude": {
"**/.git": true,
"**/.DS_Store": true,
"**/node_modules": true,
"**/dist": true,
"**/build": true,
"**/*.log": true
}
}
プロジェクト固有の設定(.cursorrc
):
yaml# Cursor設定ファイル
version: '1.0'
# インデックス設定
indexing:
mode: 'incremental'
batchSize: 50
delay: 100
priority:
- 'src/'
- 'lib/'
- 'types/'
- 'utils/'
exclude:
- 'node_modules/'
- 'dist/'
- 'build/'
- '.git/'
- '*.log'
- 'coverage/'
# メモリ管理
memory:
maxUsageMB: 2048
garbageCollection: 'aggressive'
cacheStrategy: 'lru'
# AI設定
ai:
model: 'gpt-4'
temperature: 0.2
maxTokens: 4000
contextStrategy: 'relevant-files'
# パフォーマンス設定
performance:
enableFileWatching: true
debounceMs: 300
maxConcurrentRequests: 3
timeoutMs: 30000
# プロジェクト構造
structure:
type: 'monorepo'
packages:
- name: 'frontend'
path: 'packages/frontend'
priority: 1
- name: 'backend'
path: 'packages/backend'
priority: 2
- name: 'shared'
path: 'packages/shared'
priority: 3
環境別設定の管理:
typescript// 環境別設定管理
interface EnvironmentConfig {
development: CursorConfig;
production: CursorConfig;
testing: CursorConfig;
}
interface CursorConfig {
memory: {
maxUsageMB: number;
cacheStrategy: string;
};
indexing: {
mode: string;
batchSize: number;
priority: string[];
};
ai: {
model: string;
temperature: number;
};
}
const environmentConfigs: EnvironmentConfig = {
development: {
memory: {
maxUsageMB: 4096, // 開発時は大きめ
cacheStrategy: 'aggressive',
},
indexing: {
mode: 'full',
batchSize: 100,
priority: ['src/', 'tests/', 'docs/'],
},
ai: {
model: 'gpt-4',
temperature: 0.3,
},
},
production: {
memory: {
maxUsageMB: 1024, // 本番は制限
cacheStrategy: 'conservative',
},
indexing: {
mode: 'incremental',
batchSize: 50,
priority: ['src/'],
},
ai: {
model: 'gpt-3.5-turbo',
temperature: 0.1,
},
},
testing: {
memory: {
maxUsageMB: 512, // テスト時は最小限
cacheStrategy: 'minimal',
},
indexing: {
mode: 'minimal',
batchSize: 25,
priority: ['tests/'],
},
ai: {
model: 'gpt-3.5-turbo',
temperature: 0.0,
},
},
};
パフォーマンス測定方法
Cursor のパフォーマンスを定量的に測定し、最適化の効果を確認する方法をご紹介します。
パフォーマンス測定スクリプト:
javascript// パフォーマンス測定ツール
class CursorPerformanceMonitor {
constructor() {
this.metrics = {
startupTime: 0,
indexingTime: 0,
memoryUsage: [],
responseTime: [],
errorCount: 0,
};
this.startTime = Date.now();
}
// 起動時間の測定
measureStartupTime() {
const startupTime = Date.now() - this.startTime;
this.metrics.startupTime = startupTime;
console.log(`Cursor起動時間: ${startupTime}ms`);
return startupTime;
}
// メモリ使用量の監視
monitorMemoryUsage() {
const measureMemory = () => {
if (process.memoryUsage) {
const usage = process.memoryUsage();
this.metrics.memoryUsage.push({
timestamp: Date.now(),
heapUsed: usage.heapUsed,
heapTotal: usage.heapTotal,
external: usage.external,
});
}
};
// 5秒ごとにメモリ使用量を記録
setInterval(measureMemory, 5000);
measureMemory(); // 初回実行
}
// レスポンス時間の測定
async measureResponseTime(operation, ...args) {
const startTime = performance.now();
try {
const result = await operation(...args);
const endTime = performance.now();
const responseTime = endTime - startTime;
this.metrics.responseTime.push({
operation: operation.name,
time: responseTime,
timestamp: Date.now(),
});
console.log(
`${operation.name}: ${responseTime.toFixed(2)}ms`
);
return result;
} catch (error) {
this.metrics.errorCount++;
console.error(`Error in ${operation.name}:`, error);
throw error;
}
}
// レポートの生成
generateReport() {
const avgResponseTime =
this.metrics.responseTime.length > 0
? this.metrics.responseTime.reduce(
(sum, item) => sum + item.time,
0
) / this.metrics.responseTime.length
: 0;
const avgMemoryUsage =
this.metrics.memoryUsage.length > 0
? this.metrics.memoryUsage.reduce(
(sum, item) => sum + item.heapUsed,
0
) / this.metrics.memoryUsage.length
: 0;
return {
startupTime: this.metrics.startupTime,
averageResponseTime: avgResponseTime,
averageMemoryUsage: Math.round(
avgMemoryUsage / 1024 / 1024
), // MB
totalErrors: this.metrics.errorCount,
memoryPeakUsage:
Math.max(
...this.metrics.memoryUsage.map((m) => m.heapUsed)
) /
1024 /
1024,
responseTimeP95: this.calculatePercentile(
this.metrics.responseTime.map((r) => r.time),
95
),
};
}
calculatePercentile(values, percentile) {
const sorted = [...values].sort((a, b) => a - b);
const index =
Math.ceil((percentile / 100) * sorted.length) - 1;
return sorted[index] || 0;
}
}
ベンチマークテストの実装:
bash#!/bin/bash
# Cursorパフォーマンステストスクリプト
echo "Cursorパフォーマンステストを開始します..."
# テスト環境の情報収集
echo "=== システム情報 ==="
echo "OS: $(uname -s)"
echo "メモリ: $(free -h | grep Mem | awk '{print $2}' 2>/dev/null || echo 'N/A')"
echo "CPU: $(nproc 2>/dev/null || sysctl -n hw.ncpu 2>/dev/null || echo 'N/A') cores"
# プロジェクト情報
echo "=== プロジェクト情報 ==="
file_count=$(find . -type f | wc -l)
js_file_count=$(find . -name "*.js" -o -name "*.ts" -o -name "*.jsx" -o -name "*.tsx" | wc -l)
echo "総ファイル数: $file_count"
echo "JS/TSファイル数: $js_file_count"
# Cursorの起動時間測定
echo "=== 起動時間測定 ==="
start_time=$(date +%s%N)
code . --wait
end_time=$(date +%s%N)
startup_time=$(((end_time - start_time) / 1000000))
echo "起動時間: ${startup_time}ms"
# インデックス処理時間の測定
echo "=== インデックス処理時間測定 ==="
# インデックスキャッシュを削除
rm -rf ~/.cursor/cache/*
start_time=$(date +%s%N)
# インデックス再構築をトリガー
curl -X POST http://localhost:23432/api/reindex 2>/dev/null || echo "インデックス再構築API呼び出し失敗"
sleep 5
end_time=$(date +%s%N)
index_time=$(((end_time - start_time) / 1000000))
echo "インデックス処理時間: ${index_time}ms"
# メモリ使用量の測定
echo "=== メモリ使用量測定 ==="
cursor_pid=$(pgrep -f cursor | head -1)
if [ ! -z "$cursor_pid" ]; then
memory_usage=$(ps -p $cursor_pid -o rss= 2>/dev/null)
if [ ! -z "$memory_usage" ]; then
echo "メモリ使用量: $((memory_usage / 1024))MB"
fi
fi
# 結果をファイルに保存
cat > performance_report.json <<EOF
{
"timestamp": "$(date -Iseconds)",
"system": {
"os": "$(uname -s)",
"memory": "$(free -h | grep Mem | awk '{print $2}' 2>/dev/null || echo 'N/A')",
"cpu_cores": $(nproc 2>/dev/null || sysctl -n hw.ncpu 2>/dev/null || echo 0)
},
"project": {
"total_files": $file_count,
"js_ts_files": $js_file_count
},
"performance": {
"startup_time_ms": $startup_time,
"indexing_time_ms": $index_time,
"memory_usage_mb": $((memory_usage / 1024))
}
}
EOF
echo "パフォーマンステスト完了。結果は performance_report.json に保存されました。"
継続的なパフォーマンス監視:
typescript// 継続的監視システム
class ContinuousMonitor {
private metrics: Map<string, number[]> = new Map();
private thresholds = {
responseTime: 1000, // 1秒
memoryUsage: 2048, // 2GB
errorRate: 0.05, // 5%
};
startMonitoring() {
// 定期的なヘルスチェック
setInterval(() => {
this.collectMetrics();
this.checkThresholds();
}, 60000); // 1分ごと
// プロセス終了時のレポート生成
process.on('exit', () => {
this.generateFinalReport();
});
}
private collectMetrics() {
const now = Date.now();
const memUsage = process.memoryUsage();
this.addMetric(
'memory_heap_used',
memUsage.heapUsed / 1024 / 1024
);
this.addMetric(
'memory_heap_total',
memUsage.heapTotal / 1024 / 1024
);
this.addMetric('timestamp', now);
}
private addMetric(key: string, value: number) {
if (!this.metrics.has(key)) {
this.metrics.set(key, []);
}
const values = this.metrics.get(key)!;
values.push(value);
// 最新100件のみ保持
if (values.length > 100) {
values.shift();
}
}
private checkThresholds() {
const currentMemory =
this.metrics.get('memory_heap_used')?.slice(-1)[0] ||
0;
if (currentMemory > this.thresholds.memoryUsage) {
console.warn(
`⚠️ メモリ使用量が閾値を超えました: ${currentMemory.toFixed(
2
)}MB`
);
this.suggestOptimizations();
}
}
private suggestOptimizations() {
console.log('🔧 最適化提案:');
console.log('1. .cursorignoreファイルの見直し');
console.log('2. キャッシュのクリア');
console.log('3. ワークスペースの分割');
console.log('4. 不要なファイルの除外');
}
}
運用時の注意点
実際に Cursor を運用する際の重要なポイントと、よくある問題の対処法をまとめました。
定期メンテナンススクリプト:
bash#!/bin/bash
# Cursor定期メンテナンススクリプト
MAINTENANCE_LOG="cursor_maintenance.log"
BACKUP_DIR="$HOME/.cursor/backups"
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$MAINTENANCE_LOG"
}
# バックアップの作成
create_backup() {
log "設定バックアップを作成中..."
mkdir -p "$BACKUP_DIR"
# 設定ファイルのバックアップ
if [ -f ".vscode/settings.json" ]; then
cp ".vscode/settings.json" "$BACKUP_DIR/settings_$(date +%Y%m%d).json"
fi
if [ -f ".cursorignore" ]; then
cp ".cursorignore" "$BACKUP_DIR/cursorignore_$(date +%Y%m%d)"
fi
log "バックアップ完了"
}
# キャッシュのクリーンアップ
cleanup_cache() {
log "キャッシュクリーンアップを開始..."
# 古いキャッシュファイルの削除(7日以上)
find "$HOME/.cursor/cache" -type f -mtime +7 -delete 2>/dev/null
# ログファイルの削除(30日以上)
find "$HOME/.cursor/logs" -name "*.log" -mtime +30 -delete 2>/dev/null
log "キャッシュクリーンアップ完了"
}
# パフォーマンスチェック
performance_check() {
log "パフォーマンスチェックを実行中..."
# ディスク使用量チェック
cache_size=$(du -sh "$HOME/.cursor/cache" 2>/dev/null | cut -f1)
log "キャッシュサイズ: $cache_size"
# ファイル数チェック
file_count=$(find . -type f | wc -l)
excluded_count=$(find . -type f -path "*/node_modules/*" -o -path "*/dist/*" -o -path "*/.git/*" | wc -l)
indexed_count=$((file_count - excluded_count))
log "総ファイル数: $file_count"
log "除外ファイル数: $excluded_count"
log "インデックス対象: $indexed_count"
# 推奨事項
if [ "$indexed_count" -gt 10000 ]; then
log "⚠️ インデックス対象ファイルが多すぎます($indexed_count > 10000)"
log "💡 .cursorignoreファイルの見直しを推奨"
fi
}
# 設定の検証
validate_config() {
log "設定ファイルの検証中..."
# .cursorignoreの存在確認
if [ ! -f ".cursorignore" ]; then
log "⚠️ .cursorignoreファイルが存在しません"
log "💡 .cursorignoreファイルの作成を推奨"
fi
# settings.jsonの検証
if [ -f ".vscode/settings.json" ]; then
if ! python3 -c "import json; json.load(open('.vscode/settings.json'))" 2>/dev/null; then
log "❌ settings.jsonの構文エラーを検出"
else
log "✅ settings.json構文OK"
fi
fi
}
# メイン処理
main() {
log "Cursor定期メンテナンス開始"
create_backup
cleanup_cache
performance_check
validate_config
log "Cursor定期メンテナンス完了"
}
# エラーハンドリング
trap 'log "❌ メンテナンス中にエラーが発生しました"; exit 1' ERR
main "$@"
運用チェックリスト:
typescript// 運用チェックリストの自動実行
interface ChecklistItem {
name: string;
check: () => Promise<boolean>;
fix?: () => Promise<void>;
severity: 'low' | 'medium' | 'high';
}
class OperationChecklist {
private checklist: ChecklistItem[] = [
{
name: 'メモリ使用量チェック',
check: async () => {
const usage = process.memoryUsage();
return usage.heapUsed < 2 * 1024 * 1024 * 1024; // 2GB未満
},
fix: async () => {
console.log('キャッシュをクリアしています...');
// キャッシュクリア処理
},
severity: 'high',
},
{
name: 'インデックス対象ファイル数チェック',
check: async () => {
const fileCount = await this.countIndexedFiles();
return fileCount < 10000;
},
fix: async () => {
console.log(
'.cursorignoreファイルの最適化を提案します'
);
await this.suggestIgnorePatterns();
},
severity: 'medium',
},
{
name: 'キャッシュサイズチェック',
check: async () => {
const cacheSize = await this.getCacheSize();
return cacheSize < 1024 * 1024 * 1024; // 1GB未満
},
fix: async () => {
await this.cleanupCache();
},
severity: 'medium',
},
{
name: '設定ファイル構文チェック',
check: async () => {
return await this.validateConfigFiles();
},
fix: async () => {
console.log('設定ファイルの修正を提案します');
await this.fixConfigSyntax();
},
severity: 'high',
},
];
async runChecklist(): Promise<void> {
console.log('🔍 運用チェックリストを実行中...\n');
const results = [];
for (const item of this.checklist) {
console.log(`チェック中: ${item.name}`);
try {
const passed = await item.check();
if (passed) {
console.log(`✅ ${item.name}: OK`);
results.push({ name: item.name, status: 'pass' });
} else {
console.log(
`❌ ${item.name}: NG (重要度: ${item.severity})`
);
results.push({
name: item.name,
status: 'fail',
severity: item.severity,
});
if (item.fix) {
console.log(`🔧 自動修正を実行中...`);
await item.fix();
}
}
} catch (error) {
console.log(
`⚠️ ${item.name}: エラー - ${error.message}`
);
results.push({
name: item.name,
status: 'error',
error: error.message,
});
}
console.log('');
}
this.generateReport(results);
}
private generateReport(results: any[]): void {
const failedItems = results.filter(
(r) => r.status === 'fail'
);
const errorItems = results.filter(
(r) => r.status === 'error'
);
console.log('📊 チェック結果サマリー');
console.log(
`✅ 成功: ${
results.filter((r) => r.status === 'pass').length
}`
);
console.log(`❌ 失敗: ${failedItems.length}`);
console.log(`⚠️ エラー: ${errorItems.length}`);
if (failedItems.length > 0) {
console.log('\n🔧 推奨アクション:');
failedItems.forEach((item) => {
console.log(
`- ${item.name} (重要度: ${item.severity})`
);
});
}
}
}
トラブルシューティングガイド:
問題 | 症状 | 対処法 |
---|---|---|
起動が遅い | Cursor 起動に 30 秒以上 | .cursorignore の見直し、キャッシュクリア |
メモリ不足 | システムが重い | ワークスペース分割、メモリ制限設定 |
インデックスエラー | ファイル認識しない | インデックス再構築、設定ファイル確認 |
AI 応答が遅い | 補完に 5 秒以上 | コンテキストサイズ削減、モデル変更 |
ファイル監視エラー | 変更が反映されない | watcherExclude 設定、OS 制限確認 |
mermaidflowchart TD
problem[問題発生] --> diagnose[診断実行]
diagnose --> memory{メモリ関連?}
diagnose --> performance{パフォーマンス関連?}
diagnose --> config{設定関連?}
memory -->|Yes| cleanup[キャッシュクリア]
memory -->|Yes| split[ワークスペース分割]
performance -->|Yes| ignore[.cursorignore最適化]
performance -->|Yes| index[インデックス再構築]
config -->|Yes| validate[設定検証]
config -->|Yes| backup[バックアップから復旧]
cleanup --> verify[動作確認]
split --> verify
ignore --> verify
index --> verify
validate --> verify
backup --> verify
verify -->|OK| done[解決]
verify -->|NG| escalate[エスカレーション]
図で理解できる要点:
- 問題の種類に応じた適切な対処法を選択
- 各対処法実行後は必ず動作確認を実施
- 解決しない場合はエスカレーション手順へ
まとめ
巨大リポジトリで Cursor を快適に使用するためには、以下の最適化アプローチが効果的です。
インデックス最適化では、.cursorignore
による適切な除外設定、段階的インデックス構築、キャッシュ管理が重要です。特にnode_modules
やdist
フォルダの除外により、80-90%のファイル数削減が可能になります。
部分学習による効率化では、ワークスペース分割、コンテキスト制限、プロジェクト構造に応じた学習範囲調整により、メモリ使用量を大幅に削減できます。開発フェーズに応じて必要な部分のみを学習対象とすることで、応答速度が向上します。
運用面では、定期的なパフォーマンス測定、設定の見直し、メンテナンススクリプトの自動実行により、長期的に安定した動作を維持できます。
これらの最適化により、数万ファイルを含む巨大リポジトリでも、Cursor の起動時間を数分から数十秒に短縮し、メモリ使用量を半分以下に削減することが可能です。適切な設定と継続的な最適化により、開発効率を大幅に向上させることができるでしょう。
関連リンク
- article
Cursor が巨大リポジトリで重い時の対処:インデックス最適化と部分学習のコツ
- article
Cursor のコンテキスト設計を理解する:ファイル選択・差分適用・会話履歴の最適化
- article
Cursor で作る AI 駆動型ドキュメント生成ワークフロー
- article
VSCode 拡張との比較でわかる!Cursor を選ぶべき開発スタイル
- article
Cursor × GitHub 連携:プルリク作成からレビューまで自動化する方法
- article
Cursor のカスタムルール設定 `.cursorrules` 徹底解説と実践例
- article
Redis OOM を根絶:maxmemory・eviction・大キー検出の実践トリアージ
- article
Git 内部処理の舞台裏:パックファイル・コミットグラフ・参照の関係を図解で理解
- article
Python 依存地獄からの生還:pip/Poetry/uv の競合を解きほぐす実践手順
- article
FFmpeg 音ズレを根治:VFR→CFR 変換と PTS 補正の実践ガイド
- article
ESLint の extends が効かない問題を斬る:Flat Config の files/ignores 落とし穴
- article
Prisma アーキテクチャ超図解:Engines/Client/Generator の役割を一枚で理解
- blog
iPhone 17シリーズの発表!全モデルiPhone 16から進化したポイントを見やすく整理
- blog
Googleストアから訂正案内!Pixel 10ポイント有効期限「1年」表示は誤りだった
- blog
【2025年8月】Googleストア「ストアポイント」は1年表記はミス?2年ルールとの整合性を検証
- blog
Googleストアの注文キャンセルはなぜ起きる?Pixel 10購入前に知るべき注意点
- blog
Pixcel 10シリーズの発表!全モデル Pixcel 9 から進化したポイントを見やすく整理
- blog
フロントエンドエンジニアの成長戦略:コーチングで最速スキルアップする方法
- review
今の自分に満足していますか?『持たざる者の逆襲 まだ何者でもない君へ』溝口勇児
- review
ついに語られた業界の裏側!『フジテレビの正体』堀江貴文が描くテレビ局の本当の姿
- review
愛する勇気を持てば人生が変わる!『幸せになる勇気』岸見一郎・古賀史健のアドラー実践編で真の幸福を手に入れる
- review
週末を変えれば年収も変わる!『世界の一流は「休日」に何をしているのか』越川慎司の一流週末メソッド
- review
新しい自分に会いに行こう!『自分の変え方』村岡大樹の認知科学コーチングで人生リセット
- review
科学革命から AI 時代へ!『サピエンス全史 下巻』ユヴァル・ノア・ハラリが予見する人類の未来