0

この質問は、私の前の質問に非常に関連しています。MySQL、Xの最後の数時間以内にすべての結果を返しますが、追加の重要な制約があります。

これで、2つのテーブルがあります。1つは測定用で、もう1つは測定の一部の分類結果用です。

その結果、測定値は常に到着し、新しい測定値の分類後に常に追加されます。

結果は、必ずしも測定の到着と保存の順序で同じ順序で保存されるとは限りません。

最後の結果を提示することだけに興味があります。最後に、最後に利用可能な結果の最大時間(時間は測定構造の一部です)をYとX秒の範囲と呼び、YとYXの範囲で利用可能な結果と一緒に測定値を提示することを意味します。

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

イベントテーブル:

CREATE TABLE `event_data` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `Feature` char(256) NOT NULL,
  `UnixTimeStamp` int(10) unsigned NOT NULL,
  `Value` double NOT NULL,

  KEY `ix_filter` (`Feature`),
  KEY `ix_time` (`UnixTimeStamp`),
  KEY `id_index` (`id`)
) ENGINE=MyISAM

分類された結果の表:

CREATE TABLE `event_results` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `level` enum('NORMAL','SUSPICIOUS') DEFAULT NULL,
  `score` double DEFAULT NULL,
  `eventId` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `eventId_index` (`eventId`)
) ENGINE=MyISAM

現在結果がある測定値を表示したいので、最初に最後の測定値のタイムスタンプを照会できません。また、測定値が常に到着するため、結果がまだ利用できない場合があります。

したがって
event_results.eventId=event_data.id、最大時間を使用して2つのテーブルを結合することを考えevent_data.UnixTimeStamp as maxTimeました。maxTimeを取得した後、同じ操作を再度実行し(2つのテーブルを結合)、where句に条件を追加する必要があります。

WHERE event_data.UnixTimeStamp >= maxTime + INTERVAL -X SECOND

私が求めていることを達成するためだけに2つの結合を実行するのは効率的ではないようです。もっと効果がありますか

4

2 に答える 2

1

返される結果セットが完全にはわからないので、いくつかの仮定を立てます。私が行った仮定を自由に修正してください。

(私には)event_data絶対的な「最新の」タイムスタンプから1時間以内(または数秒以内)のすべての行が必要であり、それらの行とともに、event_results一致する場合はからの関連行も返したいように思えます。行が利用可能です。

その場合は、インラインビューを使用してタイムスタンプの最大値を取得するのが最善の方法です。(クエリは単一の行を返すため、この操作は非常に効率的であり、既存のインデックスから効率的に取得できます。)

指定された期間(「最新の時間」から「最新の時間からX秒を引いたもの」まで)のすべての行が必要なため、同じクエリでその期間の開始タイムスタンプを計算できます。ここでは、1時間(= 60 * 60秒)「戻る」ことを想定しています。

SELECT MAX(UnixTimeStamp) - 3600 FROM event_data

UnixTimeStamp注:上記のSELECTリストの式は、DATETIMEまたはTIMESTAMPデータ型ではなく、整数型として定義された列に基づいています。列がDATETIMEまたはTIMESTAMPデータ型として定義されている場合、次のように表現する可能性があります。

SELECT MAX(mydatetime) + INTERVAL -3600 SECONDS

(間隔の単位は分、時間などで指定できます)

そのクエリの結果を別のクエリで使用できます。同じクエリテキストでこれを行うには、そのクエリをかっこで囲み、そのクエリが実際のテーブルであるかのように行ソースとして参照します。event_dataこれにより、次のように、指定された期間内にあるすべての行を取得できます。

SELECT d.id
     , d.Feature
     , d.UnixTimeStamp
     , d.Value
  JOIN ( SELECT MAX(l.UnixTimeStamp) - 3600 AS from_unixtimestamp
           FROM event_data l
       ) m
  JOIN event_data d
    ON d.UnixTimetamp >= m.from_unixtimestamp

この特定のケースでは、外部クエリのUnixTimeStamp列に上限の述語は必要ありません。これは、関心のある期間の上限であるMAX(UnixTimeStamp)よりも大きいUnixTimeStampの値がないことをすでに知っているためです。

(インラインビューのSELECTリストに式を追加して、を返しMAX(l.UnixTimeStamp) AS to_unixtimestamp、外部クエリのように述語を含めるAND d.UnixTimeStamp <= m.to_unixtimestampことができますが、これは不必要に冗長になります。)

event_resultsまた、テーブルから情報を返すための要件を指定しました。

「利用可能な」関連行が必要だとおっしゃっていたと思います。これは、(私にとって)一致する行がから「利用可能」event_resultsでない場合でも、テーブルから行を返したいことを示唆していevent_dataます。

LEFT JOIN操作を使用して、それを実現できます。

SELECT d.id
     , d.Feature
     , d.UnixTimeStamp
     , d.Value
     , r.id
     , r.level
     , r.score
     , r.eventId
  JOIN ( SELECT MAX(l.UnixTimeStamp) - 3600 AS from_unixtimestamp
           FROM event_data l
       ) m
  JOIN event_data d
    ON d.UnixTimetamp >= m.from_unixtimestamp
  LEFT
  JOIN event_results r
    ON r.eventId = d.id

eventIDテーブルの列には一意の制約がないためevent_results、event_resultsから複数の「一致する」行が見つかる可能性があります。それが発生するたびに、event_dataテーブルからの行が、からの一致する行ごとに1回繰り返されevent_resultsます。

からの一致する行がない場合でもevent_results、からの行event_dataが返されますが、テーブルの列はevent_resultsNULLに設定されます。

パフォーマンスを向上させるために、返される必要のない列をSELECTリストから削除し、ORDERBY句での式の選択に注意してください。(カバーインデックスを追加すると、パフォーマンスが向上する場合があります。)

上記のステートメントの場合、MySQLはテーブルのインデックスとテーブルのix_timeインデックスを使用する可能性があります。event_dataeventId_indexevent_results

于 2013-02-14T21:10:58.393 に答える
1

私の理解では、集計関数を使用していますMAX。これにより、結果としてサイズ 1 のレコード セットが生成されます。これは、実行する最高時間です。したがって、サブクエリに分割する必要があります(あなたが言うように、ネストされた選択)。ある時点で 2 つのクエリを実行する必要があります。(最後の質問への回答には、サブクエリ/ネストされた選択があることにより、2つのクエリが含まれています)。

サブクエリが問題を引き起こす主な時期は、クエリの選択部分でサブクエリを実行するときです。これは、行が存在するたびにサブクエリを実行するため、結果セットが大きくなるにつれてクエリの実行が指数関数的に遅くなります。最後の質問の答えを、恐ろしく非効率な方法で書きましょう。

SELECT timeStart, 
       (SELECT max(timeStart) FROM events) AS maxTime
FROM events
WHERE   timeStart > (maxTime + INTERVAL -1 SECOND)

これにより、eventTime レコードが存在するたびに、最大 eventtime に対して選択クエリが実行されます。同じ結果が得られるはずですが、これは遅いです。これが、サブクエリの恐怖の源です。

また、MAX各行で集計関数を実行し、毎回同じ回答を返します。したがって、各行ではなく、そのサブクエリを 1 回実行します。

ただし、最後の質問の回答の場合、MAXサブクエリ部分は1回実行され、その選択が1回実行される場所でフィルタリングするために使用されます。したがって、合計で 2 つのクエリが実行されます。

2 つの超高速クエリは、超低速の 1 つの超低速クエリよりも高速に実行されます。

于 2013-02-11T13:29:12.697 に答える