Skip to content

Performance Optimization

This guide covers comprehensive performance optimization strategies for the Elasticsearch integration system, including database tuning, search optimization, caching strategies, and system-level improvements.

// Implement connection pooling
class DatabasePool {
private static $connections = [];
private static $max_connections = 10;
public static function getConnection() {
// Reuse existing connection
if (!empty(self::$connections)) {
return array_pop(self::$connections);
}
return create_new_connection();
}
public static function releaseConnection($connection) {
if (count(self::$connections) < self::$max_connections) {
self::$connections[] = $connection;
} else {
pg_close($connection);
}
}
}
-- Optimize product queries with composite indexes
CREATE INDEX idx_product_sync_composite ON product(added_search, id)
WHERE title IS NOT NULL;
-- Optimize category joins
CREATE INDEX idx_category_parent ON core_category(parent_id);
-- Optimize updated_at queries for incremental sync
CREATE INDEX idx_product_updated ON product(updated_at DESC)
WHERE added_search = FALSE;
-- Partial indexes for better performance
CREATE INDEX idx_active_products ON product(id) WHERE is_active = TRUE;
# postgresql.conf optimizations
max_connections = 200
shared_buffers = 4GB
effective_cache_size = 12GB
work_mem = 50MB
maintenance_work_mem = 1GB
checkpoint_completion_target = 0.9
wal_buffers = 16MB
default_statistics_target = 100
-- Monitor slow queries
SELECT query, calls, total_time, mean_time, rows
FROM pg_stat_statements
ORDER BY mean_time DESC
LIMIT 20;
-- Check index usage
SELECT schemaname, tablename, indexname, idx_scan, idx_tup_read, idx_tup_fetch
FROM pg_stat_user_indexes
ORDER BY idx_scan DESC;
-- Analyze table statistics
ANALYZE product;
ANALYZE core_category;
{
"settings": {
"number_of_shards": 3,
"number_of_replicas": 1,
"refresh_interval": "30s",
"max_result_window": 10000,
"index": {
"translog": {
"flush_threshold_size": "512mb",
"sync_interval": "30s"
}
}
}
}
{
"mappings": {
"properties": {
"title": {
"type": "text",
"analyzer": "lithuanian_analyzer",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
"price": {
"type": "float",
"index": true,
"doc_values": true
},
"category": {
"type": "keyword",
"eager_global_ordinals": true
}
}
}
}
// Optimized search query
private function buildOptimizedSearchQuery($query, $filters) {
$filter_clauses = [];
$query_clauses = [];
// Convert exact matches to filters (faster)
if (!empty($filters['category'])) {
$filter_clauses[] = ['term' => ['category' => $filters['category']]];
}
if (!empty($filters['brand'])) {
$filter_clauses[] = ['terms' => ['brand' => (array)$filters['brand']]];
}
if (!empty($filters['min_price']) || !empty($filters['max_price'])) {
$range = [];
if (!empty($filters['min_price'])) $range['gte'] = $filters['min_price'];
if (!empty($filters['max_price'])) $range['lte'] = $filters['max_price'];
$filter_clauses[] = ['range' => ['price' => $range]];
}
// Keep fuzzy search in query
if (!empty($query)) {
$query_clauses[] = [
'multi_match' => [
'query' => $query,
'fields' => ['title^3', 'brand^2', 'description'],
'fuzziness' => 'AUTO'
]
];
}
return [
'bool' => [
'must' => $query_clauses,
'filter' => $filter_clauses
]
];
}
// Optimize search parameters
private $search_optimizations = [
'preference' => '_local', // Prefer local shards
'timeout' => '5s', // Request timeout
'terminate_after' => 10000, // Limit results
'track_total_hits' => false, // Skip total count for large results
'size' => 20, // Limit result size
'from' => 0 // Pagination offset
];
// Dynamic batch size based on system resources
private function optimizeBatchSize() {
$memory_limit = ini_get('memory_limit');
$memory_bytes = $this->parseMemoryLimit($memory_limit);
if ($memory_bytes < 256 * 1024 * 1024) { // Less than 256MB
return 100;
} elseif ($memory_bytes < 512 * 1024 * 1024) { // Less than 512MB
return 250;
} else {
return 500; // Default
}
}
// Optimize bulk requests
private function optimizeBulkRequest($documents) {
$bulk_body = [];
foreach ($documents as $doc) {
$bulk_body[] = [
'index' => [
'_index' => $this->index_name,
'_id' => $doc['id']
]
];
$bulk_body[] = $doc;
}
return $bulk_body;
}
// Optimize memory usage
ini_set('memory_limit', '512M');
set_time_limit(300);
// Garbage collection
gc_enable();
gc_collect_cycles();
// Memory monitoring
private function checkMemoryUsage() {
$memory_usage = memory_get_usage(true);
$memory_limit = ini_get('memory_limit');
$memory_limit_bytes = $this->parseMemoryLimit($memory_limit);
$usage_percentage = ($memory_usage / $memory_limit_bytes) * 100;
if ($usage_percentage > 80) {
$this->log("High memory usage: {$usage_percentage}%", 'WARNING');
gc_collect_cycles();
}
}
; php.ini optimizations
opcache.enable=1
opcache.memory_consumption=256
opcache.max_accelerated_files=10000
opcache.revalidate_freq=60
opcache.fast_shutdown=1
opcache.enable_cli=1
// Process data in chunks
private function processInChunks($items, $chunk_size, $processor) {
$chunks = array_chunk($items, $chunk_size);
$results = [];
foreach ($chunks as $chunk) {
$results = array_merge($results, $processor($chunk));
// Memory management
unset($chunk);
gc_collect_cycles();
}
return $results;
}
// Optimize array operations
private function optimizeArrayOperations($data) {
// Use array_column for better performance
$ids = array_column($data, 'id');
// Use array_combine for key-value pairs
$keyed_data = array_combine($ids, $data);
return $keyed_data;
}
// Cache search results
public function getCachedSearchResults($cache_key, $callback) {
$cached = wp_cache_get($cache_key, 'elasticsearch_search');
if ($cached === false) {
$cached = $callback();
wp_cache_set($cache_key, $cached, 'elasticsearch_search', 300); // 5 min cache
}
return $cached;
}
// Cache aggregations
public function getCachedAggregations($cache_key, $callback) {
$cached = wp_cache_get($cache_key, 'elasticsearch_aggregations');
if ($cached === false) {
$cached = $callback();
wp_cache_set($cache_key, $cached, 'elasticsearch_aggregations', 600); // 10 min cache
}
return $cached;
}
// Redis caching (if available)
class RedisCache {
private $redis;
public function __construct() {
if (class_exists('Redis')) {
$this->redis = new Redis();
$this->redis->connect('127.0.0.1', 6379);
}
}
public function get($key) {
if ($this->redis) {
$data = $this->redis->get($key);
return $data ? json_decode($data, true) : false;
}
return false;
}
public function set($key, $value, $ttl = 300) {
if ($this->redis) {
return $this->redis->setex($key, $ttl, json_encode($value));
}
return false;
}
}
// Cache database queries
private function getCachedQuery($query, $params, $ttl = 300) {
$cache_key = 'query_' . md5($query . serialize($params));
$cached = wp_cache_get($cache_key, 'database_queries');
if ($cached === false) {
$connection = $this->getDatabaseConnection();
$result = pg_query_params($connection, $query, $params);
$cached = pg_fetch_all($result);
wp_cache_set($cache_key, $cached, 'database_queries', $ttl);
}
return $cached;
}
; php-fpm.conf
pm = dynamic
pm.max_children = 50
pm.start_servers = 5
pm.min_spare_servers = 5
pm.max_spare_servers = 35
pm.max_requests = 1000
# Apache optimization
<IfModule mod_deflate.c>
AddOutputFilterByType DEFLATE text/plain
AddOutputFilterByType DEFLATE text/html
AddOutputFilterByType DEFLATE text/xml
AddOutputFilterByType DEFLATE text/css
AddOutputFilterByType DEFLATE application/xml
AddOutputFilterByType DEFLATE application/xhtml+xml
AddOutputFilterByType DEFLATE application/rss+xml
AddOutputFilterByType DEFLATE application/javascript
AddOutputFilterByType DEFLATE application/x-javascript
</IfModule>
# Enable KeepAlive
KeepAlive On
MaxKeepAliveRequests 100
KeepAliveTimeout 5
// Optimize cURL settings
private function optimizeCurlSettings($ch) {
curl_setopt_array($ch, [
CURLOPT_TIMEOUT => 30,
CURLOPT_CONNECTTIMEOUT => 10,
CURLOPT_HTTPHEADER => [
'Connection: close', // Don't keep connections alive
'Content-Type: application/json'
],
CURLOPT_TCP_NODELAY => true,
CURLOPT_TCP_FASTOPEN => true
]);
}
// Monitor response times
private function monitorResponseTime($operation, $callback) {
$start_time = microtime(true);
$result = $callback();
$end_time = microtime(true);
$duration = ($end_time - $start_time) * 1000; // Convert to milliseconds
$this->log("Operation '{$operation}' took {$duration}ms", 'INFO');
// Alert on slow operations
if ($duration > 1000) { // 1 second
$this->log("Slow operation detected: {$operation} took {$duration}ms", 'WARNING');
}
return $result;
}
// Monitor memory usage
private function monitorMemoryUsage($operation) {
$memory_usage = memory_get_usage(true);
$peak_memory = memory_get_peak_usage(true);
$this->log("Memory usage for '{$operation}': {$memory_usage} bytes (peak: {$peak_memory})", 'INFO');
// Alert on high memory usage
if ($memory_usage > 100 * 1024 * 1024) { // 100MB
$this->log("High memory usage detected: {$memory_usage} bytes", 'WARNING');
}
}
// Profile database queries
private function profileQuery($query, $params) {
$start_time = microtime(true);
$connection = $this->getDatabaseConnection();
$result = pg_query_params($connection, $query, $params);
$end_time = microtime(true);
$duration = ($end_time - $start_time) * 1000;
if ($duration > 100) { // 100ms
$this->log("Slow query detected: {$duration}ms - {$query}", 'WARNING');
}
return $result;
}
// Load test search functionality
public function loadTestSearch($iterations = 100) {
$queries = [
'smartphone',
'laptop',
'tablet',
'headphones',
'camera'
];
$total_time = 0;
$success_count = 0;
for ($i = 0; $i < $iterations; $i++) {
$query = $queries[array_rand($queries)];
$start_time = microtime(true);
try {
$results = $this->searchProducts($query);
$end_time = microtime(true);
$duration = ($end_time - $start_time) * 1000;
$total_time += $duration;
$success_count++;
if ($duration > 1000) {
$this->log("Slow search: {$query} took {$duration}ms", 'WARNING');
}
} catch (Exception $e) {
$this->log("Search failed: {$query} - {$e->getMessage()}", 'ERROR');
}
}
$avg_time = $total_time / $success_count;
$success_rate = ($success_count / $iterations) * 100;
$this->log("Load test results: {$success_count}/{$iterations} successful, avg time: {$avg_time}ms", 'INFO');
return [
'iterations' => $iterations,
'success_count' => $success_count,
'success_rate' => $success_rate,
'avg_response_time' => $avg_time
];
}
// Use appropriate data structures
private function optimizeDataStructures($data) {
// Use associative arrays for lookups
$lookup = array_flip(array_column($data, 'id'));
// Use generators for large datasets
function processLargeDataset($items) {
foreach ($items as $item) {
yield processItem($item);
}
}
// Use array functions efficiently
$filtered = array_filter($data, function($item) {
return $item['active'] === true;
});
}
// Process large datasets efficiently
private function processLargeDataset($items) {
$batch_size = 1000;
$processed = 0;
foreach (array_chunk($items, $batch_size) as $batch) {
$this->processBatch($batch);
$processed += count($batch);
// Memory management
unset($batch);
gc_collect_cycles();
// Progress logging
if ($processed % 10000 === 0) {
$this->log("Processed {$processed} items", 'INFO');
}
}
}
// Environment-specific optimization
private function getOptimizedSettings() {
$environment = getenv('APP_ENV') ?: 'production';
switch ($environment) {
case 'development':
return [
'batch_size' => 100,
'cache_ttl' => 60,
'log_level' => 'DEBUG'
];
case 'staging':
return [
'batch_size' => 250,
'cache_ttl' => 300,
'log_level' => 'INFO'
];
case 'production':
default:
return [
'batch_size' => 500,
'cache_ttl' => 600,
'log_level' => 'WARNING'
];
}
}
  • Response Time: < 100ms for 95% of queries
  • Throughput: > 100 queries/second
  • Error Rate: < 1%
  • Cache Hit Rate: > 80%
  • Processing Speed: > 1000 products/minute
  • Memory Usage: < 512MB
  • Error Rate: < 5%
  • Uptime: > 99.9%
  • CPU Usage: < 80%
  • Memory Usage: < 80%
  • Disk I/O: < 1000 IOPS
  • Network Latency: < 50ms
// Performance metrics collection
public function collectPerformanceMetrics() {
return [
'search' => [
'avg_response_time' => $this->getAverageSearchTime(),
'queries_per_second' => $this->getQueriesPerSecond(),
'error_rate' => $this->getSearchErrorRate(),
'cache_hit_rate' => $this->getCacheHitRate()
],
'sync' => [
'products_per_minute' => $this->getProductsPerMinute(),
'memory_usage' => $this->getMemoryUsage(),
'error_rate' => $this->getSyncErrorRate(),
'uptime' => $this->getUptime()
],
'system' => [
'cpu_usage' => $this->getCpuUsage(),
'memory_usage' => $this->getSystemMemoryUsage(),
'disk_io' => $this->getDiskIO(),
'network_latency' => $this->getNetworkLatency()
]
];
}