
قاعدة بيانات السلاسل الزمنية (TSDB) متخصصة في تخزين نقاط البيانات المفهرسة حسب الوقت والاستعلام عنها - قراءات أجهزة الاستشعار، ومقاييس الخادم، وسجلات التطبيقات، وبيانات التجزئة المالية، وقياس إنترنت الأشياء عن بعد. تتميز بيانات السلاسل الزمنية بخصائص فريدة تجعل قواعد البيانات التقليدية دون المستوى الأمثل:
قاعدة بيانات السلاسل الزمنية (TSDB) متخصصة في تخزين نقاط البيانات المفهرسة حسب الوقت والاستعلام عنها - قراءات أجهزة الاستشعار، ومقاييس الخادم، وسجلات التطبيقات، وبيانات التجزئة المالية، وقياس إنترنت الأشياء عن بعد. تتميز بيانات السلاسل الزمنية بخصائص فريدة تجعل قواعد البيانات التقليدية دون المستوى الأمثل:
تحتوي كل نقطة بيانات للسلسلة الزمنية على:
| مكون | مثال | الوصف |
|---|---|---|
| ** الطابع الزمني ** | 2026-05-24T14:30:00Z | عندما تم أخذ القياس |
| القيمة | 42.5 | القيمة المقاسة |
| ** متري ** | cpu_usage | ما يتم قياسه |
| ** العلامات / التسميات ** | المضيف = web01، المنطقة = شرق الولايات المتحدة | البيانات الوصفية للتصفية |
Metric: cpu_usage{host="web01", region="us-east"}
┌─────────────────────┬───────┐
│ Timestamp │ Value │
├─────────────────────┼───────┤
│ 2026-05-24T14:30:00 │ 42.5 │
│ 2026-05-24T14:30:01 │ 43.2 │
│ 2026-05-24T14:30:02 │ 41.8 │
│ ... │ ... │
└─────────────────────┴───────┘
| العملية | PostgreSQL | TimescaleDB (PostgreSQL + TS) | إنفلوكس دي بي (TSDB) |
|---|---|---|---|
| ** كتابة الإنتاجية ** | 10 ألف صف/ثانية | 100K-1M صفوف/ثانية | 1M+ صفوف/ثانية |
| الاستعلام: متوسط ساعة واحدة × 5 دقائق | دقائق (مسح كامل) | الثواني (التجميع المستمر) | ثواني |
| التخزين | موجه نحو الصف | صف/عمود مختلط | موجه نحو العمود |
| ضغط | لا شيء افتراضيا | 90%+ (الضغط الأصلي) | 90%+ |
| سياسات الاحتفاظ | إدارة الأقسام يدوياً | تلقائي | تلقائي |
| ** تقليص البيانات ** | الاستعلامات اليدوية | المجاميع المستمرة | استعلامات الاختزال |
| ** دعم SQL ** | كامل | كامل (SQL) | محدود (تدفق/SQL) |
| ميزة | TimescaleDB | InfluxDB | بروميثيوس | فيكتورياميتريكس | QuestDB |
|---|---|---|---|---|---|
| المحرك | ملحق PostgreSQL | محرك TS مخصص | مخصص على أساس السحب | محرك TS مخصص | عمودي |
| لغة الاستعلام | SQL | مزود/تدفق | PromQL | متوافق مع PromQL | SQL + التدفق |
| معدل الإقبال | 1 م +/ثانية | 1 م +/ثانية | 500 كيلو/ثانية | 1 م +/ثانية | 2 م+/ثانية |
| ضغط | 90-97% | 90+% | لا شيء | 90+% | 90+% |
| ** التجميع ** | عقدة متعددة (مقياس زمني) | المؤسسة | التقسيم الأصلي | أصلي | لا شيء |
| الاحتفاظ | تلقائي مع السياسات | تلقائي | شكلي | شكلي | دليل |
| ** المجاميع المستمرة ** | نعم (مواطن) | لا (مهمة منفصلة) | قواعد التسجيل | قواعد التسجيل | لا |
| الأفضل ل | مستخدمي SQL، البيانات التشغيلية | إنترنت الأشياء، DevOps | Kubernetes، السحابة الأصلية | مقاييس عالية المستوى | المالية، وعالية السرعة |
# InfluxDB v3 — data model
from influxdb_client import InfluxDBClient, Point
from influxdb_client.client.write_api import SYNCHRONOUS
client = InfluxDBClient(url="http://localhost:8086", token="my-token")
write_api = client.write_api(write_options=SYNCHRONOUS)
# A point = measurement + tags + fields + timestamp
point = (
Point("temperature")
.tag("sensor", "sensor-001")
.tag("location", "warehouse-a")
.field("value", 23.5)
.field("humidity", 65.2)
.time(datetime.utcnow())
)
write_api.write(bucket="sensors", record=point)
-- InfluxDB SQL (v3)
SELECT time, value
FROM temperature
WHERE sensor = 'sensor-001'
AND time >= NOW() - INTERVAL '1 hour'
ORDER BY time DESC;
-- Aggregation with downsampling
SELECT time_bucket(INTERVAL '5 minutes', time) as bucket,
AVG(value) as avg_temp,
MAX(value) as max_temp,
MIN(value) as min_temp
FROM temperature
WHERE location = 'warehouse-a'
AND time >= NOW() - INTERVAL '24 hours'
GROUP BY bucket
ORDER BY bucket;
-- InfluxDB: automatic data lifecycle
CREATE RETENTION POLICY "one_hour"
ON "sensors"
DURATION 1h
REPLICATION 1
DEFAULT;
CREATE RETENTION POLICY "one_week"
ON "sensors"
DURATION 168h
REPLICATION 1;
-- Create downsample task
CREATE TASK "downsample_1h" ON "sensors"
EVERY 1 HOUR
BEGIN
-- Aggregate 1-minute data to 1-hour averages
SELECT time_bucket(INTERVAL '1 hour', time) as time,
AVG(value) as value
INTO "one_week"."temperature_hourly"
FROM "one_hour"."temperature"
WHERE time >= NOW() - INTERVAL '2 hours'
GROUP BY 1, sensor, location;
END;
┌─────────────────────────────────────────────────┐
│ Prometheus Server │
│ ┌──────────┐ ┌──────────┐ ┌───────────────┐ │
│ │ Retrieval│ │ TSDB │ │ Alertmanager │ │
│ │ (pull) │──│ (storage)│──│ (alerts) │ │
│ └─────┬────┘ └──────────┘ └───────────────┘ │
│ │ │
└────────┼──────────────────────────────────────────┘
│
┌────┼────────────┬──────────────┐
▼ ▼ ▼ ▼
App App Node Exporter Custom Exporter
# Basic queries
cpu_usage{host="web01"}
http_requests_total[5m]
# Rate (per-second average)
rate(http_requests_total[5m])
# Aggregation
avg by (host) (cpu_usage)
# Histogram quantile
histogram_quantile(0.95, rate(http_request_duration_seconds_bucket[5m]))
# Predict linear regression
predict_linear(node_disk_free_bytes[1h], 3600) < 0
# Recording rule (pre-computed)
- record: job:http_requests:rate5m
expr: rate(http_requests_total[5m])
# prometheus.yml
scrape_configs:
- job_name: 'kubernetes-nodes'
kubernetes_sd_configs:
- role: node
relabel_configs:
- source_labels: [__meta_kubernetes_node_label_kubernetes_io_role]
regex: control-plane
action: drop
- job_name: 'custom-app'
static_configs:
- targets: ['app01:8080', 'app02:8080', 'app03:8080']
يعد TimescaleDB امتدادًا لـ PostgreSQL الذي يضيف إمكانات السلاسل الزمنية مع الحفاظ على التوافق الكامل مع SQL.
-- Create a hypertable (automatically partitions by time)
CREATE TABLE temperature (
time TIMESTAMPTZ NOT NULL,
sensor_id INTEGER,
location TEXT,
value DOUBLE PRECISION,
humidity DOUBLE PRECISION
);
-- Convert to hypertable (partitions by 1 day chunks)
SELECT create_hypertable('temperature', 'time',
chunk_time_interval => INTERVAL '1 day');
-- Add partitioning by location (optional, for multi-node)
SELECT add_dimension('temperature', 'location', number_partitions => 4);
-- Enable compression on hypertable
ALTER TABLE temperature SET (
timescaledb.compress,
timescaledb.compress_segmentby = 'sensor_id',
timescaledb.compress_orderby = 'time DESC'
);
-- Compression policy: compress data older than 7 days
SELECT add_compression_policy('temperature', INTERVAL '7 days');
-- Compression ratio: 90-97%
-- 100GB of raw data → 3-10GB compressed
-- Create 5-minute aggregates (refreshed every minute)
CREATE MATERIALIZED VIEW temperature_hourly
WITH (timescaledb.continuous) AS
SELECT time_bucket('5 minutes', time) as bucket,
sensor_id,
AVG(value) as avg_temp,
MAX(value) as max_temp,
MIN(value) as min_temp,
stddev(value) as temp_stddev
FROM temperature
GROUP BY bucket, sensor_id;
-- Refresh policy
SELECT add_continuous_aggregate_policy('temperature_hourly',
start_offset => INTERVAL '3 days',
end_offset => INTERVAL '1 hour',
schedule_interval => INTERVAL '1 minute');
-- Automatic data removal
SELECT add_retention_policy('temperature_raw', INTERVAL '30 days');
SELECT add_retention_policy('temperature_hourly', INTERVAL '1 year');
SELECT add_retention_policy('temperature_daily', INTERVAL '5 years');
-- Raw data: 1m intervals, kept 30 days
-- 5m average: kept 1 year
-- 1h average: kept 5 years
SELECT time_bucket('1 hour', time) as hour,
AVG(value) as avg_temperature,
PERCENTILE_CONT(0.95) WITHIN GROUP (ORDER BY value) as p95
FROM temperature
WHERE time >= NOW() - INTERVAL '7 days'
GROUP BY hour
ORDER BY hour;
-- Fill missing data with linear interpolation
SELECT time_bucket('5 minutes', time) as bucket,
INTERPOLATE(AVG(value)) as temperature
FROM temperature
WHERE sensor_id = 1
AND time >= NOW() - INTERVAL '1 hour'
GROUP BY bucket
ORDER BY bucket;
-- Or use LAST observation carried forward (LOCF)
SELECT time_bucket('5 minutes', time) as bucket,
LOCF(AVG(value)) as temperature
FROM temperature
GROUP BY bucket
ORDER BY bucket;
-- Detect values outside 3 standard deviations
WITH stats AS (
SELECT AVG(value) as mean,
stddev(value) as sigma
FROM temperature
WHERE time >= NOW() - INTERVAL '24 hours'
)
SELECT time, value,
(value - mean) / sigma as z_score
FROM temperature, stats
WHERE time >= NOW() - INTERVAL '1 hour'
AND ABS((value - mean) / sigma) > 3
ORDER BY time;
Raw data layout (row-oriented):
time, sensor_id, location, value
14:30:00, 1, "room_a", 23.5
14:30:01, 1, "room_a", 23.6
14:30:02, 1, "room_a", 23.4
14:30:03, 1, "room_a", 23.7
Column-oriented + Delta encoding:
time: 14:30:00, +1s, +1s, +1s → 1 value + 3 deltas
sensor_id: 1, 1, 1, 1 → run-length encoding: "1 × 4"
location: "room_a" × 4 → run-length encoding: "room_a × 4"
value: 23.5, +0.1, -0.2, +0.3 → delta encoding
Result: ~95% compression vs. raw text
| قاعدة البيانات | الخام | مضغوط | نسبة |
|---|---|---|---|
| TimescaleDB | 100 جيجابايت | 3-10 جيجابايت | 90-97% |
| InfluxDB | 100 جيجابايت | 5-15 جيجابايت | 85-95% |
| بروميثيوس | 100 جيجابايت | 20-25 جيجابايت | 75-80% |
| فيكتورياميتريكس | 100 جيجابايت | 3-8 جيجابايت | 92-97% |
# Node exporter metrics collected every 15 seconds
metrics:
- cpu_usage{host="web01", cpu="0"}
- memory_used{host="web01", type="RAM"}
- disk_io{host="web01", device="sda", type="read_bytes"}
- network_bytes{host="web01", interface="eth0", direction="in"}
- load_average{host="web01", duration="1m"}
storage:
raw: 15s intervals, 7 days
aggregated: 5m intervals, 30 days
daily: 1h intervals, 1 year
# Millions of devices sending data every minute
from timescaledb import hypertable
sensors = hypertable('sensor_data', 'time',
chunk_time='1 day',
compression='7 days',
retention='90 days'
)
# Query: average temperature per device per hour
query = """
SELECT time_bucket('1 hour', time) as hour,
device_id,
AVG(temperature) as avg_temp,
COUNT(*) as samples
FROM sensor_data
WHERE time >= NOW() - INTERVAL '24 hours'
GROUP BY hour, device_id
"""
-- Stock price ticks: 10M+ per day per instrument
CREATE TABLE ticks (
time TIMESTAMPTZ NOT NULL,
symbol TEXT NOT NULL,
price DOUBLE PRECISION,
volume BIGINT,
bid DOUBLE PRECISION,
ask DOUBLE PRECISION
);
SELECT create_hypertable('ticks', 'time',
chunk_time_interval => INTERVAL '1 hour');
-- OHLC (Open-High-Low-Close) candlestick query
SELECT time_bucket('5 minutes', time) as bucket,
symbol,
FIRST(price, time) as open,
MAX(price) as high,
MIN(price) as low,
LAST(price, time) as close,
SUM(volume) as volume
FROM ticks
WHERE symbol = 'AAPL'
AND time >= NOW() - INTERVAL '1 day'
GROUP BY bucket, symbol;
-- Good schema: separate metrics by table
CREATE TABLE cpu_usage (time TIMESTAMPTZ, host TEXT, value DOUBLE PRECISION);
CREATE TABLE memory_usage (time TIMESTAMPTZ, host TEXT, value DOUBLE PRECISION);
-- Avoid: single wide table with all metrics as columns
-- (leads to sparse data, poor compression)
-- Too small: too many partitions, slow queries
-- Too large: poor memory management, slow ingestion
-- Rule of thumb: each chunk should be 1-10GB compressed
-- For 1000 writes/sec, 1KB each = 86GB/day
-- 1 day chunks = 86GB (too large)
-- 6 hour chunks = 21GB (good)
SELECT set_chunk_time_interval('temperature', INTERVAL '6 hours');
تم تصميم قواعد بيانات السلاسل الزمنية خصيصًا للبيانات التي تنتجها الأنظمة الحديثة بمعظمها: القياسات ذات الطابع الزمني من التطبيقات والبنية التحتية وأجهزة إنترنت الأشياء والأسواق المالية.
| حالة الاستخدام | قاعدة البيانات الموصى بها |
|---|---|
| مراقبة البنية التحتية (Kubernetes) | بروميثيوس + فيكتورياميتريكس |
| بيانات مستشعر إنترنت الأشياء مع استعلامات SQL | TimescaleDB |
| التحليلات في الوقت الحقيقي، DevOps | InfluxDB |
| البيانات المالية عالية التردد | QuestDB |
| المقاييس السحابية الأصلية والمعتمدة على السحب | بروميثيوس |
الوجبات الرئيسية:
تستوعب بنية السلاسل الزمنية الصحيحة البيانات بكفاءة، وتؤخرها بسلاسة، وتقوم بالاستعلام عنها على الفور - وتحول الأرقام ذات الطوابع الزمنية الأولية إلى رؤى قابلة للتنفيذ.
لا توجد تعليقات معتمدة بعد. قد تنتظر الردود الجديدة المراجعة.