2

5 秒ごとに接続を自動的にチェックし、結果を MySQL データベースに保存するループ PHP スクリプトを使用して、ISP のダウンタイムの監視を開始しました。スクリプトは、いくつかのリモート Web サイトにアクセスできるかどうかを確認し、結果をログに記録します。チェックの時間とステータスは、常にデータベースに保存されます。

テーブルの構造は次のとおりです。

id (auto increment)
time (time stamp)
status (varchar)

今私の問題に。

私はデータを持っていますが、それを使用して得たい結果を達成する方法がわかりません。基本的に、接続がダウンしていたすべての期間と、接続がダウンしていた時間を見つけたいと思います。

たとえば、次のデータを含む 10 行がある場合

0 | 2012-07-24 22:23:00 | up
1 | 2012-07-24 22:23:05 | up
2 | 2012-07-24 22:23:10 | down
3 | 2012-07-24 22:23:16 | down
4 | 2012-07-24 22:23:21 | up
5 | 2012-07-24 22:23:26 | down
6 | 2012-07-24 22:23:32 | down
7 | 2012-07-24 22:23:37 | up
8 | 2012-07-24 22:23:42 | up
9 | 2012-07-24 22:23:47 | up

クエリは期間 (22:23:10 から 22:23:21 まで、および 22:23:26 から 22:23:37 まで) を返す必要があります。したがって、クエリは、接続が最初にダウンしてから最初に接続が再開するまでの時間を常に検出する必要があります。

私がうまくいくと思った方法の 1 つは、接続がダウンまたはアップするすべての行を見つけることでしたが、どうすればこれらの行を見つけることができるでしょうか? そして、これよりも良い解決策はありますか?

クエリがどのように見えるべきか本当にわからないので、助けていただければ幸いです。

ありがとう、よろしくラッシー

4

3 に答える 3

0

これが1つのアプローチです。

タイムスタンプ順にステータス行を取得することから始めます (インライン ビューは としてエイリアス化されますs)。次に、MySQL ユーザー変数を使用して、前の行の値を保持し、各行を処理します。

私たちが本当に探しているのは、一連の「ダウン」ステータスの直後に続く「アップ」ステータスです。そして、「up」ステータスの行が見つかった場合、本当に必要なのは、前の一連の「down」ステータスからの最も古いタイムスタンプです。

したがって、次のようなものが機能します。

SELECT d.start_down
     , d.ended_down
  FROM (SELECT @i := @i + 1 AS i
             , @start := IF(s.status = 'down' AND (@status = 'up' OR @i = 1), s.time, @start) AS start_down
             , @ended := IF(s.status = 'up' AND @status = 'down', s.time, NULL) AS ended_down
             , @status := s.status
         FROM (SELECT t.time
                    , t.status
                 FROM mydata t
                WHERE t.status IN ('up','down')
                ORDER BY t.time ASC, t.status ASC
              ) s
         JOIN (SELECT @i := 0, @status := 'up', @ended := NULL, @start := NULL) i
      ) d
WHERE d.start_down IS NOT NULL
  AND d.ended_down IS NOT NULL

これは、表示する特定のデータ セットに対して機能します。

これが処理しないもの (返さないもの) は、まだ終了していない「ダウン」期間です。つまり、「アップ」ステータスが続かない一連の「ダウン」ステータスです。

行を順番に返すためのファイルソート操作を回避するには、 にカバリング インデックスが必要です(time,status)。このクエリは、一時 (MyISAM) テーブルを生成して、 としてエイリアス化されたインライン ビューを具体化しますd

注:このクエリが何を行っているかを理解するには、最も外側のクエリを剥がして、エイリアスとしてインライン ビューのクエリだけを実行します(選択リストにd追加できます)。s.time

