1, 'select_type' => 'SIMPLE', 'table' => 'users', 'type' => 'ALL', 'key' => null, 'rows' => 1000 ]; } return false; } }; } public function queryScalar(string $sql) { return '{"Plan": {"Node Type": "Seq Scan", "Relation Name": "users"}}'; } }; $analyzer = new QueryAnalyzer($mockConnection); echo " ✅ QueryAnalyzer created successfully\n\n"; } catch (\Throwable $e) { echo " ❌ Error creating QueryAnalyzer: {$e->getMessage()}\n\n"; } echo "2. Testing Query Analysis with Different Query Types:\n"; $testQueries = [ [ 'name' => 'Simple SELECT', 'sql' => 'SELECT id, name FROM users WHERE active = 1', 'execution_time_ms' => 25.5, 'memory_usage' => 512000 ], [ 'name' => 'SELECT with wildcard', 'sql' => 'SELECT * FROM users WHERE email LIKE "%@example.com"', 'execution_time_ms' => 1250.0, 'memory_usage' => 5242880 ], [ 'name' => 'Complex JOIN query', 'sql' => 'SELECT u.*, p.name as profile_name FROM users u LEFT JOIN profiles p ON u.id = p.user_id LEFT JOIN settings s ON u.id = s.user_id WHERE u.active = 1 ORDER BY u.created_at DESC', 'execution_time_ms' => 2100.7, 'memory_usage' => 10485760 ], [ 'name' => 'Subquery with aggregation', 'sql' => 'SELECT COUNT(*) FROM users WHERE id IN (SELECT user_id FROM orders WHERE total > (SELECT AVG(total) FROM orders))', 'execution_time_ms' => 3500.2, 'memory_usage' => 15728640 ], [ 'name' => 'Optimized query', 'sql' => 'SELECT id, email FROM users WHERE created_at >= ? AND status = ? LIMIT 100', 'execution_time_ms' => 15.3, 'memory_usage' => 204800 ] ]; foreach ($testQueries as $testQuery) { try { echo " 🔍 Analyzing: {$testQuery['name']}\n"; // Create a QueryProfile for testing $profile = new class( $testQuery['sql'], $testQuery['execution_time_ms'], $testQuery['memory_usage'] ) { public string $id; public object $query; public Duration $executionTime; public object $startTimestamp; public object $endTimestamp; public int $memoryUsage; public function __construct(string $sql, float $executionTimeMs, int $memoryUsage) { $this->id = uniqid('query_'); $this->query = new class($sql) { public function __construct(public string $sql) {} }; $this->executionTime = Duration::fromMilliseconds($executionTimeMs); $this->startTimestamp = new class { public function __construct() {} }; $this->endTimestamp = new class { public function __construct() {} }; $this->memoryUsage = $memoryUsage; } public function getComplexityScore(): int { $sql = strtoupper($this->query->sql); $complexity = 0; $complexity += substr_count($sql, 'JOIN') * 2; $complexity += substr_count($sql, 'SELECT') - 1; $complexity += substr_count($sql, 'UNION') * 3; $complexity += substr_count($sql, 'GROUP BY') * 2; $complexity += substr_count($sql, 'ORDER BY'); $complexity += substr_count($sql, 'SUBQUERY') * 4; return max(1, $complexity); } }; $analysis = $analyzer->analyzeQuery($profile); echo " • SQL: " . substr($testQuery['sql'], 0, 60) . (strlen($testQuery['sql']) > 60 ? '...' : '') . "\n"; echo " • Execution time: {$testQuery['execution_time_ms']}ms\n"; echo " • Memory usage: " . number_format($testQuery['memory_usage'] / 1024 / 1024, 2) . " MB\n"; echo " • Optimization Score: {$analysis->optimizationScore}/100\n"; echo " • Issues found: " . count($analysis->issues) . "\n"; echo " • Suggestions: " . count($analysis->suggestions) . "\n"; if (!empty($analysis->issues)) { echo " • Top issue: {$analysis->issues[0]}\n"; } if (!empty($analysis->suggestions)) { echo " • Top suggestion: {$analysis->suggestions[0]}\n"; } if (!empty($analysis->indexRecommendations)) { echo " • Index recommendation: {$analysis->indexRecommendations[0]}\n"; } echo "\n"; } catch (\Throwable $e) { echo " ❌ Error analyzing query: {$e->getMessage()}\n\n"; } } echo "3. Testing Batch Analysis and Summary:\n"; try { // Create profiles for batch analysis $profiles = []; foreach ($testQueries as $i => $testQuery) { $profiles[] = new class( $testQuery['sql'], $testQuery['execution_time_ms'], $testQuery['memory_usage'], $i ) { public string $id; public object $query; public Duration $executionTime; public object $startTimestamp; public object $endTimestamp; public int $memoryUsage; public function __construct(string $sql, float $executionTimeMs, int $memoryUsage, int $index) { $this->id = "query_{$index}"; $this->query = new class($sql) { public function __construct(public string $sql) {} }; $this->executionTime = Duration::fromMilliseconds($executionTimeMs); $this->startTimestamp = new class { public function __construct() {} }; $this->endTimestamp = new class { public function __construct() {} }; $this->memoryUsage = $memoryUsage; } public function getComplexityScore(): int { $sql = strtoupper($this->query->sql); $complexity = 0; $complexity += substr_count($sql, 'JOIN') * 2; $complexity += substr_count($sql, 'SELECT') - 1; $complexity += substr_count($sql, 'UNION') * 3; $complexity += substr_count($sql, 'GROUP BY') * 2; $complexity += substr_count($sql, 'ORDER BY'); return max(1, $complexity); } }; } $batchAnalyses = $analyzer->batchAnalyze($profiles); $summary = $analyzer->getOptimizationSummary($batchAnalyses); echo " 📊 Batch Analysis Summary:\n"; echo " • Total queries analyzed: {$summary['total_queries_analyzed']}\n"; echo " • Average optimization score: {$summary['average_optimization_score']}/100\n"; echo " • Total issues: {$summary['total_issues']}\n"; echo " • Total suggestions: {$summary['total_suggestions']}\n"; echo " • Overall assessment: {$summary['overall_assessment']}\n\n"; echo " 🔥 Most Common Issues:\n"; foreach ($summary['most_common_issues'] as $issue => $count) { echo " • {$issue} (occurred {$count} times)\n"; } echo "\n"; echo " 💡 Most Common Suggestions:\n"; foreach ($summary['most_common_suggestions'] as $suggestion => $count) { echo " • {$suggestion} (suggested {$count} times)\n"; } echo "\n"; } catch (\Throwable $e) { echo " ❌ Error in batch analysis: {$e->getMessage()}\n\n"; } echo "4. Testing Individual Query Analysis Patterns:\n"; $specialTestCases = [ [ 'name' => 'N+1 Pattern Detection', 'queries' => [ 'SELECT * FROM users', 'SELECT * FROM profiles WHERE user_id = 1', 'SELECT * FROM profiles WHERE user_id = 2', 'SELECT * FROM profiles WHERE user_id = 3', 'SELECT * FROM profiles WHERE user_id = 4', 'SELECT * FROM profiles WHERE user_id = 5' ] ], [ 'name' => 'Index Opportunity Detection', 'queries' => [ 'SELECT * FROM orders WHERE customer_id = 123', 'SELECT * FROM orders WHERE customer_id = 456', 'SELECT * FROM orders WHERE customer_id = 789', 'SELECT * FROM products WHERE category_id = 10', 'SELECT * FROM products WHERE category_id = 20' ] ] ]; foreach ($specialTestCases as $testCase) { echo " 🔍 Testing: {$testCase['name']}\n"; $queryGroups = []; foreach ($testCase['queries'] as $sql) { // Normalize SQL for pattern detection $normalized = preg_replace('/\b\d+\b/', '?', $sql); $normalized = preg_replace('/\s+/', ' ', trim($normalized)); $queryGroups[$normalized][] = $sql; } foreach ($queryGroups as $pattern => $queries) { if (count($queries) > 1) { echo " • Pattern detected: " . substr($pattern, 0, 50) . "...\n"; echo " • Execution count: " . count($queries) . "\n"; echo " • Recommendation: "; if (str_contains($pattern, 'profiles WHERE user_id')) { echo "Use eager loading to avoid N+1 queries\n"; } elseif (str_contains($pattern, 'WHERE customer_id') || str_contains($pattern, 'WHERE category_id')) { echo "Consider adding index on the WHERE clause column\n"; } else { echo "Review for optimization opportunities\n"; } } } echo "\n"; } echo "5. Testing Performance Assessment:\n"; $performanceTests = [ ['score' => 95, 'expected' => 'excellent'], ['score' => 80, 'expected' => 'good'], ['score' => 65, 'expected' => 'fair'], ['score' => 45, 'expected' => 'poor'], ['score' => 25, 'expected' => 'critical'] ]; foreach ($performanceTests as $test) { $assessment = match (true) { $test['score'] >= 90 => 'excellent', $test['score'] >= 75 => 'good', $test['score'] >= 60 => 'fair', $test['score'] >= 40 => 'poor', default => 'critical' }; $status = $assessment === $test['expected'] ? '✅' : '❌'; echo " {$status} Score {$test['score']}: {$assessment} (expected: {$test['expected']})\n"; } echo "\n=== Database Query Optimization Tools Test Completed ===\n";