1

ユーザーがアプリケーションに接続しているときに、2 ~ 5 秒ごとにデータベースに ping を実行するシステムを取得しました。彼の接続に応じて、ping の時間枠は 10 秒ほど長くなる場合があります。

例:

Pings: 1,4,6,8,9,12,16,20,50,180,187,189,200,203,206,210 ...

ping 間の 1 分を超えない範囲を取得してグループ化するためのクエリを実行しているので、ユーザーが接続されている時間を知ることができます。

この質問について@fancyPantsがアドバイスしたように、結果を選択するために実行しているクエリは次のとおりです 。MySQL query to group results by date range?

select
userid, groupnum,
min(ping) as start_date,
max(ping) as end_date,
max(ping) - min(ping) as duration
from (
select
*,
@groupnum := if(@prevUser != userId, @groupnum + 1, @groupnum),
@groupnum := if(ping - @prevTS > 60, @groupnum + 1, @groupnum) as groupnum,
@prevUser := userid,
@prevTS := ping
from
Table1 t
, (select @groupnum:=1, @prevTS:=NULL, @prevUser:=NULL) vars
order by userid, ping
) sq
group by userid, groupnum

次の結果が生成されます。

user: X | start_date: 1   | end_date: 50  | duration: 49
user: X | start_date: 180 | end_date: 210 | duration: 30

このクエリに、次のことを行うステートメントを追加して、助けが必要です。

1位。選択した行を、クエリが返すスキーマとまったく同じ新しいテーブルに挿入します。

id: auto_increment| user: X | start_date: 1   | end_date: 50  | duration: 49
id: auto_increment| user: X | start_date: 180 | end_date: 210 | duration: 30

2番目。クエリで選択され、新しいテーブルに挿入された、選択された行を削除します。

  • このクエリは、サーバー上の cronjob によって 10 分ごとに実行されます。そのため、大きな打撃を受ける可能性のある ping テーブルをクリーンアップし、サーファーに表示する値を新しいテーブルに保存できます。

  • 新しいクエリでは、有効期限が切れていない ping をフィルター処理する句が必要です。有効期限が切れていない ping は、cron が実行される現在の時刻から 60 秒以内に実行されたものです。たとえば、現在 = 100 の場合、最後に取得する ping は 41 未満にすることはできません。このようにして、cron の実行時に、まだデータベースに ping しているユーザーから行を選択しません。

1 回のクエリで実行できますか、それとも 2 回必要ですか?

ありがとう、

4

2 に答える 2

1

(以前の回答のフォローアップ)

ping_timestamp 列には正確に何が格納されていますか? Unix タイムスタンプか何か?UNIXタイムスタンプであると仮定します。

ユーザー アクティビティ データを保持するテーブルを作成します。

create table user_activity (
    user_id    int(11) not null
  , start_date int(11) not null
  , end_date   int(11) not null
  , duration   int(11) not null
);

まだ閉じていない間隔をスキップしてデータを集計します。

set @rnum = 1;
set @cut_off = unix_timestamp() - 60;

insert
  into user_activity
select user_id
     , min(ping_timestamp) start_date
     , max(ping_timestamp) end_date
     , max(ping_timestamp)-min(ping_timestamp) duration
  from ( select user_id
              , ping_timestamp
              , @rnum := if(ping_timestamp - @prev_ping_ts > 60, @rnum+1, @rnum) rnum
              , @prev_ping_ts := ping_timestamp
           from ping_data
          order by user_id, ping_timestamp
       ) t
 group by user_id, rnum
having end_date <= @cut_off
;

その後、user_activity テーブルのデータに基づいて、処理された行を削除できます。

delete t
  from ping_data t
  join ( select user_id
              , max(end_date) max_timestamp
           from user_activity
          group by user_id
       ) ua
    on t.user_id = ua.user_id
 where t.ping_timestamp <= ua.max_timestamp
;
于 2013-10-07T14:57:08.467 に答える
0

挿入、削除、および選択ステートメントを組み合わせることは不可能であることを除けば、とにかくお勧めしません。

よし、一歩一歩…

1位。選択した行を、クエリが返すスキーマとまったく同じ新しいテーブルに挿入します

ここで「トリック」が役に立ちます。クエリを実行しますが、書き込みます

CREATE TABLE new_ping /*or whatever tablename*/ AS
SELECT ...

これにより、テーブルが自動的に作成されます (そしてデータが挿入されます) が、主キーやインデックスが作成されず、データ型が適合しない場合があるため、通常は調整する必要があります。クエリは次のように生成されます (エンジンや文字セットなど、実行時に異なるものがある可能性があります。これらの設定はデフォルト設定に依存します)。

CREATE TABLE `new_ping` (
  `userid` int(11) DEFAULT NULL,
  `groupnum` mediumtext,
  `start_date` int(11) DEFAULT NULL,
  `end_date` int(11) DEFAULT NULL,
  `duration` bigint(12) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8

(上記はクエリで取得できますSHOW CREATE TABLE ping;

テーブルには常に主キーを設定することをお勧めします。useridandgroupnumが良い主キーになるようです。わからない場合は、自動インクリメント列を使用することもできます。とにかく、私はこのようにテーブルを調整します:

DROP TABLE IF EXISTS new_ping;
CREATE TABLE `new_ping` (
  `userid` int(11) DEFAULT NULL,
  `groupnum` mediumtext,
  `start_date` int(11) DEFAULT NULL,
  `end_date` int(11) DEFAULT NULL,
  `duration` int(12) DEFAULT NULL, /*bigint is certainly too big*/
  primary key (userid, groupnum)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

他の列にインデックスを追加したいかもしれません...

新しい create table ステートメントが作成されたので、古いテーブルを削除し、上記のステートメントで (または調整して) 再作成します。DROP TABLE ...ステートメントの上にステートメントを追加することでそうしましたCREATE

次に、データを挿入します。

INSERT INTO new_ping (userid, groupnum, start_date, end_date, duration)
SELECT ... /*the query in your question*/

次のステップ...

2番目。クエリで選択され、新しいテーブルに挿入された、選択された行を削除します。

私はここで少し迷っています。どれを削除しますか? 古いテーブルのものですよね?このsqlfiddleのように。しかし、正確にはどれですか?質問からのクエリは、それらをグループとして表示するだけです。それを片付けてコメントを書いてください、それから私は答え続けます...

于 2013-09-28T11:38:35.213 に答える