Learn to configure automated data retention policies in TimescaleDB for efficient storage management. Set up compression, continuous aggregates, and automated data lifecycle policies to optimize time-series database performance and reduce storage costs.
Prerequisites
- Root or sudo access
- At least 4GB RAM
- PostgreSQL 12+ compatible system
What this solves
TimescaleDB data retention policies automatically manage your time-series data lifecycle by dropping old data, compressing chunks, and maintaining continuous aggregates. This prevents storage bloat, reduces query costs, and maintains database performance as your time-series data grows. You'll implement automated retention rules that keep recent data accessible while compressing or removing historical data based on your business requirements.
Step-by-step configuration
Update system packages
Start by updating your package manager to ensure you have the latest PostgreSQL and system packages available.
sudo apt update && sudo apt upgrade -y
sudo apt install -y wget ca-certificates
sudo dnf update -y
sudo dnf install -y wget ca-certificates
Install PostgreSQL 16
TimescaleDB requires PostgreSQL 12 or higher. Install PostgreSQL 16 for the best performance and feature compatibility.
sudo sh -c 'echo "deb http://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list'
wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add -
sudo apt update
sudo apt install -y postgresql-16 postgresql-client-16 postgresql-contrib-16
sudo dnf install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-9-x86_64/pgdg-redhat-repo-latest.noarch.rpm
sudo dnf install -y postgresql16-server postgresql16-contrib
sudo /usr/pgsql-16/bin/postgresql-16-setup initdb
Start and enable PostgreSQL
Enable PostgreSQL to start on boot and start the service immediately.
sudo systemctl enable --now postgresql
sudo systemctl status postgresql
sudo systemctl enable --now postgresql-16
sudo systemctl status postgresql-16
Install TimescaleDB
Add the TimescaleDB repository and install the extension for PostgreSQL 16.
echo "deb https://packagecloud.io/timescale/timescaledb/ubuntu/ $(lsb_release -c -s) main" | sudo tee /etc/apt/sources.list.d/timescaledb.list
wget --quiet -O - https://packagecloud.io/timescale/timescaledb/gpgkey | sudo apt-key add -
sudo apt update
sudo apt install -y timescaledb-2-postgresql-16
sudo tee /etc/yum.repos.d/timescale_timescaledb.repo <
Configure PostgreSQL for TimescaleDB
Run the timescaledb-tune utility to optimize PostgreSQL configuration for time-series workloads.
sudo timescaledb-tune --quiet --yes
Restart PostgreSQL
Restart PostgreSQL to apply the TimescaleDB configuration changes.
sudo systemctl restart postgresql
sudo systemctl restart postgresql-16
Create a database and enable TimescaleDB
Create a new database for time-series data and enable the TimescaleDB extension.
sudo -u postgres createdb metrics_db
sudo -u postgres psql -d metrics_db -c "CREATE EXTENSION IF NOT EXISTS timescaledb;"
Create a sample time-series table
Create a hypertable to demonstrate retention policies with sensor data.
sudo -u postgres psql -d metrics_db << 'EOF'
CREATE TABLE sensor_data (
time TIMESTAMPTZ NOT NULL,
sensor_id INTEGER NOT NULL,
temperature DOUBLE PRECISION,
humidity DOUBLE PRECISION,
location TEXT
);
SELECT create_hypertable('sensor_data', 'time');
EOF
Insert sample data
Add sample time-series data spanning several months to test retention policies.
sudo -u postgres psql -d metrics_db << 'EOF'
INSERT INTO sensor_data (time, sensor_id, temperature, humidity, location)
SELECT
generate_series(NOW() - INTERVAL '6 months', NOW(), INTERVAL '1 hour') AS time,
(random() * 10 + 1)::INTEGER AS sensor_id,
(random() * 30 + 20) AS temperature,
(random() * 40 + 40) AS humidity,
'Building-' || (random() * 5 + 1)::INTEGER AS location;
EOF
Configure data retention policies
Create a basic retention policy
Set up a retention policy to automatically drop data older than 3 months.
sudo -u postgres psql -d metrics_db -c "
SELECT add_retention_policy('sensor_data', INTERVAL '3 months');
"
Enable compression
Enable compression for chunks older than 7 days to reduce storage usage while maintaining data accessibility.
sudo -u postgres psql -d metrics_db << 'EOF'
ALTER TABLE sensor_data SET (
timescaledb.compress,
timescaledb.compress_segmentby = 'sensor_id',
timescaledb.compress_orderby = 'time DESC'
);
SELECT add_compression_policy('sensor_data', INTERVAL '7 days');
EOF
Create continuous aggregates
Set up continuous aggregates for efficient querying of historical data with automatic refresh policies.
sudo -u postgres psql -d metrics_db << 'EOF'
CREATE MATERIALIZED VIEW sensor_data_hourly
WITH (timescaledb.continuous) AS
SELECT
time_bucket('1 hour', time) AS bucket,
sensor_id,
location,
AVG(temperature) AS avg_temperature,
AVG(humidity) AS avg_humidity,
MIN(temperature) AS min_temperature,
MAX(temperature) AS max_temperature
FROM sensor_data
GROUP BY bucket, sensor_id, location;
CREATE MATERIALIZED VIEW sensor_data_daily
WITH (timescaledb.continuous) AS
SELECT
time_bucket('1 day', time) AS bucket,
sensor_id,
location,
AVG(temperature) AS avg_temperature,
AVG(humidity) AS avg_humidity,
MIN(temperature) AS min_temperature,
MAX(temperature) AS max_temperature
FROM sensor_data
GROUP BY bucket, sensor_id, location;
EOF
Configure continuous aggregate refresh policies
Add refresh policies to keep continuous aggregates up to date automatically.
sudo -u postgres psql -d metrics_db << 'EOF'
SELECT add_continuous_aggregate_policy('sensor_data_hourly',
start_offset => INTERVAL '3 hours',
end_offset => INTERVAL '1 hour',
schedule_interval => INTERVAL '1 hour');
SELECT add_continuous_aggregate_policy('sensor_data_daily',
start_offset => INTERVAL '3 days',
end_offset => INTERVAL '1 day',
schedule_interval => INTERVAL '1 day');
EOF
Set up retention for continuous aggregates
Configure retention policies for the continuous aggregates to manage their lifecycle independently.
sudo -u postgres psql -d metrics_db << 'EOF'
SELECT add_retention_policy('sensor_data_hourly', INTERVAL '1 year');
SELECT add_retention_policy('sensor_data_daily', INTERVAL '3 years');
EOF
Monitor and optimize retention performance
Check compression status
Monitor which chunks are compressed and their compression ratios to optimize storage.
sudo -u postgres psql -d metrics_db -c "
SELECT
chunk_schema,
chunk_name,
compression_status,
before_compression_total_bytes,
after_compression_total_bytes,
ROUND(100 - (after_compression_total_bytes::float / before_compression_total_bytes::float * 100), 2) AS compression_ratio_percent
FROM chunk_compression_stats('sensor_data')
ORDER BY chunk_name;
"
View retention policy status
Check all active retention and compression policies to ensure they're running as expected.
sudo -u postgres psql -d metrics_db -c "
SELECT
application_name,
schedule_interval,
max_runtime,
max_retries,
retry_period
FROM timescaledb_information.jobs
WHERE proc_name IN ('policy_retention', 'policy_compression', 'policy_refresh_continuous_aggregate');
"
Monitor job execution history
Review the execution history of retention and compression jobs to identify any failures or performance issues.
sudo -u postgres psql -d metrics_db -c "
SELECT
job_id,
start_time,
finish_time,
success,
error_message
FROM timescaledb_information.job_stats
ORDER BY start_time DESC
LIMIT 20;
"
Configure job scheduling
Adjust the schedule for retention and compression jobs to run during low-traffic periods.
sudo -u postgres psql -d metrics_db << 'EOF'
-- Run retention policy daily at 2 AM
SELECT alter_job(
(SELECT job_id FROM timescaledb_information.jobs WHERE proc_name = 'policy_retention' AND hypertable_name = 'sensor_data'),
schedule_interval => INTERVAL '1 day',
max_runtime => INTERVAL '1 hour'
);
-- Run compression policy every 6 hours
SELECT alter_job(
(SELECT job_id FROM timescaledb_information.jobs WHERE proc_name = 'policy_compression' AND hypertable_name = 'sensor_data'),
schedule_interval => INTERVAL '6 hours',
max_runtime => INTERVAL '2 hours'
);
EOF
Create monitoring views
Set up monitoring views to track storage usage and policy effectiveness over time.
sudo -u postgres psql -d metrics_db << 'EOF'
CREATE OR REPLACE VIEW storage_stats AS
SELECT
hypertable_name,
total_size_bytes,
pg_size_pretty(total_size_bytes) AS total_size,
compressed_heap_size_bytes,
pg_size_pretty(compressed_heap_size_bytes) AS compressed_size,
CASE
WHEN total_size_bytes > 0 THEN
ROUND(100 - (compressed_heap_size_bytes::float / total_size_bytes::float * 100), 2)
ELSE 0
END AS compression_ratio_percent
FROM hypertable_detailed_size('sensor_data');
CREATE OR REPLACE VIEW chunk_status AS
SELECT
chunk_name,
range_start,
range_end,
is_compressed,
compressed_heap_size,
pg_size_pretty(compressed_heap_size) AS compressed_size
FROM timescaledb_information.chunks
WHERE hypertable_name = 'sensor_data'
ORDER BY range_start DESC;
EOF
Advanced retention configurations
Create conditional retention policies
Set up more complex retention rules based on data characteristics using custom functions.
sudo -u postgres psql -d metrics_db << 'EOF'
-- Create function for conditional retention based on sensor importance
CREATE OR REPLACE FUNCTION conditional_retention_policy()
RETURNS VOID AS $$
DECLAREBEGIN
-- Keep critical sensor data (sensor_id 1-3) for 1 year
-- Keep normal sensor data for 3 months
DELETE FROM sensor_data
WHERE time < NOW() - INTERVAL '1 year'
AND sensor_id IN (1, 2, 3);
DELETE FROM sensor_data
WHERE time < NOW() - INTERVAL '3 months'
AND sensor_id NOT IN (1, 2, 3);
END;
$$ LANGUAGE plpgsql;
-- Schedule the custom retention policy
SELECT add_job('conditional_retention_policy', '1 day');
EOF
Configure alerting for retention policies
Create a function to monitor retention policy execution and alert on failures.
sudo -u postgres psql -d metrics_db << 'EOF'
CREATE OR REPLACE FUNCTION check_retention_health()
RETURNS TABLE(job_name TEXT, last_success TIMESTAMPTZ, status TEXT) AS $$
BEGIN
RETURN QUERY
SELECT
j.application_name::TEXT,
js.last_successful_finish,
CASE
WHEN js.last_successful_finish < NOW() - INTERVAL '2 days' THEN 'STALE'
WHEN js.consecutive_failures > 3 THEN 'FAILING'
ELSE 'OK'
END::TEXT
FROM timescaledb_information.jobs j
JOIN timescaledb_information.job_stats js ON j.job_id = js.job_id
WHERE j.proc_name IN ('policy_retention', 'policy_compression');
END;
$$ LANGUAGE plpgsql;
EOF
Verify your setup
Check that your retention policies are working correctly and data is being managed as expected.
sudo -u postgres psql -d metrics_db -c "SELECT * FROM storage_stats;"
sudo -u postgres psql -d metrics_db -c "SELECT * FROM chunk_status LIMIT 10;"
sudo -u postgres psql -d metrics_db -c "SELECT * FROM check_retention_health();"
sudo -u postgres psql -d metrics_db -c "SELECT COUNT(*) AS total_records FROM sensor_data;"
sudo -u postgres psql -d metrics_db -c "SELECT COUNT(*) AS compressed_chunks FROM timescaledb_information.chunks WHERE is_compressed = true AND hypertable_name = 'sensor_data';"
Common issues
Symptom Cause Fix
Retention policy not executing Background worker not running SELECT timescaledb_pre_restore(); then restart PostgreSQL
Compression failing Active transactions on chunks Wait for transactions to complete or restart PostgreSQL
High storage usage despite retention VACUUM not running after deletion VACUUM ANALYZE sensor_data;
Continuous aggregate not refreshing Policy disabled or failing Check job status: SELECT * FROM timescaledb_information.job_stats;
Query performance degraded Missing indexes on compressed chunks Add indexes before enabling compression
Extension not loading Missing shared_preload_libraries Add 'timescaledb' to postgresql.conf and restart
Next steps
- Configure TimescaleDB backup and recovery with pgBackRest for automated PostgreSQL protection
- Configure Grafana dashboards for TimescaleDB analytics with real-time metrics and alerting
- Set up TimescaleDB high availability with streaming replication and automatic failover
- Configure TimescaleDB multi-node clustering for distributed time-series workloads
- Implement TimescaleDB advanced compression strategies for optimal storage efficiency
Running this in production?
Want this handled for you? Setting up TimescaleDB retention policies once is straightforward. Keeping them monitored, tuned, and integrated with backup strategies across environments is the harder part. See how we run infrastructure like this for European SaaS and analytics teams.
Automated install script
Run this to automate the entire setup
#!/usr/bin/env bash
set -euo pipefail
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Global variables
TOTAL_STEPS=8
DB_NAME="${1:-timeseries_db}"
DB_USER="${2:-tsdb_user}"
DB_PASSWORD=""
POSTGRES_VERSION="16"
# Error handling
cleanup() {
echo -e "${RED}[ERROR] Installation failed. Cleaning up...${NC}"
if systemctl is-active --quiet postgresql 2>/dev/null || systemctl is-active --quiet postgresql-${POSTGRES_VERSION} 2>/dev/null; then
echo "PostgreSQL service is running, leaving it as is for manual inspection"
fi
}
trap cleanup ERR
usage() {
echo "Usage: $0 [database_name] [database_user]"
echo " database_name: Name of the TimescaleDB database (default: timeseries_db)"
echo " database_user: Database user for TimescaleDB (default: tsdb_user)"
echo "Example: $0 mytsdb myuser"
exit 1
}
# Check if help is requested
if [[ "${1:-}" == "-h" ]] || [[ "${1:-}" == "--help" ]]; then
usage
fi
# Check prerequisites
if [[ $EUID -ne 0 ]]; then
echo -e "${RED}[ERROR] This script must be run as root or with sudo${NC}"
exit 1
fi
# Auto-detect distribution
if [[ ! -f /etc/os-release ]]; then
echo -e "${RED}[ERROR] Cannot detect Linux distribution${NC}"
exit 1
fi
source /etc/os-release
case "$ID" in
ubuntu|debian)
PKG_MGR="apt"
PKG_UPDATE="apt update"
PKG_INSTALL="apt install -y"
PKG_UPGRADE="apt upgrade -y"
PG_SERVICE="postgresql"
PG_CONFIG_DIR="/etc/postgresql/${POSTGRES_VERSION}/main"
PG_DATA_DIR="/var/lib/postgresql/${POSTGRES_VERSION}/main"
;;
almalinux|rocky|centos|rhel|ol)
PKG_MGR="dnf"
PKG_UPDATE="dnf update -y"
PKG_INSTALL="dnf install -y"
PKG_UPGRADE="dnf update -y"
PG_SERVICE="postgresql-${POSTGRES_VERSION}"
PG_CONFIG_DIR="/var/lib/pgsql/${POSTGRES_VERSION}/data"
PG_DATA_DIR="/var/lib/pgsql/${POSTGRES_VERSION}/data"
;;
amzn)
PKG_MGR="yum"
PKG_UPDATE="yum update -y"
PKG_INSTALL="yum install -y"
PKG_UPGRADE="yum update -y"
PG_SERVICE="postgresql-${POSTGRES_VERSION}"
PG_CONFIG_DIR="/var/lib/pgsql/${POSTGRES_VERSION}/data"
PG_DATA_DIR="/var/lib/pgsql/${POSTGRES_VERSION}/data"
;;
fedora)
PKG_MGR="dnf"
PKG_UPDATE="dnf update -y"
PKG_INSTALL="dnf install -y"
PKG_UPGRADE="dnf update -y"
PG_SERVICE="postgresql"
PG_CONFIG_DIR="/var/lib/pgsql/data"
PG_DATA_DIR="/var/lib/pgsql/data"
;;
*)
echo -e "${RED}[ERROR] Unsupported distribution: $ID${NC}"
exit 1
;;
esac
echo -e "${BLUE}[INFO] Detected distribution: $PRETTY_NAME${NC}"
echo -e "${BLUE}[INFO] Using package manager: $PKG_MGR${NC}"
# Generate random password
DB_PASSWORD=$(openssl rand -base64 32 | tr -d "=+/" | cut -c1-25)
echo -e "${GREEN}[1/$TOTAL_STEPS] Updating system packages...${NC}"
$PKG_UPDATE
$PKG_INSTALL wget ca-certificates curl gnupg lsb-release openssl
echo -e "${GREEN}[2/$TOTAL_STEPS] Adding PostgreSQL repository...${NC}"
case "$ID" in
ubuntu|debian)
curl -fsSL https://www.postgresql.org/media/keys/ACCC4CF8.asc | gpg --dearmor -o /usr/share/keyrings/postgresql-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/postgresql-keyring.gpg] http://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list
$PKG_UPDATE
;;
almalinux|rocky|centos|rhel|ol|amzn)
if [[ "$ID" == "amzn" ]]; then
$PKG_INSTALL https://download.postgresql.org/pub/repos/yum/reporpms/EL-8-x86_64/pgdg-redhat-repo-latest.noarch.rpm
else
VERSION_ID_MAJOR=$(echo $VERSION_ID | cut -d. -f1)
$PKG_INSTALL https://download.postgresql.org/pub/repos/yum/reporpms/EL-${VERSION_ID_MAJOR}-x86_64/pgdg-redhat-repo-latest.noarch.rpm
fi
;;
esac
echo -e "${GREEN}[3/$TOTAL_STEPS] Installing PostgreSQL ${POSTGRES_VERSION}...${NC}"
case "$ID" in
ubuntu|debian)
$PKG_INSTALL postgresql-${POSTGRES_VERSION} postgresql-client-${POSTGRES_VERSION} postgresql-contrib-${POSTGRES_VERSION}
;;
almalinux|rocky|centos|rhel|ol|amzn)
$PKG_INSTALL postgresql${POSTGRES_VERSION}-server postgresql${POSTGRES_VERSION}-contrib
/usr/pgsql-${POSTGRES_VERSION}/bin/postgresql-${POSTGRES_VERSION}-setup initdb
;;
fedora)
$PKG_INSTALL postgresql-server postgresql-contrib
postgresql-setup --initdb
;;
esac
echo -e "${GREEN}[4/$TOTAL_STEPS] Starting and enabling PostgreSQL...${NC}"
systemctl enable $PG_SERVICE
systemctl start $PG_SERVICE
systemctl status $PG_SERVICE --no-pager -l
echo -e "${GREEN}[5/$TOTAL_STEPS] Adding TimescaleDB repository...${NC}"
case "$ID" in
ubuntu|debian)
curl -fsSL https://packagecloud.io/timescale/timescaledb/gpgkey | gpg --dearmor -o /usr/share/keyrings/timescaledb-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/timescaledb-keyring.gpg] https://packagecloud.io/timescale/timescaledb/ubuntu/ $(lsb_release -c -s) main" > /etc/apt/sources.list.d/timescaledb.list
$PKG_UPDATE
;;
almalinux|rocky|centos|rhel|ol|amzn)
cat > /etc/yum.repos.d/timescale_timescaledb.repo <<EOF
[timescale_timescaledb]
name=timescale_timescaledb
baseurl=https://packagecloud.io/timescale/timescaledb/el/\$releasever/\$basearch
repo_gpgcheck=1
gpgcheck=0
enabled=1
gpgkey=https://packagecloud.io/timescale/timescaledb/gpgkey
sslverify=1
sslcacert=/etc/pki/tls/certs/ca-bundle.crt
metadata_expire=300
EOF
;;
esac
echo -e "${GREEN}[6/$TOTAL_STEPS] Installing TimescaleDB...${NC}"
case "$ID" in
ubuntu|debian)
$PKG_INSTALL timescaledb-2-postgresql-${POSTGRES_VERSION}
;;
almalinux|rocky|centos|rhel|ol|amzn)
$PKG_INSTALL timescaledb-2-postgresql${POSTGRES_VERSION}
;;
esac
echo -e "${GREEN}[7/$TOTAL_STEPS] Configuring TimescaleDB...${NC}"
# Run timescaledb-tune for optimization
timescaledb-tune --quiet --yes || echo -e "${YELLOW}[WARNING] TimescaleDB tune failed, continuing...${NC}"
# Add TimescaleDB to postgresql.conf
if [[ "$ID" == "ubuntu" ]] || [[ "$ID" == "debian" ]]; then
PG_CONF="/etc/postgresql/${POSTGRES_VERSION}/main/postgresql.conf"
else
PG_CONF="${PG_CONFIG_DIR}/postgresql.conf"
fi
# Backup original config
cp "$PG_CONF" "${PG_CONF}.backup.$(date +%Y%m%d_%H%M%S)"
# Add TimescaleDB to shared_preload_libraries if not already present
if ! grep -q "timescaledb" "$PG_CONF"; then
sed -i "s/#shared_preload_libraries = ''/shared_preload_libraries = 'timescaledb'/" "$PG_CONF"
sed -i "s/shared_preload_libraries = ''/shared_preload_libraries = 'timescaledb'/" "$PG_CONF"
sed -i "s/shared_preload_libraries = 'timescaledb'/shared_preload_libraries = 'timescaledb'/" "$PG_CONF"
echo "shared_preload_libraries = 'timescaledb'" >> "$PG_CONF"
fi
# Restart PostgreSQL to load TimescaleDB
systemctl restart $PG_SERVICE
echo -e "${GREEN}[8/$TOTAL_STEPS] Setting up database and user...${NC}"
# Create database and user
sudo -u postgres psql <<EOF
CREATE DATABASE $DB_NAME;
CREATE USER $DB_USER WITH PASSWORD '$DB_PASSWORD';
GRANT ALL PRIVILEGES ON DATABASE $DB_NAME TO $DB_USER;
ALTER USER $DB_USER CREATEDB;
\q
EOF
# Enable TimescaleDB extension
sudo -u postgres psql -d $DB_NAME -c "CREATE EXTENSION IF NOT EXISTS timescaledb;"
# Create sample configuration for data retention
sudo -u postgres psql -d $DB_NAME <<EOF
-- Example: Create a sample hypertable and retention policy
CREATE TABLE IF NOT EXISTS metrics (
time TIMESTAMPTZ NOT NULL,
device_id INTEGER,
temperature DOUBLE PRECISION,
humidity DOUBLE PRECISION
);
-- Convert to hypertable
SELECT create_hypertable('metrics', 'time', if_not_exists => TRUE);
-- Add retention policy (keep data for 30 days, compress after 7 days)
SELECT add_retention_policy('metrics', INTERVAL '30 days', if_not_exists => TRUE);
SELECT add_compression_policy('metrics', INTERVAL '7 days', if_not_exists => TRUE);
-- Create continuous aggregate for hourly averages
CREATE MATERIALIZED VIEW IF NOT EXISTS metrics_hourly
WITH (timescaledb.continuous) AS
SELECT time_bucket('1 hour', time) AS bucket,
device_id,
AVG(temperature) as avg_temperature,
AVG(humidity) as avg_humidity
FROM metrics
GROUP BY bucket, device_id;
-- Add retention policy for continuous aggregate (keep for 1 year)
SELECT add_retention_policy('metrics_hourly', INTERVAL '365 days', if_not_exists => TRUE);
\q
EOF
echo -e "${GREEN}[SUCCESS] TimescaleDB installation completed successfully!${NC}"
echo ""
echo -e "${BLUE}Database Information:${NC}"
echo " Database Name: $DB_NAME"
echo " Database User: $DB_USER"
echo " Database Password: $DB_PASSWORD"
echo " PostgreSQL Service: $PG_SERVICE"
echo ""
echo -e "${BLUE}Connection Examples:${NC}"
echo " psql -h localhost -U $DB_USER -d $DB_NAME"
echo " Connection string: postgresql://$DB_USER:$DB_PASSWORD@localhost:5432/$DB_NAME"
echo ""
echo -e "${YELLOW}[INFO] Sample hypertable 'metrics' created with retention policies${NC}"
echo -e "${YELLOW}[INFO] Data retention: 30 days, Compression: 7 days${NC}"
echo -e "${YELLOW}[INFO] Save the database credentials in a secure location!${NC}"
# Verify installation
echo -e "${GREEN}Verifying installation...${NC}"
sudo -u postgres psql -d $DB_NAME -c "SELECT default_version, installed_version FROM pg_available_extensions WHERE name = 'timescaledb';" || echo -e "${RED}[ERROR] TimescaleDB verification failed${NC}"
Review the script before running. Execute with: bash install.sh