5

この構造に単純化できる 2 つのテーブルがあります。

表1:

+----+----------+---------------------+-------+
| id | descr_id |        date         | value |
+----+----------+---------------------+-------+
| 1  |        1 | 2013-09-20 16:39:06 |     1 |
+----+----------+---------------------+-------+
| 2  |        2 | 2013-09-20 16:44:06 |     1 |
+----+----------+---------------------+-------+
| 3  |        3 | 2013-09-20 16:49:06 |     5 |
+----+----------+---------------------+-------+
| 4  |        4 | 2013-09-20 16:44:06 |   894 |
+----+----------+---------------------+-------+

表 2:

+----------+-------------+
| descr_id | description |
+----------+-------------+
|       1  | abc         |
+----------+-------------+
|       2  | abc         |
+----------+-------------+
|       3  | abc         |
+----------+-------------+
|       4  | DEF         |
+----------+-------------+

説明を table1 に結合し、説明でフィルターして、説明 = abc の行のみを取得し、「重複」行を除外します。ここで、2 つの行が同じ値を持ち、日付が 1 から 6 分以内の場合は重複します。別。私の目的の出力テーブルは以下のとおりです (abc が目的の説明フィルターであると仮定します)。

+----+----------+---------------------+-------+-------------+
| id | descr_id |        date         | value | description |
+----+----------+---------------------+-------+-------------+
| 1  |        1 | 2013-09-20 16:39:06 |     1 | abc         |
+----+----------+---------------------+-------+-------------+
| 3  |        3 | 2013-09-20 16:49:06 |     5 | abc         |
+----+----------+---------------------+-------+-------------+

私が思いついたクエリは次のとおりです。

select * 
  from (
        select * 
          from table1 
          join table2 using(descr_id) 
         where label='abc'
       ) t1 
  left join (
        select * 
          from table1 
          join table2 using(descr_id) 
         where label='abc'
        ) t2 on( t1.date<t2.date and t1.date + interval 6 minute > t2.date) 
 where t1.value=t2.value.

残念ながら、このクエリは私のデータセットで実行するのに 1 分以上かかり、結果が返されません (結果があるはずですが)。このクエリを実行するより効率的な方法はありますか? 派生テーブルに名前を付けて、後で同じクエリで参照する方法はありますか? また、クエリが結果を返さないのはなぜですか?

助けてくれてありがとう!

編集:タイムスタンプが近いいくつかのサンプルの最初のものを保持したいと思います。

テーブル 1 には 610 万行、テーブル 2 には 30K の行があるため、テーブル 2 には "abc" という説明の行が 1 つしかないことがわかります。これは、事前に descr_id をクエリしてから、その id を使用して大きなクエリで table2 をまったく結合しないようにすることで、はるかに効率的にできることを意味します。ただし、私の table2 が上記のように設定されている場合 (これはデータベース設計が不十分であることは認めます)、そのようなクエリを実行する良い方法は何ですか?

4

2 に答える 2

1

一時テーブルを作成し、一時テーブルに結合してみてください。

CREATE TEMPORARY TABLE t1 AS (select * 
          FROM table1 
          JOIN table2 USING(descr_id) 
         WHERE label='abc')

CREATE TEMPORARY TABLE t2 AS (select * 
          FROM table1 
          JOIN table2 USING(descr_id) 
         WHERE label='abc')

SELECT *
FROM t1
LEFT JOIN t2 on( t1.date<t2.date and t1.date + interval 6 minute > t2.date) 
WHERE t1.value=t2.value

データベースから切断すると、一時テーブルは自動的にクリーンアップされるため、明示的に削除する必要はありません。

私はもともとこれを持っていましたが、完全な要件を満たしているとは思いません:

SELECT t1.id,
       t1.descr_id,
       t1.date,
       t1.value,
       t2.description
FROM table1 t1
JOIN table2 t2 ON t1.descr_id = t2.descr_id
WHERE t2.description = 'abc' 

これは基本的に元のクエリと同じですが、別のオプションとして、ビューを作成し、次のようにビューに結合することもできます。

CREATE VIEW v1 AS
SELECT * FROM table1 JOIN table2 USING(descr_id) WHERE label='abc'

CREATE VIEW v2 AS
SELECT * FROM table1 JOIN table2 USING(descr_id) WHERE label='abc'

SELECT *
FROM v1
LEFT JOIN v2 on( v1.date<v2.date and v1.date + interval 6 minute > v2.date) 
WHERE v1.value=v2.value

また、このクエリを定期的に実行する場合は、最初のクエリの結果をステージング テーブルにロードし、次のようにステージング テーブルで結合を行うことを検討してください。

INSERT INTO staging
(SELECT * 
        FROM table1 
        JOIN table2 USING(descr_id) 
        WHERE label='abc')

SELECT *
    FROM staging s1
    LEFT JOIN staging s2 on( s1.date<s2.date and s1.date + interval 6 minute > s2.date) 
    WHERE s1.value=s2.value

TRUNCATE TABLE staging
于 2013-09-25T17:32:19.720 に答える
0

select * from table1 t1 join table2 t2 using(descr_id) where label='abc' and not exists (select * from table1 t11 join table2 t22 using(descr_id) where label='abc' and t1.日付 < t11.date および t1.date + 間隔 6 分 > t11.date)

(t1.date + interval 6 minutes) 構文を再確認する必要がある場合があります

于 2014-04-24T14:35:57.887 に答える