2017-08-29 2972 views
0

我有一个聚合了一些UNION ALL选择的子查询。在此之前,我准备了SELECT来创建交叉表并将其限制为20.我希望能够在主查询中限制它们之前检索子查询结果的总计数。这是为了尝试构建一个分页,它接收记录的总数,然后是特定的页面记录网格。在应用LIMIT(clickhouse)之前对子查询进行SELECT计数

样品查询:

SELECT 
    name, 
    sumIf(metric_value, metric_name = 'data') AS data, 
    sumif(.... 
FROM 
    (SELECT 
     name, metric_name, SUM(metric_value) as metric_value 
    FROM 
     (SELECT 
       name, 'data' AS metric_name, SUM(data) AS metric_value 
      FROM 
       table 
      WHERE 
       date > '2017-01-01 00:00:00' 
      GROUP BY 
       name 

      UNION ALL 

      SELECT 
       name, 'data' AS metric_name, SUM(data) AS metric_value 
      FROM 
       table2 
      WHERE 
       date > '2017-01-01 00:00:00' 
      GROUP BY 
       name 

      UNION ALL 

      SELECT 
       name, 'data' AS metric_name, SUM(data) AS metric_value 
      FROM 
       table3 
      WHERE 
       date > '2017-01-01 00:00:00' 
      GROUP BY 
       name 

      UNION ALL 

      . 
      . 
      .) 
    GROUP BY 
     name, metric_name) 
GROUP BY 
    name 
ORDER BY 
    name ASC 
LIMIT 0,20; 

第一个子查询返回大量数据的,所以我想我可以指望它并返回作为一个列值,或行,它会传播到主选择限制20个结果。因为我需要知道整个结果集,但不希望两次调用同一个查询而没有限制,仅限于获取COUNT。至少有12个UNION ALL三级子选择,为什么浪费资源。我期待尝试通用SQL解决方案不一定与ClickHouse

我想使用count(*) OVER(),但不支持,所以如果这只是选项,我知道我需要运行查询两次。

+0

是否SQL_CALC_FOUND_ROWS帮助吗?这个场景就是它的设计目的。您使用该选项运行查询,然后SELECT FOUND_ROWS()将为您提供LIMIT应用之前的总行数(不需要再次运行查询)。 https://dev.mysql.com/doc/refman/5.7/en/information-functions.html#function_found-rows – EdmCoff

+0

您可能想要加入相同的联合子查询,但这次要获得结果数。 – Lamar

+0

感谢您的评论,我不知道SQL_CALC_FOUND_ROWS存在。它可以解决问题,任何人都可以使用支持该命令的数据库。我正在使用的ClickHouse是基于列的,并且未实现。 – OscarHanzely

回答

0

应该提到的第一件事是,没有人通常对查询的确切页数感兴趣。它可以很容易地估计,几乎没有人会关心估计的确切程度。但是,如果您有一个链接到GUI中的最后一页,人们通常会点击链接来查看它是否有效。

尽管如此,有些情况下分析人员应该访问所有页面,然后GUI应显示确切的工作量。好消息是,在后一种情况下,更好的策略是缓存整个结果表的快照并计算表中的行不再成为问题。

我的意思是,与客户讨论他们是否真的需要它是有意义的,因为每天多次不必要的全面扫描可能会影响数据库负载和计费总额。

无论如何,如果您仍然需要估计行数,您可以简化查询以计算行数。据我所知,这是一样的东西:

SELECT SUM(cnt) as row_count 
FROM (
    SELECT COUNT(DISTINCT name) as cnt FROM table1 WHERE date > ... 
    UNION ALL 
    SELECT COUNT(DISTINCT name) as cnt FROM table2 WHERE date > ... 
    ... 
) as counts; 

,或者如果data是恒定的指标名称

SELECT COUNT(DISTINCT name) as row_count 
FROM (
    SELECT DISTINCT name FROM table1 WHERE date > ... 
    UNION ALL 
    SELECT DISTINCT name FROM table2 WHERE date > ... 
    ... 
) as names; 
+0

谢谢@newtover,我读过与之前开始一样的陈述,虽然您是对的,并且我同意不需要知道确切的结果/页面,但这是在用于统计数据计费统计作为主要参数的系统中。话虽如此,分组sql的最大结果数量预计将小于5000,并且由于日期限制,客户端可能仅将数据拉到几百个最大值。这很容易让他们看到那几页的记录,它需要精确,因为它可能会导致最后一页的问题。 – OscarHanzely

+0

你的建议几乎总结了理论,我需要在数据库上运行单个相同结构的命令以获得总体结果。计数可能会有所帮助,但加载将仍然存在,我目前正在查看ClickHouse,如果它兑现了subquerries的结果,那么执行它两次没有什么大不了的。然而,我们将要处理的行数量估计在分布式碎片上大约为2000万。所以需要进行一些性能测试。 – OscarHanzely