More fixes

This commit is contained in:
root
2025-06-08 12:01:14 +00:00
parent 43031a1aa4
commit d0b0346016
22 changed files with 7187 additions and 8 deletions

View File

@@ -0,0 +1,683 @@
<?php
// Security headers
header('X-Content-Type-Options: nosniff');
header('X-Frame-Options: DENY');
header('X-XSS-Protection: 1; mode=block');
header('Referrer-Policy: strict-origin-when-cross-origin');
header('Content-Security-Policy: default-src \'self\'; script-src \'self\' \'unsafe-inline\' https://www.googletagmanager.com; style-src \'self\' \'unsafe-inline\' https://fonts.googleapis.com; font-src \'self\' https://fonts.gstatic.com; img-src \'self\' data: https:; connect-src \'self\' https://www.google-analytics.com;');
// Article-specific variables
$article_title = 'Database Optimisation for Big Data: Advanced Techniques and Architecture';
$article_description = 'Master database optimisation for big data workloads. Comprehensive guide to indexing, partitioning, query optimisation, and distributed database architecture.';
$article_keywords = 'database optimisation, big data, query performance, indexing strategies, partitioning, distributed databases, NoSQL, SQL tuning';
$article_author = 'Database Team';
$article_date = '2024-06-07';
$last_modified = '2024-06-07';
$article_slug = 'database-optimization-big-data';
$article_category = 'Technology';
$hero_image = '/assets/images/hero-data-analytics.svg';
// Breadcrumb navigation
$breadcrumbs = [
['url' => '/', 'label' => 'Home'],
['url' => '/blog', 'label' => 'Blog'],
['url' => '/blog/categories/technology.php', 'label' => 'Technology'],
['url' => '', 'label' => 'Database Optimisation for Big Data']
];
?>
<!DOCTYPE html>
<html lang="en-GB">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title><?php echo htmlspecialchars($article_title); ?> | UK Data Services Blog</title>
<meta name="description" content="<?php echo htmlspecialchars($article_description); ?>">
<meta name="keywords" content="<?php echo htmlspecialchars($article_keywords); ?>">
<meta name="author" content="<?php echo htmlspecialchars($article_author); ?>">
<meta property="og:title" content="<?php echo htmlspecialchars($article_title); ?>">
<meta property="og:description" content="<?php echo htmlspecialchars($article_description); ?>">
<meta property="og:type" content="article">
<meta property="og:url" content="https://www.ukdataservices.com/blog/articles/<?php echo $article_slug; ?>">
<meta property="og:image" content="https://www.ukdataservices.com<?php echo $hero_image; ?>">
<meta property="article:author" content="<?php echo htmlspecialchars($article_author); ?>">
<meta property="article:published_time" content="<?php echo $article_date; ?>T09:00:00+00:00">
<meta property="article:modified_time" content="<?php echo $last_modified; ?>T09:00:00+00:00">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="<?php echo htmlspecialchars($article_title); ?>">
<meta name="twitter:description" content="<?php echo htmlspecialchars($article_description); ?>">
<meta name="twitter:image" content="https://www.ukdataservices.com<?php echo $hero_image; ?>">
<link rel="canonical" href="https://www.ukdataservices.com/blog/articles/<?php echo $article_slug; ?>">
<link rel="stylesheet" href="/assets/css/main.css">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
<?php include($_SERVER['DOCUMENT_ROOT'] . '/add_inline_css.php'); ?>
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "BlogPosting",
"headline": "<?php echo htmlspecialchars($article_title); ?>",
"description": "<?php echo htmlspecialchars($article_description); ?>",
"image": "https://www.ukdataservices.com<?php echo $hero_image; ?>",
"datePublished": "<?php echo $article_date; ?>T09:00:00+00:00",
"dateModified": "<?php echo $last_modified; ?>T09:00:00+00:00",
"author": {
"@type": "Person",
"name": "<?php echo htmlspecialchars($article_author); ?>"
},
"publisher": {
"@type": "Organization",
"name": "UK Data Services",
"logo": {
"@type": "ImageObject",
"url": "https://www.ukdataservices.com/assets/images/logo.svg"
}
},
"mainEntityOfPage": {
"@type": "WebPage",
"@id": "https://www.ukdataservices.com/blog/articles/<?php echo $article_slug; ?>"
},
"keywords": "<?php echo htmlspecialchars($article_keywords); ?>"
}
</script>
</head>
<body>
<?php include($_SERVER['DOCUMENT_ROOT'] . '/includes/header.php'); ?>
<article class="blog-article">
<div class="container">
<!-- Breadcrumb Navigation -->
<nav class="breadcrumb" aria-label="Breadcrumb">
<ol>
<?php foreach ($breadcrumbs as $index => $crumb): ?>
<?php if ($crumb['url']): ?>
<li><a href="<?php echo $crumb['url']; ?>"><?php echo htmlspecialchars($crumb['label']); ?></a></li>
<?php else: ?>
<li class="active" aria-current="page"><?php echo htmlspecialchars($crumb['label']); ?></li>
<?php endif; ?>
<?php endforeach; ?>
</ol>
</nav>
<header class="article-header">
<div class="article-meta">
<span class="article-category"><?php echo htmlspecialchars($article_category); ?></span>
<span class="article-date"><?php echo date('d F Y', strtotime($article_date)); ?></span>
<span class="article-author">By <?php echo htmlspecialchars($article_author); ?></span>
</div>
<h1><?php echo htmlspecialchars($article_title); ?></h1>
<p class="article-lead"><?php echo htmlspecialchars($article_description); ?></p>
</header>
<div class="article-content">
<section>
<h2>The Big Data Database Challenge</h2>
<p>As data volumes continue to grow exponentially, traditional database optimisation techniques often fall short of the performance requirements needed for big data workloads. Modern organisations are processing petabytes of information, serving millions of concurrent users, and requiring sub-second response times for complex analytical queries.</p>
<p>The scale of the challenge is substantial:</p>
<ul>
<li><strong>Data Volume:</strong> Organisations managing datasets exceeding 100TB regularly</li>
<li><strong>Query Complexity:</strong> Analytical queries spanning billions of records with complex joins</li>
<li><strong>Concurrent Users:</strong> Systems serving thousands of simultaneous database connections</li>
<li><strong>Real-Time Requirements:</strong> Sub-second response times for time-sensitive applications</li>
<li><strong>Cost Constraints:</strong> Optimising performance while controlling infrastructure costs</li>
</ul>
<p>This guide explores advanced optimisation techniques that enable databases to handle big data workloads efficiently, from fundamental indexing strategies to cutting-edge distributed architectures.</p>
</section>
<section>
<h2>Advanced Indexing Strategies</h2>
<h3>Columnar Indexing</h3>
<p>Columnar indexes are particularly effective for analytical workloads that access specific columns across large datasets:</p>
<pre><code class="language-sql">
-- PostgreSQL columnar index example
CREATE INDEX CONCURRENTLY idx_sales_date_column
ON sales_data
USING BRIN (sale_date, region_id);
-- This index is highly efficient for range queries
SELECT SUM(amount)
FROM sales_data
WHERE sale_date BETWEEN '2024-01-01' AND '2024-12-31'
AND region_id IN (1, 2, 3);
</code></pre>
<h3>Partial Indexing</h3>
<p>Partial indexes reduce storage overhead and improve performance by indexing only relevant subset of data:</p>
<pre><code class="language-sql">
-- Index only active records to improve performance
CREATE INDEX idx_active_customers
ON customers (customer_id, last_activity_date)
WHERE status = 'active' AND last_activity_date > '2023-01-01';
-- Separate indexes for different query patterns
CREATE INDEX idx_high_value_transactions
ON transactions (transaction_date, amount)
WHERE amount > 1000;
</code></pre>
<h3>Expression and Functional Indexes</h3>
<p>Indexes on computed expressions can dramatically improve performance for complex queries:</p>
<pre><code class="language-sql">
-- Index on computed expression
CREATE INDEX idx_customer_full_name
ON customers (LOWER(first_name || ' ' || last_name));
-- Index on date extraction
CREATE INDEX idx_order_year_month
ON orders (EXTRACT(YEAR FROM order_date), EXTRACT(MONTH FROM order_date));
-- Enables efficient queries like:
SELECT * FROM orders
WHERE EXTRACT(YEAR FROM order_date) = 2024
AND EXTRACT(MONTH FROM order_date) = 6;
</code></pre>
</section>
<section>
<h2>Table Partitioning Strategies</h2>
<h3>Horizontal Partitioning</h3>
<p>Distribute large tables across multiple physical partitions for improved query performance and maintenance:</p>
<pre><code class="language-sql">
-- Range partitioning by date
CREATE TABLE sales_data (
id BIGSERIAL,
sale_date DATE NOT NULL,
customer_id INTEGER,
amount DECIMAL(10,2),
product_id INTEGER
) PARTITION BY RANGE (sale_date);
-- Create monthly partitions
CREATE TABLE sales_2024_01 PARTITION OF sales_data
FOR VALUES FROM ('2024-01-01') TO ('2024-02-01');
CREATE TABLE sales_2024_02 PARTITION OF sales_data
FOR VALUES FROM ('2024-02-01') TO ('2024-03-01');
-- Hash partitioning for even distribution
CREATE TABLE user_activities (
id BIGSERIAL,
user_id INTEGER NOT NULL,
activity_type VARCHAR(50),
timestamp TIMESTAMP
) PARTITION BY HASH (user_id);
CREATE TABLE user_activities_0 PARTITION OF user_activities
FOR VALUES WITH (modulus 4, remainder 0);
</code></pre>
<h3>Partition Pruning Optimisation</h3>
<p>Ensure queries can eliminate irrelevant partitions for maximum performance:</p>
<pre><code class="language-sql">
-- Query that benefits from partition pruning
EXPLAIN (ANALYZE, BUFFERS)
SELECT customer_id, SUM(amount)
FROM sales_data
WHERE sale_date >= '2024-06-01'
AND sale_date < '2024-07-01'
GROUP BY customer_id;
-- Result shows only June partition accessed:
-- Partition constraint: ((sale_date >= '2024-06-01') AND (sale_date < '2024-07-01'))
</code></pre>
<h3>Automated Partition Management</h3>
<p>Implement automated partition creation and maintenance:</p>
<pre><code class="language-sql">
-- Function to automatically create monthly partitions
CREATE OR REPLACE FUNCTION create_monthly_partition(
table_name TEXT,
start_date DATE
) RETURNS VOID AS $$
DECLARE
partition_name TEXT;
end_date DATE;
BEGIN
partition_name := table_name || '_' || TO_CHAR(start_date, 'YYYY_MM');
end_date := start_date + INTERVAL '1 month';
EXECUTE format('CREATE TABLE %I PARTITION OF %I
FOR VALUES FROM (%L) TO (%L)',
partition_name, table_name, start_date, end_date);
END;
$$ LANGUAGE plpgsql;
</code></pre>
</section>
<section>
<h2>Query Optimisation Techniques</h2>
<h3>Advanced Query Analysis</h3>
<p>Use execution plan analysis to identify performance bottlenecks:</p>
<pre><code class="language-sql">
-- Detailed execution plan with timing and buffer information
EXPLAIN (ANALYZE, BUFFERS, FORMAT JSON)
SELECT
p.product_name,
SUM(s.amount) as total_sales,
COUNT(*) as transaction_count,
AVG(s.amount) as avg_transaction
FROM sales_data s
JOIN products p ON s.product_id = p.id
JOIN customers c ON s.customer_id = c.id
WHERE s.sale_date >= '2024-01-01'
AND c.segment = 'premium'
GROUP BY p.product_name
HAVING SUM(s.amount) > 10000
ORDER BY total_sales DESC;
</code></pre>
<h3>Join Optimisation</h3>
<p>Optimise complex joins for large datasets:</p>
<pre><code class="language-sql">
-- Use CTEs to break down complex queries
WITH premium_customers AS (
SELECT customer_id
FROM customers
WHERE segment = 'premium'
),
recent_sales AS (
SELECT product_id, customer_id, amount
FROM sales_data
WHERE sale_date >= '2024-01-01'
)
SELECT
p.product_name,
SUM(rs.amount) as total_sales
FROM recent_sales rs
JOIN premium_customers pc ON rs.customer_id = pc.customer_id
JOIN products p ON rs.product_id = p.id
GROUP BY p.product_name;
-- Alternative using window functions for better performance
SELECT DISTINCT
product_name,
SUM(amount) OVER (PARTITION BY product_id) as total_sales
FROM (
SELECT s.product_id, s.amount, p.product_name
FROM sales_data s
JOIN products p ON s.product_id = p.id
JOIN customers c ON s.customer_id = c.id
WHERE s.sale_date >= '2024-01-01'
AND c.segment = 'premium'
) subquery;
</code></pre>
<h3>Aggregation Optimisation</h3>
<p>Optimise grouping and aggregation operations:</p>
<pre><code class="language-sql">
-- Pre-aggregated materialized views for common queries
CREATE MATERIALIZED VIEW monthly_sales_summary AS
SELECT
DATE_TRUNC('month', sale_date) as sale_month,
product_id,
customer_segment,
SUM(amount) as total_amount,
COUNT(*) as transaction_count,
AVG(amount) as avg_amount
FROM sales_data s
JOIN customers c ON s.customer_id = c.id
GROUP BY DATE_TRUNC('month', sale_date), product_id, customer_segment;
-- Create index on materialized view
CREATE INDEX idx_monthly_summary_date_product
ON monthly_sales_summary (sale_month, product_id);
-- Refresh strategy
CREATE OR REPLACE FUNCTION refresh_monthly_summary()
RETURNS VOID AS $$
BEGIN
REFRESH MATERIALIZED VIEW CONCURRENTLY monthly_sales_summary;
END;
$$ LANGUAGE plpgsql;
</code></pre>
</section>
<section>
<h2>Distributed Database Architecture</h2>
<h3>Sharding Strategies</h3>
<p>Implement horizontal scaling through intelligent data distribution:</p>
<ul>
<li><strong>Range-based Sharding:</strong> Distribute data based on value ranges (e.g., date ranges, geographic regions)</li>
<li><strong>Hash-based Sharding:</strong> Use hash functions for even distribution across shards</li>
<li><strong>Directory-based Sharding:</strong> Maintain a lookup table for data location</li>
<li><strong>Composite Sharding:</strong> Combine multiple sharding strategies</li>
</ul>
<h3>Master-Slave Replication</h3>
<p>Configure read replicas for scaling read-heavy workloads:</p>
<pre><code class="language-sql">
-- PostgreSQL streaming replication configuration
-- Primary server postgresql.conf
wal_level = replica
max_wal_senders = 3
wal_keep_segments = 64
archive_mode = on
archive_command = 'cp %p /archive/%f'
-- Replica server recovery.conf
standby_mode = 'on'
primary_conninfo = 'host=primary-server port=5432 user=replicator'
trigger_file = '/tmp/postgresql.trigger'
</code></pre>
<h3>Connection Pooling</h3>
<p>Implement efficient connection management for high-concurrency environments:</p>
<pre><code class="language-ini">
; PgBouncer configuration for connection pooling
[databases]
production = host=db-cluster port=5432 dbname=production_db
[pgbouncer]
listen_port = 6432
listen_addr = *
auth_type = md5
auth_file = userlist.txt
pool_mode = transaction
max_client_conn = 1000
default_pool_size = 25
max_db_connections = 100
reserve_pool_size = 5
server_reset_query = DISCARD ALL
</code></pre>
</section>
<section>
<h2>NoSQL Optimisation Strategies</h2>
<h3>MongoDB Optimisation</h3>
<p>Optimise document databases for big data workloads:</p>
<pre><code class="language-javascript">
// Compound indexes for complex queries
db.users.createIndex({
"location.country": 1,
"age": 1,
"lastLogin": -1
});
// Aggregation pipeline optimisation
db.sales.aggregate([
// Use $match early to reduce dataset
{ $match: {
date: { $gte: ISODate("2024-01-01") },
status: "completed"
}},
// Use $project to reduce data transfer
{ $project: {
amount: 1,
productId: 1,
customerId: 1
}},
{ $group: {
_id: "$productId",
totalSales: { $sum: "$amount" },
customerCount: { $addToSet: "$customerId" }
}},
{ $addFields: {
uniqueCustomers: { $size: "$customerCount" }
}},
{ $sort: { totalSales: -1 }},
{ $limit: 100 }
]);
</code></pre>
<h3>Cassandra Optimisation</h3>
<p>Design efficient data models for distributed columnar databases:</p>
<pre><code class="language-sql">
-- Partition key design for even distribution
CREATE TABLE user_activities (
user_id UUID,
activity_date DATE,
activity_time TIMESTAMP,
activity_type TEXT,
details MAP<TEXT, TEXT>,
PRIMARY KEY ((user_id, activity_date), activity_time)
) WITH CLUSTERING ORDER BY (activity_time DESC);
-- Materialized view for different query patterns
CREATE MATERIALIZED VIEW activities_by_type AS
SELECT user_id, activity_date, activity_time, activity_type, details
FROM user_activities
WHERE activity_type IS NOT NULL
PRIMARY KEY ((activity_type, activity_date), activity_time, user_id);
</code></pre>
<h3>Redis Optimisation</h3>
<p>Optimise in-memory data structures for caching and real-time analytics:</p>
<pre><code class="language-python">
import redis
from datetime import datetime, timedelta
# Redis connection with optimisation
r = redis.Redis(
host='redis-cluster',
port=6379,
decode_responses=True,
max_connections=100,
socket_connect_timeout=5,
socket_timeout=5
)
# Efficient batch operations
pipe = r.pipeline()
for i in range(1000):
pipe.hset(f"user:{i}", mapping={
"name": f"User {i}",
"last_login": datetime.now().isoformat(),
"score": i * 10
})
pipe.execute()
# Memory-efficient data structures
# Use sorted sets for leaderboards
r.zadd("leaderboard", {"user1": 1000, "user2": 2000, "user3": 1500})
top_users = r.zrevrange("leaderboard", 0, 9, withscores=True)
# Use HyperLogLog for cardinality estimation
r.pfadd("unique_visitors", "user1", "user2", "user3")
unique_count = r.pfcount("unique_visitors")
</code></pre>
</section>
<section>
<h2>Performance Monitoring and Tuning</h2>
<h3>Database Metrics Collection</h3>
<p>Implement comprehensive monitoring for proactive performance management:</p>
<pre><code class="language-sql">
-- PostgreSQL performance monitoring queries
-- Long-running queries
SELECT
pid,
now() - pg_stat_activity.query_start AS duration,
query,
state
FROM pg_stat_activity
WHERE (now() - pg_stat_activity.query_start) > interval '5 minutes'
AND state = 'active'
ORDER BY duration DESC;
-- Index usage statistics
SELECT
schemaname,
tablename,
indexname,
idx_tup_read,
idx_tup_fetch,
idx_scan
FROM pg_stat_user_indexes
WHERE idx_scan = 0
ORDER BY schemaname, tablename;
-- Table bloat analysis
SELECT
schemaname,
tablename,
n_dead_tup,
n_live_tup,
ROUND(n_dead_tup::float / (n_live_tup + n_dead_tup + 1) * 100, 2) AS bloat_percentage
FROM pg_stat_user_tables
WHERE n_dead_tup > 1000
ORDER BY bloat_percentage DESC;
</code></pre>
<h3>Automated Performance Tuning</h3>
<p>Implement automated tuning for dynamic workloads:</p>
<pre><code class="language-python">
import psycopg2
import psutil
from datetime import datetime
class DatabaseTuner:
def __init__(self, connection_string):
self.conn = psycopg2.connect(connection_string)
def analyze_slow_queries(self):
"""Identify and analyze slow queries"""
with self.conn.cursor() as cur:
cur.execute("""
SELECT query, calls, total_time, mean_time, stddev_time
FROM pg_stat_statements
WHERE mean_time > 1000
ORDER BY total_time DESC
LIMIT 10
""")
return cur.fetchall()
def suggest_indexes(self):
"""Suggest missing indexes based on query patterns"""
with self.conn.cursor() as cur:
cur.execute("""
SELECT schemaname, tablename, attname, n_distinct, correlation
FROM pg_stats
WHERE schemaname = 'public'
AND n_distinct > 100
AND correlation < 0.1
""")
return cur.fetchall()
def auto_vacuum_tuning(self):
"""Adjust autovacuum settings based on table activity"""
system_memory = psutil.virtual_memory().total
maintenance_work_mem = min(2 * 1024**3, system_memory // 16) # 2GB or 1/16 of RAM
with self.conn.cursor() as cur:
cur.execute(f"""
ALTER SYSTEM SET maintenance_work_mem = '{maintenance_work_mem // 1024**2}MB';
SELECT pg_reload_conf();
""")
</code></pre>
<h3>Capacity Planning</h3>
<p>Predict and plan for future performance requirements:</p>
<ul>
<li><strong>Growth Trend Analysis:</strong> Track data growth patterns and query complexity evolution</li>
<li><strong>Resource Utilisation Monitoring:</strong> CPU, memory, disk I/O, and network usage patterns</li>
<li><strong>Performance Baseline Establishment:</strong> Document acceptable performance thresholds</li>
<li><strong>Scalability Testing:</strong> Regular load testing to identify breaking points</li>
</ul>
</section>
<section>
<h2>Cloud Database Optimisation</h2>
<h3>AWS RDS Optimisation</h3>
<p>Leverage cloud-specific features for enhanced performance:</p>
<ul>
<li><strong>Read Replicas:</strong> Scale read operations across multiple instances</li>
<li><strong>Aurora Global Database:</strong> Global distribution for low-latency access</li>
<li><strong>Performance Insights:</strong> Built-in monitoring and tuning recommendations</li>
<li><strong>Automated Backups:</strong> Point-in-time recovery with minimal performance impact</li>
</ul>
<h3>Google Cloud SQL Optimisation</h3>
<ul>
<li><strong>High Availability:</strong> Automatic failover with regional persistent disks</li>
<li><strong>Query Insights:</strong> Intelligent query performance analysis</li>
<li><strong>Connection Pooling:</strong> Built-in connection management</li>
<li><strong>Automatic Storage Scaling:</strong> Dynamic storage expansion</li>
</ul>
<h3>Azure Database Optimisation</h3>
<ul>
<li><strong>Intelligent Performance:</strong> AI-powered performance tuning</li>
<li><strong>Hyperscale:</strong> Elastic scaling for large databases</li>
<li><strong>Query Store:</strong> Historical query performance tracking</li>
<li><strong>Automatic Tuning:</strong> Machine learning-based optimisation</li>
</ul>
</section>
<section>
<h2>Emerging Technologies and Trends</h2>
<h3>NewSQL Databases</h3>
<p>Modern databases combining ACID compliance with horizontal scalability:</p>
<ul>
<li><strong>CockroachDB:</strong> Distributed SQL with automatic sharding</li>
<li><strong>TiDB:</strong> Hybrid transactional and analytical processing</li>
<li><strong>YugabyteDB:</strong> Multi-cloud distributed SQL</li>
<li><strong>FaunaDB:</strong> Serverless, globally distributed database</li>
</ul>
<h3>In-Memory Computing</h3>
<p>Ultra-fast data processing using RAM-based storage:</p>
<ul>
<li><strong>SAP HANA:</strong> In-memory analytics platform</li>
<li><strong>Apache Ignite:</strong> Distributed in-memory computing platform</li>
<li><strong>Redis Enterprise:</strong> Multi-model in-memory database</li>
<li><strong>MemSQL (SingleStore):</strong> Real-time analytics database</li>
</ul>
<h3>Serverless Databases</h3>
<p>Auto-scaling databases with pay-per-use pricing:</p>
<ul>
<li><strong>Aurora Serverless:</strong> On-demand PostgreSQL and MySQL</li>
<li><strong>Azure SQL Database Serverless:</strong> Automatic scaling SQL database</li>
<li><strong>PlanetScale:</strong> Serverless MySQL platform</li>
<li><strong>FaunaDB:</strong> Serverless, ACID-compliant database</li>
</ul>
</section>
<section class="article-cta">
<h2>Expert Database Optimisation Services</h2>
<p>Optimising databases for big data requires deep expertise in query performance, distributed systems, and advanced database technologies. UK Data Services provides comprehensive database optimisation consulting, from performance audits to complete architecture redesign, helping organisations achieve optimal performance at scale.</p>
<a href="/contact" class="cta-button">Optimise Your Database</a>
</section>
</div>
<?php include($_SERVER['DOCUMENT_ROOT'] . '/includes/article-footer.php'); ?>
</div>
</article>
<?php include($_SERVER['DOCUMENT_ROOT'] . '/includes/footer.php'); ?>
<script src="/assets/js/main.js" defer></script>
</body>
</html>