【问题标题】:Check existence of distinct values for each group检查每个组是否存在不同的值
【发布时间】:2016-01-12 16:29:06
【问题描述】:

编辑:

假设我在 MySQL 中有下表:

CREATE TABLE `events` (
`pv_name` varchar(60) COLLATE utf8mb4_unicode_ci NOT NULL,
`time_stamp` bigint(20) UNSIGNED NOT NULL,
`value` text CHARACTER SET utf8mb4 COLLATE utf8mb4_bin,
PRIMARY KEY (`pv_name`, `time_stamp`)
) ENGINE=InnoDB;

我可以使用以下查询在此表中找到具有多个不同 value 的每个 pv_name

SELECT events.pv_name
FROM events
GROUP BY events.pv_name
HAVING COUNT(DISTINCT events.value) > 1;

问题是这个查询效率不高。它计算所有不同的值,而不是在找到多个值后停止。

一个建议如下:

SELECT events.pv_name
FROM events
GROUP BY events.pv_name
HAVING MIN(events.value) < MAX(events.value);

如果索引包含value,这是有效的。但是,value 是文本列,所以不能。

是否有其他方法可以提高搜索效率?也许某种形式的相关子查询?我想继续使用 MySQL,但如果另一个数据库服务器中有一个功能可以帮助我,我可能会考虑迁移到它。

【问题讨论】:

  • 插入的频率如何?时效准确度要求是什么?
  • 对于插入率,我没有一个好的固定数字。它可以与数据库允许的一样快。不知道你说的及时准确是什么意思?
  • 统计数据的准确性是否存在滞后。这种类型的信息排除或使不同的策略成为可能
  • SELECT * FROM Customers GROUP BY pv_name HAVING MIN(time_stamp ) &lt; MAX(time_stamp ) ;你有 time_stamp 的价值
  • @Drew:如果您的意思是这样的话,假设在查询时表被冻结是没有问题的?也就是说,您可以忽略在执行查询期间可能添加的任何行。

标签: mysql sql group-by query-optimization distinct


【解决方案1】:

要回答您的问题,最好避免使用group bydistinct。不过,首先,我建议为表添加一个自动递增的event_id。这样就可以确定两行是否相同。

所以,我建议以下查询:

select e.*
from events e
where e.time_stamp between $ts1 and $ts2 and
      exists (select 1
              from events e2
              where e2.pv_name = e.pv_name and
                    e2.time_stamp between $ts1 and $ts2 and
                    e2.event_id < e.event_id
             );

您还需要索引:events(time_stamp, pv_name, event_id)events(pv_name, time_stamp, event_id)

这会找到成对的事件。您可以使用select distinct pv_name。但是,这会产生大量额外的处理来删除重复项。

【讨论】:

  • 这似乎没有比较值?
  • 比较什么值?您的问题是关于获取姓名列表。
  • 在给定时间间隔内具有多个不同值的名称。
【解决方案2】:
SELECT * FROM Customers WHERE pv_name IN
(SELECT pv_name FROM Customers GROUP BY pv_name HAVING COUNT(*) > 1) AND
 time_stamp BETWEEN 'start_time' and `end_time'

SELECT * FROM Customers GROUP BY pv_name HAVING MIN(time_stamp ) < MAX(time_stamp );

这可能有效。

【讨论】:

    【解决方案3】:

    我相信以下可能有效?可以改进吗?

    -- Chooses a single non null `value` from the `events` table for each `pv_name`.
    CREATE TEMPORARY TABLE single_values ( PRIMARY KEY (pv_name) ) ENGINE=Memory AS (
    SELECT events.pv_name, events.value
    FROM events
    WHERE events.value IS NOT NULL
    GROUP BY events.pv_name );
    
    -- Finds each `pv_name` that has a `value` different than the one for it in `single_values`.
    -- This is a correlated subquery.
    SELECT single_values.pv_name
    FROM single_values
    WHERE 1 = (
    SELECT 1
    FROM events
    WHERE events.pv_name = single_values.pv_name
    AND events.value <> single_values.value
    AND events.value IS NOT NULL
    LIMIT 1 );
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-02-14
      • 1970-01-01
      • 2014-05-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-08-11
      相关资源
      最近更新 更多