3. SQL 基础回顾:查询与聚合

在将 SQL 与 Grafana 结合进行趋势分析之前,必须牢固掌握 SQL 查询的核心语法。本章将系统回顾 SELECT、WHERE、ORDER BY、LIMIT 以及常用聚合函数,这些是构建任何时间序列查询的基石。

3.1 SELECT 语句与字段投影

SELECT 语句用于从数据库表中检索数据。其基本语法决定了返回哪些列(字段)以及如何对它们进行变换。

核心语法结构:
SELECT column1, column2, ...
FROM table_name;

使用 * 通配符可选择所有列,但在生产环境中应明确指定列名以提高查询性能和可读性。

Grafana 实践提示: 在 Grafana 的查询编辑器中,始终明确列出你需要的字段(如 timestamp、value、host),避免使用 SELECT *,这可以减少数据传输量并避免因表结构变更导致的仪表盘故障。
SELECT 字段投影流程 源表 (logs) id, ts, cpu, mem 投影操作 SELECT ts, cpu 结果集 ts, cpu 只保留需要的列,减少 I/O 与网络开销

3.2 WHERE 条件过滤

WHERE 子句用于在数据返回前过滤行记录。它支持比较运算符(=, >, <)、逻辑运算符(AND, OR, NOT)以及范围匹配(IN, BETWEEN, LIKE)。

运算符 示例 说明
= WHERE status = 'active' 精确匹配
> / < WHERE cpu > 90 大于 / 小于
BETWEEN WHERE ts BETWEEN '2024-01-01' AND '2024-01-31' 范围匹配(闭区间)
IN WHERE region IN ('us-east', 'eu-west') 匹配集合中的任意值
LIKE WHERE host LIKE 'web-%' 模式匹配(% 通配符)
性能警告: 在 WHERE 子句中对列使用函数(如 WHERE DATE(ts) = '2024-01-01')会导致索引失效。应尽量使用列原生格式进行范围比较,或利用数据库的时间函数优化。

3.3 ORDER BY 排序与 LIMIT 分页

ORDER BY 用于对结果集按一列或多列进行排序,默认升序(ASC),可指定 DESC 降序。LIMIT 用于限制返回的行数,常与 ORDER BY 配合实现“Top-N”查询。

典型用法:获取 CPU 使用率最高的前 5 条记录
SELECT timestamp, host, cpu_usage
FROM system_metrics
WHERE timestamp > now() - INTERVAL '1 hour'
ORDER BY cpu_usage DESC
LIMIT 5;

分页模式: 在需要分页展示时,某些数据库(如 PostgreSQL、MySQL)支持 LIMIT 配合 OFFSET 语法。

-- 获取第 2 页数据,每页 10 条
SELECT * FROM events
ORDER BY event_time DESC
LIMIT 10 OFFSET 10;
Grafana 应用: 在 Grafana 的“Table”面板中,你可以利用 ORDER BY 和 LIMIT 来展示“最新告警”或“最高延迟的 Top 10 服务”,无需在应用层进行二次排序。

3.4 常用聚合函数

聚合函数用于对一组值执行计算并返回单个汇总值。它们通常与 GROUP BY 子句结合使用,是趋势分析的核心工具。

函数 返回类型 说明 忽略 NULL
COUNT(*) 整数 统计行数(包括 NULL) 否
COUNT(column) 整数 统计非 NULL 值的数量 是
SUM(column) 数值 计算数值列的总和 是
AVG(column) 浮点数 计算数值列的平均值 是
MIN(column) 与列类型相同 返回最小值 是
MAX(column) 与列类型相同 返回最大值 是
聚合函数数据流 原始行数据 100 行记录 GROUP BY 按 host 分组 聚合计算 AVG(cpu) 结果 3 行 聚合函数将多行数据压缩为单个值,是时间序列降采样的基础 例如:将 1 分钟的原始点聚合成一个平均值点

3.5 综合查询示例

以下示例展示了如何将上述知识点组合成一个完整的趋势分析查询。该查询按小时统计每个服务的平均响应时间和请求总数。

SELECT
    DATE_TRUNC('hour', request_time) AS hour_bucket,
    service_name,
    COUNT(*) AS total_requests,
    AVG(response_time_ms) AS avg_response_time,
    MAX(response_time_ms) AS max_response_time
FROM api_requests
WHERE request_time >= now() - INTERVAL '7 days'
  AND status_code != 500
GROUP BY hour_bucket, service_name
ORDER BY hour_bucket DESC, avg_response_time DESC
LIMIT 100;
查询解析:
  • DATE_TRUNC:将时间戳截断到小时级别,实现时间桶聚合。
  • WHERE:过滤最近 7 天数据,并排除服务器错误(500)。
  • GROUP BY:按小时和服务名分组,这是生成多维度时间序列的关键。
  • ORDER BY:按时间降序,再按平均响应时间降序排列。
  • LIMIT:限制返回 100 条记录,防止 Grafana 面板过载。
Grafana 集成: 在 Grafana 的“Time series”面板中,你可以直接使用上述查询作为数据源。Grafana 会自动识别 hour_bucket 列为时间字段,service_name 为维度字段,avg_response_time 和 total_requests 为指标字段,无需额外配置。

3.6 常见错误与避坑指南

错误模式 错误示例 正确做法
SELECT 中混合聚合与非聚合列 SELECT host, AVG(cpu) FROM metrics 非聚合列必须出现在 GROUP BY 中
WHERE 中使用聚合函数 WHERE AVG(cpu) > 90 使用 HAVING 子句过滤聚合结果
ORDER BY 使用别名但数据库不支持 ORDER BY avg_cpu(某些数据库) 使用原始表达式或确认数据库支持别名排序
LIMIT 不加 ORDER BY SELECT * FROM logs LIMIT 10 结果不确定,应始终配合 ORDER BY