2016-12-01 4 views
0

I MySQLでの次の表があります。MySQLは、時間間隔でグループごとの値の明確なペアを見つける

CREATE TABLE `events` (
    `pv_name` varchar(60) COLLATE utf8mb4_bin NOT NULL, 
    `time_stamp` bigint(20) unsigned NOT NULL, 
    `event_type` varchar(40) COLLATE utf8mb4_bin NOT NULL, 
    `has_data` tinyint(1) NOT NULL, 
    `data` json DEFAULT NULL 
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin ROW_FORMAT=COMPRESSED; 

ALTER TABLE `events` 
ADD PRIMARY KEY (`pv_name`,`time_stamp`), ADD KEY `has_data` (`has_data`,`pv_name`,`time_stamp`); 

が、私は価値の少なくとも1つの変更があり、各pv_nameを見つけるために、効率的なクエリを構築するために苦労してきました所与の時間間隔で、

私はそれではなく、すぐにそれを超えるものを見つけると停止の各pv_nameための一定の時間間隔で個別値のすべてを、見つけたので、私は現在持っているクエリが非効率的であると信じています:

SELECT events.pv_name 
FROM events 
WHERE events.time_stamp > 0 AND events.time_stamp < 9999999999999999999 
GROUP BY events.pv_name 
HAVING COUNT(DISTINCT JSON_EXTRACT(events.data, '$.value')) > 1; 

DISTINCTとLIMITのROW_COUNTを組み合わせる場合

は、MySQLは、すぐにそれがROW_COUNTユニークな行を検索 として停止します。ドキュメントは、と言っているので、これを避けるために、私は、別々のステップに数と異なる部分を壊し検討しています

一定の時間間隔で各pv_nameための個別値のすべてを見つけることはありません与えられた時間間隔で各pv_nameのために異なる値のペアを見つけるための効率的なクエリがありますか?

EDIT @Rickジェームズ

私は基本的に、このためのより高速な非カーソルベースのソリューションを見つけようとしています

SET @[email protected]@sql_mode, sql_mode='STRICT_ALL_TABLES'; 

DELIMITER // 

DROP PROCEDURE IF EXISTS check_for_change; 
CREATE PROCEDURE check_for_change(IN t0_in bigint(20) unsigned, IN t1_in bigint(20) unsigned) 
BEGIN 
    DECLARE done INT DEFAULT FALSE; 
    DECLARE current_pv_name VARCHAR(60); 
    DECLARE cur CURSOR FOR SELECT DISTINCT pv_name FROM events; 
    DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET done = TRUE; 

    SET @t0_in := t0_in; 
    SET @t1_in := t1_in; 


    IF @t0_in > @t1_in THEN 
     SET @temp := @t0_in; 
     SET @t0_in := @t1_in; 
     SET @t1_in := @temp; 
    END IF; 


    DROP TEMPORARY TABLE IF EXISTS has_change; 
    CREATE TEMPORARY TABLE has_change (
    pv_name varchar(60) NOT NULL, 
    PRIMARY KEY (pv_name) 
    ) ENGINE=Memory DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; 


    OPEN cur; 

    label1: LOOP 
     FETCH cur INTO current_pv_name; 

     IF done THEN 
      LEAVE label1; 
     END IF; 

     INSERT INTO has_change 
     SELECT current_pv_name 
     FROM (
     SELECT DISTINCT JSON_EXTRACT(events.data, '$.value') AS distinct_value 
     FROM events 
     WHERE events.pv_name = current_pv_name 
     AND events.has_data = 1 
     AND events.time_stamp > @t0_in AND events.time_stamp < @t1_in 
     LIMIT 2) AS t 
     HAVING COUNT(t.distinct_value) = 2; 
    END LOOP; 

    CLOSE cur; 
END // 

DELIMITER ; 

SET [email protected]_sql_mode; 

ここでの最適化は、個別値の数に制限の適用であります各pv_nameを見つける。

+0

「別個の値のペア」は、「変更のあるものを見つける」と同じことを私に言いません。サンプルデータとサンプル出力を提供してください。 –

+0

間隔で変更された値のペアが、間隔で変更された値よりもある場合。 – Patrick

+0

@RickJames質問を編集しました。私はこれがそれを明確にするのを助けることを望みますか? – Patrick

答えて

0

LIMITはありません。したがって、この見積もりは適用されません。 (または、少なくとも私はそうではないと思う)。

COUNT(DISTINCT ...)場合によっては、すべての行を読み込むよりも優れた「ルーズスキャン」を実行することもあります。たとえば、INDEX(name, foo)とともに

SELECT name 
    FROM tbl 
    GROUP BY name 
    HAVING COUNT(DISTINCT foo) > 3; 

は、おそらく各nameためfoosCOUNT DISTINCTを行うには、インデックスを通じて飛び越すでしょう。確かに、これはあなたが要求したように「3時に止まる」わけではありません。

あなたはそれがなかった(またはしなかった)ことを確認するには

FLUSH STATUS; 
SELECT ...; 
SHOW SESSIONS STATUS LIKE 'Handler%'; 

を行うことによって上記を発揮することができますが、テーブルの大きさであるHandler_read数を持っています。

ルーズスキャンは、複数の理由で特定のクエリには適用されません。

ボトムライン:「いいえ、目標を達成できません」

また、書き込んだストアドルーチンは、フルスキャンのオーバーヘッドを単に受け入れるよりもはるかに時間がかかります。

+0

私は 'COUNT(DISTINCT ...) 'を使うと' LIMIT'を追加しても役に立たないと言っていましたが、 'DISTINCT'だけを使った別のクエリを作成した場合、' LIMIT'をそれは助けになります(見積もりごとに)。そして、その結果に 'COUNT'を実行することができます。それが私が本質的にストアドプロシージャで行ったことです。 – Patrick

+0

2つのクエリの相対速度は、反復する名前の数と時間間隔のサイズによって異なります。両方が小さい場合は、最初に投稿したクエリが速く、両方が大きい場合はカーソルのアプローチが速く、時にははるかに高速です。 – Patrick

+0

別の質問として、カーソルベースのアプローチ、すなわち並列化を改善する他の方法がありますか? – Patrick

関連する問題