Skip to main content
Glama
sascodiego

MCP Vibe Coding Knowledge Graph

by sascodiego
queryOptimizer.js29.8 kB
import { logger } from '../utils/logger.js'; import { EventEmitter } from 'events'; /** * CONTEXT: Advanced query optimization and caching system for Kuzu database * REASON: Maximize query performance through intelligent optimization and caching * CHANGE: Comprehensive optimization engine with adaptive caching strategies * PREVENTION: Slow queries, resource waste, and performance degradation */ export class QueryOptimizer extends EventEmitter { constructor(config = {}) { super(); this.config = { cacheSize: config.cacheSize || 10000, cacheTTL: config.cacheTTL || 3600, // 1 hour default adaptiveCaching: config.adaptiveCaching !== false, optimizationLevel: config.optimizationLevel || 'balanced', // 'aggressive', 'balanced', 'conservative' enableStatistics: config.enableStatistics !== false, maxOptimizationTime: config.maxOptimizationTime || 100, // ms ...config }; // Caching system this.queryCache = new Map(); this.resultCache = new Map(); this.planCache = new Map(); // Statistics and analytics this.queryStats = new Map(); this.optimizationStats = { queriesOptimized: 0, totalOptimizationTime: 0, averageOptimizationTime: 0, cacheHits: 0, cacheMisses: 0, optimizationsFailed: 0 }; // Optimization rules and patterns this.optimizationRules = new Map(); this.patternCatalog = new Map(); this.indexHints = new Map(); this.initializeOptimizationRules(); this.startMaintenanceRoutines(); logger.info('QueryOptimizer initialized', { cacheSize: this.config.cacheSize, optimizationLevel: this.config.optimizationLevel }); } /** * Optimize a query before execution */ async optimizeQuery(query, parameters = {}, metadata = {}) { const startTime = Date.now(); try { const querySignature = this.generateQuerySignature(query, parameters); // Check if we have a cached optimized version const cachedOptimization = this.getCachedOptimization(querySignature); if (cachedOptimization) { this.optimizationStats.cacheHits++; logger.debug('Using cached query optimization', { querySignature: querySignature.substring(0, 50) }); return cachedOptimization; } this.optimizationStats.cacheMisses++; // Analyze query structure const analysis = this.analyzeQuery(query, parameters, metadata); // Apply optimization rules const optimizedQuery = await this.applyOptimizationRules(query, analysis); // Generate execution hints const hints = this.generateExecutionHints(analysis); // Create optimization result const optimization = { originalQuery: query, optimizedQuery, parameters, hints, analysis, optimizationLevel: this.config.optimizationLevel, timestamp: Date.now(), estimatedImprovement: this.estimateImprovement(analysis) }; // Cache the optimization this.cacheOptimization(querySignature, optimization); // Update statistics const optimizationTime = Date.now() - startTime; this.updateOptimizationStats(optimizationTime, true); logger.debug('Query optimized successfully', { optimizationTime: `${optimizationTime}ms`, estimatedImprovement: optimization.estimatedImprovement, hintsGenerated: hints.length }); this.emit('queryOptimized', optimization); return optimization; } catch (error) { const optimizationTime = Date.now() - startTime; this.updateOptimizationStats(optimizationTime, false); logger.error('Query optimization failed', { error: error.message, query: query.substring(0, 200) }); this.emit('optimizationError', { error, query }); // Return original query as fallback return { originalQuery: query, optimizedQuery: query, parameters, hints: [], analysis: { complexity: 'unknown' }, optimizationLevel: 'none', timestamp: Date.now(), estimatedImprovement: 0, error: error.message }; } } /** * Analyze query structure and characteristics */ analyzeQuery(query, parameters, metadata) { const analysis = { queryType: this.detectQueryType(query), complexity: this.calculateComplexity(query), patterns: this.extractPatterns(query), joins: this.detectJoins(query), filters: this.extractFilters(query), aggregations: this.detectAggregations(query), orderBy: this.extractOrderBy(query), limit: this.extractLimit(query), parameterCount: Object.keys(parameters).length, estimatedRows: this.estimateRowCount(query, metadata), indexes: this.suggestIndexes(query), bottlenecks: this.identifyBottlenecks(query) }; // Advanced analysis for complex queries if (analysis.complexity > 10) { analysis.subqueries = this.extractSubqueries(query); analysis.recursion = this.detectRecursion(query); analysis.cartesianProducts = this.detectCartesianProducts(query); } return analysis; } /** * Apply optimization rules based on analysis */ async applyOptimizationRules(query, analysis) { let optimizedQuery = query; const appliedRules = []; for (const [ruleName, rule] of this.optimizationRules) { try { if (rule.condition(analysis, this.config.optimizationLevel)) { const ruleResult = await rule.apply(optimizedQuery, analysis); if (ruleResult.modified) { optimizedQuery = ruleResult.query; appliedRules.push({ name: ruleName, improvement: ruleResult.improvement || 0, description: rule.description }); logger.debug(`Applied optimization rule: ${ruleName}`, { improvement: ruleResult.improvement }); } } } catch (error) { logger.warn(`Optimization rule ${ruleName} failed`, { error: error.message }); } } if (appliedRules.length > 0) { logger.debug('Query optimization completed', { rulesApplied: appliedRules.length, rules: appliedRules.map(r => r.name) }); } return optimizedQuery; } /** * Generate execution hints for the query optimizer */ generateExecutionHints(analysis) { const hints = []; // Index hints if (analysis.indexes && analysis.indexes.length > 0) { hints.push({ type: 'INDEX_USAGE', value: analysis.indexes, priority: 'HIGH' }); } // Join order hints if (analysis.joins && analysis.joins.length > 1) { const optimalJoinOrder = this.calculateOptimalJoinOrder(analysis.joins); hints.push({ type: 'JOIN_ORDER', value: optimalJoinOrder, priority: 'MEDIUM' }); } // Memory hints if (analysis.estimatedRows > 100000) { hints.push({ type: 'MEMORY_OPTIMIZATION', value: 'USE_STREAMING', priority: 'HIGH' }); } // Parallel execution hints if (analysis.complexity > 15) { hints.push({ type: 'PARALLEL_EXECUTION', value: 'ENABLE', priority: 'MEDIUM' }); } // Filter pushdown hints if (analysis.filters && analysis.filters.length > 0) { hints.push({ type: 'FILTER_PUSHDOWN', value: analysis.filters, priority: 'HIGH' }); } return hints; } /** * Cache query results with intelligent eviction */ cacheResult(querySignature, result, ttl = null) { const cacheTTL = ttl || this.config.cacheTTL; const cacheEntry = { result, timestamp: Date.now(), ttl: cacheTTL * 1000, // Convert to milliseconds accessCount: 1, lastAccessed: Date.now(), size: this.estimateResultSize(result) }; // Adaptive TTL based on query characteristics if (this.config.adaptiveCaching) { cacheEntry.ttl = this.calculateAdaptiveTTL(querySignature, result); } this.resultCache.set(querySignature, cacheEntry); // Evict if cache is full this.evictIfNecessary(); logger.debug('Result cached', { querySignature: querySignature.substring(0, 50), resultSize: cacheEntry.size, ttl: cacheEntry.ttl / 1000 }); this.emit('resultCached', { querySignature, size: cacheEntry.size }); } /** * Get cached result if available and valid */ getCachedResult(querySignature) { const cacheEntry = this.resultCache.get(querySignature); if (!cacheEntry) { return null; } const now = Date.now(); const isExpired = (now - cacheEntry.timestamp) > cacheEntry.ttl; if (isExpired) { this.resultCache.delete(querySignature); logger.debug('Cache entry expired and removed', { querySignature: querySignature.substring(0, 50) }); return null; } // Update access statistics cacheEntry.accessCount++; cacheEntry.lastAccessed = now; // Extend TTL for frequently accessed items if (this.config.adaptiveCaching && cacheEntry.accessCount > 5) { cacheEntry.ttl *= 1.2; // Extend by 20% } logger.debug('Cache hit', { querySignature: querySignature.substring(0, 50), accessCount: cacheEntry.accessCount }); this.emit('cacheHit', { querySignature, accessCount: cacheEntry.accessCount }); return cacheEntry.result; } /** * Invalidate cache entries based on patterns */ invalidateCache(pattern = null) { let invalidatedCount = 0; if (pattern) { // Invalidate specific pattern for (const [key, entry] of this.resultCache) { if (key.includes(pattern)) { this.resultCache.delete(key); invalidatedCount++; } } } else { // Clear all cache invalidatedCount = this.resultCache.size; this.resultCache.clear(); } logger.debug('Cache invalidated', { pattern, entriesInvalidated: invalidatedCount }); this.emit('cacheInvalidated', { pattern, count: invalidatedCount }); return invalidatedCount; } /** * Get comprehensive statistics */ getStatistics() { const cacheStats = this.getCacheStatistics(); const queryStats = this.getQueryStatistics(); return { optimization: { ...this.optimizationStats }, cache: cacheStats, queries: queryStats, config: this.config, uptime: Date.now() - (this.startTime || Date.now()) }; } /** * Get cache statistics */ getCacheStatistics() { const entries = Array.from(this.resultCache.values()); const totalSize = entries.reduce((sum, entry) => sum + entry.size, 0); const averageSize = entries.length > 0 ? totalSize / entries.length : 0; const totalAccesses = entries.reduce((sum, entry) => sum + entry.accessCount, 0); return { size: this.resultCache.size, maxSize: this.config.cacheSize, utilization: (this.resultCache.size / this.config.cacheSize) * 100, totalSize, averageSize, totalAccesses, hitRate: this.optimizationStats.cacheHits / (this.optimizationStats.cacheHits + this.optimizationStats.cacheMisses) * 100 }; } /** * Get query statistics */ getQueryStatistics() { const stats = Array.from(this.queryStats.values()); return { totalQueries: stats.reduce((sum, s) => sum + s.executions, 0), totalErrors: stats.reduce((sum, s) => sum + s.errors, 0), averageExecutionTime: stats.reduce((sum, s) => sum + s.averageTime, 0) / stats.length || 0, uniqueQueries: stats.length }; } /** * Initialize optimization rules */ initializeOptimizationRules() { // Filter pushdown optimization this.optimizationRules.set('filterPushdown', { description: 'Push WHERE conditions closer to data sources', condition: (analysis, level) => analysis.filters.length > 0, apply: async (query, analysis) => { // Implementation for pushing filters down let modified = false; let optimizedQuery = query; // Simple filter pushdown logic if (query.includes('WHERE') && query.includes('MATCH')) { const whereIndex = query.indexOf('WHERE'); const matchIndex = query.lastIndexOf('MATCH', whereIndex); if (matchIndex < whereIndex && whereIndex - matchIndex > 50) { // Move simple filters closer to MATCH modified = true; // This is a simplified example - real implementation would be more complex } } return { modified, query: optimizedQuery, improvement: modified ? 15 : 0 }; } }); // Index hint optimization this.optimizationRules.set('indexHints', { description: 'Add index hints for better performance', condition: (analysis, level) => analysis.indexes.length > 0, apply: async (query, analysis) => { let optimizedQuery = query; let modified = false; // Add index hints where appropriate for (const index of analysis.indexes) { if (!query.includes(`USING INDEX ${index}`)) { // Add index hint const hintComment = `/* USING INDEX ${index} */`; optimizedQuery = optimizedQuery.replace( /MATCH\s+\([^)]+\)/, `$& ${hintComment}` ); modified = true; } } return { modified, query: optimizedQuery, improvement: modified ? 20 : 0 }; } }); // LIMIT pushdown optimization this.optimizationRules.set('limitPushdown', { description: 'Push LIMIT clauses to reduce intermediate results', condition: (analysis, level) => analysis.limit && analysis.limit < 1000, apply: async (query, analysis) => { let modified = false; let optimizedQuery = query; // If query has ORDER BY with LIMIT, consider pushing limit down if (query.includes('ORDER BY') && query.includes('LIMIT')) { // This is a placeholder for more complex limit pushdown logic modified = true; } return { modified, query: optimizedQuery, improvement: modified ? 10 : 0 }; } }); // Join reordering optimization this.optimizationRules.set('joinReordering', { description: 'Reorder joins for optimal execution', condition: (analysis, level) => analysis.joins.length > 1 && level !== 'conservative', apply: async (query, analysis) => { let modified = false; let optimizedQuery = query; // Simplified join reordering logic if (analysis.joins.length > 2) { // This would implement cost-based join reordering modified = true; } return { modified, query: optimizedQuery, improvement: modified ? 25 : 0 }; } }); logger.debug('Optimization rules initialized', { ruleCount: this.optimizationRules.size }); } /** * Detect query type */ detectQueryType(query) { const upperQuery = query.toUpperCase(); if (upperQuery.includes('CREATE') || upperQuery.includes('MERGE')) { return 'WRITE'; } else if (upperQuery.includes('DELETE') || upperQuery.includes('REMOVE')) { return 'DELETE'; } else if (upperQuery.includes('SET')) { return 'UPDATE'; } else { return 'READ'; } } /** * Calculate query complexity score */ calculateComplexity(query) { let complexity = 1; // Count pattern matches const matchCount = (query.match(/MATCH/gi) || []).length; complexity += matchCount * 2; // Count relationships const relationshipCount = (query.match(/-\[.*?\]-/g) || []).length; complexity += relationshipCount * 3; // Count variable length paths const variableLengthCount = (query.match(/\*\d*\.\.\d*/g) || []).length; complexity += variableLengthCount * 10; // Count aggregations const aggregationCount = (query.match(/\b(count|sum|avg|max|min|collect)\s*\(/gi) || []).length; complexity += aggregationCount * 2; // Count subqueries const subqueryCount = (query.match(/\bWITH\b/gi) || []).length; complexity += subqueryCount * 3; return complexity; } /** * Extract patterns from query */ extractPatterns(query) { const patterns = []; const patternRegex = /\([^)]*\)(?:-\[[^\]]*\]-\([^)]*\))*/g; let match; while ((match = patternRegex.exec(query)) !== null) { patterns.push(match[0]); } return patterns; } /** * Detect joins in query */ detectJoins(query) { const joins = []; // Simple join detection based on multiple MATCH clauses or relationship patterns const matchCount = (query.match(/MATCH/gi) || []).length; if (matchCount > 1) { joins.push({ type: 'IMPLICIT', count: matchCount - 1 }); } // Detect relationship-based joins const relationshipCount = (query.match(/-\[.*?\]-/g) || []).length; if (relationshipCount > 0) { joins.push({ type: 'RELATIONSHIP', count: relationshipCount }); } return joins; } /** * Extract filters from WHERE clauses */ extractFilters(query) { const filters = []; const whereRegex = /WHERE\s+(.+?)(?:\s+(?:RETURN|ORDER|LIMIT|WITH|$))/gi; let match; while ((match = whereRegex.exec(query)) !== null) { const condition = match[1].trim(); filters.push({ condition, type: this.classifyFilter(condition), selectivity: this.estimateSelectivity(condition) }); } return filters; } /** * Classify filter type */ classifyFilter(condition) { if (condition.includes('=')) return 'EQUALITY'; if (condition.includes('>') || condition.includes('<')) return 'RANGE'; if (condition.includes('CONTAINS') || condition.includes('LIKE')) return 'TEXT_SEARCH'; if (condition.includes('IN')) return 'IN_LIST'; return 'OTHER'; } /** * Estimate filter selectivity (0-1, lower is more selective) */ estimateSelectivity(condition) { if (condition.includes('=')) return 0.1; if (condition.includes('CONTAINS')) return 0.3; if (condition.includes('>') || condition.includes('<')) return 0.5; return 0.8; } /** * Detect aggregations */ detectAggregations(query) { const aggregations = []; const aggRegex = /\b(count|sum|avg|max|min|collect)\s*\([^)]*\)/gi; let match; while ((match = aggRegex.exec(query)) !== null) { aggregations.push({ function: match[1].toLowerCase(), expression: match[0] }); } return aggregations; } /** * Extract ORDER BY clause */ extractOrderBy(query) { const orderRegex = /ORDER BY\s+(.+?)(?:\s+(?:LIMIT|SKIP|$))/i; const match = orderRegex.exec(query); if (match) { const orderBy = match[1].trim(); return { expression: orderBy, direction: orderBy.toUpperCase().includes('DESC') ? 'DESC' : 'ASC' }; } return null; } /** * Extract LIMIT clause */ extractLimit(query) { const limitRegex = /LIMIT\s+(\d+)/i; const match = limitRegex.exec(query); return match ? parseInt(match[1]) : null; } /** * Estimate row count */ estimateRowCount(query, metadata) { // This is a simplified estimation let estimate = 1000; // Default estimate if (metadata.entityCounts) { // Use actual entity counts if available if (query.includes('CodeEntity')) { estimate = metadata.entityCounts.codeEntities || estimate; } if (query.includes('Pattern')) { estimate = Math.min(estimate, metadata.entityCounts.patterns || estimate); } } // Adjust for filters const filters = this.extractFilters(query); for (const filter of filters) { estimate *= filter.selectivity; } // Adjust for limit const limit = this.extractLimit(query); if (limit) { estimate = Math.min(estimate, limit); } return Math.ceil(estimate); } /** * Suggest indexes based on query patterns */ suggestIndexes(query) { const suggestions = []; // Suggest indexes for equality filters const equalityFilters = query.match(/(\w+)\.(\w+)\s*=\s*\$(\w+)/g); if (equalityFilters) { for (const filter of equalityFilters) { const parts = filter.match(/(\w+)\.(\w+)/); if (parts) { suggestions.push(`${parts[1]}_${parts[2]}`); } } } // Suggest indexes for ORDER BY const orderBy = this.extractOrderBy(query); if (orderBy) { const field = orderBy.expression.split(' ')[0]; if (field.includes('.')) { suggestions.push(field.replace('.', '_')); } } return [...new Set(suggestions)]; // Remove duplicates } /** * Identify potential bottlenecks */ identifyBottlenecks(query) { const bottlenecks = []; // Cartesian products if (this.detectCartesianProducts(query)) { bottlenecks.push({ type: 'CARTESIAN_PRODUCT', severity: 'HIGH', description: 'Query may produce cartesian product' }); } // Missing indexes const filters = this.extractFilters(query); for (const filter of filters) { if (filter.type === 'EQUALITY' && !query.includes('USING INDEX')) { bottlenecks.push({ type: 'MISSING_INDEX', severity: 'MEDIUM', description: `Consider adding index for ${filter.condition}` }); } } // Large result sets without LIMIT if (!this.extractLimit(query) && !query.includes('count(')) { bottlenecks.push({ type: 'UNLIMITED_RESULTS', severity: 'MEDIUM', description: 'Query may return large result set without LIMIT' }); } return bottlenecks; } /** * Detect potential cartesian products */ detectCartesianProducts(query) { const matchClauses = (query.match(/MATCH/gi) || []).length; const whereClauses = (query.match(/WHERE/gi) || []).length; // Simple heuristic: multiple MATCH clauses without proper WHERE conditions return matchClauses > 1 && whereClauses === 0; } /** * Calculate adaptive TTL based on query characteristics */ calculateAdaptiveTTL(querySignature, result) { let baseTTL = this.config.cacheTTL * 1000; // Convert to milliseconds // Extend TTL for expensive queries (more complex = longer cache) const complexity = this.calculateComplexity(querySignature); const complexityMultiplier = Math.min(complexity / 10, 3); // Cap at 3x baseTTL *= (1 + complexityMultiplier); // Extend TTL for smaller result sets (less likely to change) const resultSize = this.estimateResultSize(result); if (resultSize < 1000) { baseTTL *= 1.5; } // Reduce TTL for write-heavy patterns if (querySignature.includes('CREATE') || querySignature.includes('MERGE')) { baseTTL *= 0.5; } return Math.min(baseTTL, this.config.cacheTTL * 5000); // Cap at 5x original TTL } /** * Estimate result size in bytes */ estimateResultSize(result) { if (!result || !Array.isArray(result)) return 0; // Rough estimation: 100 bytes per row on average return result.length * 100; } /** * Calculate optimal join order */ calculateOptimalJoinOrder(joins) { // Simplified join ordering - in practice this would be much more complex return joins.sort((a, b) => { // Prefer smaller tables first (if we had cardinality estimates) if (a.type === 'RELATIONSHIP' && b.type === 'IMPLICIT') return -1; if (a.type === 'IMPLICIT' && b.type === 'RELATIONSHIP') return 1; return 0; }); } /** * Generate query signature for caching */ generateQuerySignature(query, parameters) { const normalizedQuery = query .replace(/\s+/g, ' ') .trim() .toLowerCase(); const paramString = JSON.stringify(parameters, Object.keys(parameters).sort()); return `${normalizedQuery}|${paramString}`; } /** * Cache optimization result */ cacheOptimization(querySignature, optimization) { this.queryCache.set(querySignature, { ...optimization, accessCount: 0, lastAccessed: Date.now() }); // Limit cache size if (this.queryCache.size > this.config.cacheSize) { // Remove least recently used let oldestKey = null; let oldestTime = Date.now(); for (const [key, entry] of this.queryCache) { if (entry.lastAccessed < oldestTime) { oldestTime = entry.lastAccessed; oldestKey = key; } } if (oldestKey) { this.queryCache.delete(oldestKey); } } } /** * Get cached optimization */ getCachedOptimization(querySignature) { const cached = this.queryCache.get(querySignature); if (cached) { cached.accessCount++; cached.lastAccessed = Date.now(); return cached; } return null; } /** * Evict cache entries if necessary */ evictIfNecessary() { if (this.resultCache.size <= this.config.cacheSize) { return; } // LRU eviction strategy const entries = Array.from(this.resultCache.entries()) .sort(([,a], [,b]) => a.lastAccessed - b.lastAccessed); const toEvict = entries.slice(0, entries.length - this.config.cacheSize); for (const [key] of toEvict) { this.resultCache.delete(key); } logger.debug('Cache eviction completed', { evictedCount: toEvict.length, remainingSize: this.resultCache.size }); } /** * Update optimization statistics */ updateOptimizationStats(optimizationTime, success) { this.optimizationStats.queriesOptimized++; if (success) { this.optimizationStats.totalOptimizationTime += optimizationTime; this.optimizationStats.averageOptimizationTime = this.optimizationStats.totalOptimizationTime / this.optimizationStats.queriesOptimized; } else { this.optimizationStats.optimizationsFailed++; } } /** * Start maintenance routines */ startMaintenanceRoutines() { // Cache cleanup routine setInterval(() => { this.cleanupExpiredEntries(); }, 60000); // Every minute // Statistics logging setInterval(() => { const stats = this.getStatistics(); logger.debug('QueryOptimizer statistics', stats); this.emit('statisticsUpdate', stats); }, 300000); // Every 5 minutes } /** * Clean up expired cache entries */ cleanupExpiredEntries() { const now = Date.now(); let cleanedCount = 0; for (const [key, entry] of this.resultCache) { if ((now - entry.timestamp) > entry.ttl) { this.resultCache.delete(key); cleanedCount++; } } if (cleanedCount > 0) { logger.debug('Cache cleanup completed', { cleanedCount, remainingSize: this.resultCache.size }); } } /** * Estimate performance improvement */ estimateImprovement(analysis) { let improvement = 0; // Index usage improvement if (analysis.indexes.length > 0) { improvement += 20; } // Filter selectivity improvement const selectiveFilters = analysis.filters.filter(f => f.selectivity < 0.3); improvement += selectiveFilters.length * 10; // Join optimization improvement if (analysis.joins.length > 1) { improvement += 15; } // Limit clause improvement if (analysis.limit && analysis.limit < 100) { improvement += 25; } return Math.min(improvement, 100); // Cap at 100% } /** * Shutdown the optimizer */ shutdown() { this.queryCache.clear(); this.resultCache.clear(); this.planCache.clear(); logger.info('QueryOptimizer shutdown completed'); this.emit('shutdown'); } } export default QueryOptimizer;

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/sascodiego/KGsMCP'

If you have feedback or need assistance with the MCP directory API, please join our Discord server