【问题标题】:mysql efficient join of 2 tables to the same 2 tablesmysql有效地将2个表连接到相同的2个表
【发布时间】:2013-09-25 17:15:54
【问题描述】:

我有 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的行,并过滤掉“重复”行,如果两行具有相同的值并且它们的日期在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.

不幸的是,这个查询需要一分钟才能运行我的数据集,并且没有返回任何结果(尽管我相信应该有结果)。有没有更有效的方法来执行这个查询?有没有办法命名派生表并稍后在同一查询中引用它?另外,为什么我的查询没有返回结果?

提前感谢您的帮助!

编辑: 我想保留几个时间戳相近的样本中的第一个。

我的 table1 有 610 万行,我的 table2 有 30K,这让我意识到 table2 只有一行用于描述“abc”。这意味着我可以事先查询 descr_id,然后使用该 id 来避免在大查询中加入 table2,从而提高效率。但是,如果我的 table2 的设置如上所述(我承认这将是糟糕的数据库设计),那么执行此类查询的好方法是什么?

【问题讨论】:

  • 您是希望保留几个时间戳接近的样本中的第一个,还是最后一个,或者平均它们的时间戳,还是什么?结果集中应该使用什么时间戳来表示您的每一组样本都靠得很近?
  • 好问题顺便说一句 +1 表有多少条记录?

标签: mysql performance join time-series deduplication


【解决方案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

【讨论】:

  • 请不要使用这种 SQL 反模式...这样做非常糟糕...因为这会导致基于 myisam 磁盘的表...
  • 使用后删除表会更好吗?还是根本不应该使用临时表?
  • 临时表应该避免它可能导致myisam磁盘看到这个dev.mysql.com/doc/refman/5.7/en/internal-temporary-tables.html它max_heap_table_size太小它会发生
【解决方案2】:

尝试使用不存在 就像是 选择 * 从表 1 t1 使用(descr_id)加入 table2 t2 其中 label='abc' 且不存在(选择 * 从表 1 t11 使用(descr_id)加入 table2 t22 其中 label='abc' 和 t1.date t11.date)

您可能需要仔细检查 (t1.date + 间隔 6 分钟) 语法

【讨论】:

    猜你喜欢
    • 2012-12-29
    • 1970-01-01
    • 2019-04-04
    • 1970-01-01
    • 1970-01-01
    • 2012-09-13
    • 2015-05-30
    • 2013-04-19
    相关资源
    最近更新 更多