1

这类似于mysql query 中的 Compute dates and durations,除了我没有唯一的 ID 列可以使用,而且我的样本不是起点/终点。

作为一个有趣的实验,我将 cron 设置为ps aux > 'date +%Y-%m-%d_%H-%M'.txt. 我现在有大约 250,000 个“机器正在运行的东西”的样本。

我想把它变成“进程| cmd | 开始| 停止”的列表。假设是“开始”事件是该对第一次存在,而“停止”事件是它停止存在的第一个样本:样本不可能“丢失”或任何事情。

也就是说,有哪些方法可以进行这种转换,最好使用 SQL(因为我喜欢 SQL,这似乎是一个不错的挑战)。假设 pids 不能重复,这是一项微不足道的任务(将所有内容放在一个表中,SELECT MIN(time), MAX(time), pid GROUP BY pid)。但是,由于 PID/cmd 对是重复的(我检查过,有重复),我需要一种方法来执行真正的“查找所有连续段”搜索。

如有必要,我可以做一些形式

Load file0 -> oldList
ForEach fileN:
    Load fileN ->newList
    oldList-newList = closedN
    newList-oldList = openedN
    oldList=newList

但这不是 SQL,也不是很有趣。谁知道呢,我最终可能会在某个时候拥有真正的 SQL 数据来处理这个属性。

我正在考虑首先构建一个差异表,然后将所有关闭与所有打开连接起来,并在每次打开后拉出最小距离关闭,但我想知道是否有更好的方法。

4

1 回答 1

1

你没有提到你正在使用什么数据库。让我假设您正在使用支持排名函数的数据库,因为这简化了解决方案。

解决这个问题的关键是观察。您想为每个 pid 分配一个 id 以查看它是否是唯一的。当 pid未出现在先前的时间戳输出中时,我将假设 pid 表示单个进程。

现在,想法是:

  1. 为每组输出分配一个序列号。根据日期,第一次调用 ps 得到 1,接下来是 2,依此类推。
  2. 根据日期为每个 pid 分配一个序号。第一次出现得到 1,接下来是 2,依此类推。
  3. 对于按顺序出现的 pid,差异是一个常数。我们可以将其称为该集合的 groupid。

所以,这是实际的查询:

select groupid, pid, min(time), max(time)
from (select t.*,
             (dense_rank() over (order by time) -
              row_number() over (partition by pid order by time)
             ) as groupid
      from t
     ) t
group by groupid, pid

这适用于大多数数据库(SQL Server、Oracle、DB2、Postgres、Teradata 等)。它在 MySQL 中不起作用,因为 MySQL 不支持窗口/分析函数。

于 2012-09-14T20:34:17.320 回答