Files
michaelschiemer/tests/debug/test-database-optimization-tools.php
Michael Schiemer fc3d7e6357 feat(Production): Complete production deployment infrastructure
- Add comprehensive health check system with multiple endpoints
- Add Prometheus metrics endpoint
- Add production logging configurations (5 strategies)
- Add complete deployment documentation suite:
  * QUICKSTART.md - 30-minute deployment guide
  * DEPLOYMENT_CHECKLIST.md - Printable verification checklist
  * DEPLOYMENT_WORKFLOW.md - Complete deployment lifecycle
  * PRODUCTION_DEPLOYMENT.md - Comprehensive technical reference
  * production-logging.md - Logging configuration guide
  * ANSIBLE_DEPLOYMENT.md - Infrastructure as Code automation
  * README.md - Navigation hub
  * DEPLOYMENT_SUMMARY.md - Executive summary
- Add deployment scripts and automation
- Add DEPLOYMENT_PLAN.md - Concrete plan for immediate deployment
- Update README with production-ready features

All production infrastructure is now complete and ready for deployment.
2025-10-25 19:18:37 +02:00

345 lines
12 KiB
PHP

<?php
declare(strict_types=1);
require_once __DIR__ . '/../../vendor/autoload.php';
use App\Framework\Core\ValueObjects\Duration;
use App\Framework\Database\Profiling\QueryAnalyzer;
use App\Framework\Database\Profiling\QueryProfile;
echo "=== Testing Database Query Optimization Tools ===\n\n";
echo "1. Testing Query Analysis System:\n";
try {
// Create mock connection for analyzer
$mockConnection = new class () {
public function query(string $sql)
{
// Mock implementation that returns a result-like object
return new class () {
public function fetch()
{
static $called = false;
if (! $called) {
$called = true;
return [
'id' => 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";