このクエリは、「アップ」または「ダウン」ステータスのすべての行を取得しています。「トリック」は、「ダウン」期間を終了する行のみに「開始」時間と「終了」時間の両方を割り当てる (ダウン期間をマークする) ことです。(つまり、「ダウン」ステータスの行に続く「アップ」ステータスの最初の行です。) これが実際の作業が行われる場所です。最も外側のクエリは、この結果セット内のすべての「余分な」行を除外するだけです (つまり、必要ありません。)

SELECT @i := @i + 1 AS i
     , @start := IF(s.status = 'down' AND (@status = 'up' OR @i = 1), s.time, @start) AS start_down
     , @ended := IF(s.status = 'up' AND @status = 'down', s.time, NULL) AS ended_down
     , @status := s.status
     , s.time
  FROM (SELECT t.time
             , t.status
          FROM mydata t
         WHERE t.status IN ('up','down')
         ORDER BY t.time ASC, t.status ASC
       ) s
  JOIN (SELECT @i := 0, @status := 'up', @ended := NULL, @start := NULL) i

エイリアス化されたインラインビューの目的はs、タイムスタンプ値で並べ替えられた行を取得することです。これにより、それらを順番に処理できます。エイリアス化されたインライン ビューはそのままなiので、クエリの開始時にいくつかのユーザー変数を初期化できます。

Oracle または SQL Server で実行している場合は、"分析関数" または "ランキング関数" (それぞれ名前が付けられているとおり) を利用できます。 "。

于 2012-07-25T22:00:38.660 に答える
0

これが機能するかどうかはわかりません(コメントだけではない場合)

1現在の IDより小さいID を持つ行のステータスが異なる場合にのみ行を選択し (したがって、任意のペリオンの最初のエントリを選択します)、>= と同じステータスで終了時間を決定します。

SELECT ou.id AS outerId, 
       ou.timeColumn AS currentRowTime,
       ou.status AS currentRowStatus,
      (  SELECT max(time)
         FROM statusTable
         WHERE time >= ou.timeColumn AND status = ou.status) AS endTime
FROM statusTable ou
WHERE ou.status != 
       (SELECT status
        FROM statusTable
        WHERE id = (ou.id -1))
于 2012-07-25T21:28:31.743 に答える
0

今のところ、これをあなたのセットアップに合わせて調整する時間はありませんが、Web ページでほぼ同じことを行って、コンピューターの電源が切られたときと電源が入れ直されたときを監視しています。点灯していた合計時間を計算すると...

これを完全に無視しない限り、PHP にアクセスできるかどうかもわかりません。もしそうなら、あなたは次のようなものを適応させることができるかもしれません:

$lasttype="OFF";
$ontime=0;
$totalontime=0;

$query2 = " SELECT
  log_unixtime,
  status
FROM somefaketablename
ORDER BY
  log_unixtime asc
;";

$result2=mysql_query($query2);
while($row2=mysql_fetch_array($result2)){
  if($lasttype=="OFF" && $row2['status']=="ON"){
    $ontime = $row2['log_unixtime'];
  }elseif($lasttype=="ON" && $row2['status']=="OFF"){
    $thisblockontime=$row2['log_unixtime']-$ontime;
    $totalontime+=($thisblockontime);
  }
  $lasttype=$row2['status'];
}

基本的に、コンピュータがオフであることを示す偽の行から始めて、実際の各行をループします。

コンピューターがオフだったが、現在はオンになっている場合は、変数を設定して、いつオンになったかを確認し、ループを続けます...

コンピュータがオンになるまでループを続けますが、現在はオフになっています。その場合は、現在の行の時間から、以前に保存されたオンになった時間を減算します。それは、その「ON」のグループについて、それがどれくらいの期間オンになっていたかを示しています。

私が言ったように、あなたが望むことをするためにそれをかなり大きく適応させる必要がありますが、「コンピュータのオン/オフ」を「接続のアップ/ダウン」に置き換えると、本質的に同じ考えです...

この作業を行う 1 つのことは、日付を整数として、UNIX タイムスタンプとして保存していることです。そのため、減算が機能するように日付を変換する必要がある場合があります。

于 2012-07-25T21:37:19.913 に答える