← 返回文章列表
产品动态 4 分钟阅读 炬鲸团队

把日志当数据库查:炬鲸 SQL 检索实战

日志平台最缺的不是存储,是查询。本文介绍炬鲸的 SQL 化检索:用 SELECT、WHERE、GROUP BY 直接在海量日志上过滤、聚合与关联,附可直接套用的语句模板与性能建议。

为什么用 SQL 查日志

日志平台最常见的痛点不是存不下,而是查不动。关键词搜索只能定位"某句话",一旦要回答"过去 24 小时错误率最高的 5 个接口""哪些 pod 的 GC 停顿最严重"这类问题,就只能逐页翻,或者导出后自己写脚本处理。炬鲸把日志组织成一张可查询的表,支持标准 SQL:SELECT 做投影、WHERE 过滤、GROUP BY 聚合、JOIN 关联,一条语句顶过去半小时的手工翻页。对运维和开发来说 SQL 是现成技能,学习成本几乎为零,排查口径也更容易在团队里统一。

基础查询:过滤与投影

采集时解析出的字段(服务名、级别、耗时、trace_id、pod 等)在 SQL 里就是列名。查某个服务近一小时内的 ERROR 日志:

SELECT timestamp, message, pod
FROM logs
WHERE service = 'order-service'
  AND level = 'ERROR'
  AND timestamp > now() - INTERVAL 1 HOUR
ORDER BY timestamp DESC
LIMIT 100;

列名可以起中文别名,方便把语句直接贴给不熟 SQL 的同事:

SELECT level AS 级别, count(*) AS 条数
FROM logs
WHERE timestamp > now() - INTERVAL 1 HOUR
GROUP BY level;

嵌套字段(如 JSON 里的 request.user_id)用点号访问即可,和查普通列一样,不需要先解析再查。

聚合与关联

聚合才是 SQL 查日志真正值钱的地方。排查"哪个接口拖慢了整体",一条语句搞定:

SELECT api_path,
       avg(duration_ms) AS avg_ms,
       p99(duration_ms) AS p99_ms,
       count(*)        AS cnt
FROM logs
WHERE level = 'INFO'
  AND duration_ms IS NOT NULL
  AND timestamp > now() - INTERVAL 1 HOUR
GROUP BY api_path
ORDER BY p99_ms DESC
LIMIT 20;

p99、p95 这类分位聚合函数内置,不用自己实现。关联同样顺手:用 trace_id 把一次慢请求的所有日志串成一条调用链,从网关到数据库逐跳看耗时,直接定位卡在哪一跳。还可以把错误日志按 trace_id JOIN 到告警表,做到"告警即带调用链",值班人员点开告警就能看到上下文。

性能与索引建议

要让 SQL 查日志快,养成两个习惯:一是永远带时间范围,全表扫描是慢查询的最大来源;二是把高频过滤字段建索引。炬鲸写入侧按时间自动分区,查询侧对 service、level、trace_id 预建索引,几十亿条日志里上面的语句依然秒级返回。复杂聚合建议走异步任务,结果落成报表定时推送,别在排查高峰期和实时检索抢资源。对重复使用的语句,存成"保存查询"并共享给团队,比每次手敲更快也更不容易出错。