本文介绍优化查询的方法,用于提高查询效率。

增加Shard数量

Shard表示计算资源,Shard越多,计算越快,您需要保证平均每个Shard扫描的数据不多于5000万条。您可以通过分裂Shard,增加Shard数量。具体操作,请参见分裂Shard
注意 分裂Shard会产生更多费用,且只对新数据起到加速效果,旧数据仍然在旧Shard中。

缩减查询的时间范围和数据量

  • 时间范围越大,查询越慢。

    适当缩短查询的时间范围可以更快地完成计算。

  • 数据量越大,查询越慢。

    请尽量减少查询的数据量。

多次重复查询

当查询不精确时,可以尝试多次重复查询。每次查询时,底层加速机制会充分利用已有的结果进行分析,因此多次查询可以使结果更加精确。

优化SQL分析语句

计算时间较长的查询分析语句具备如下特点。
  • 使用GROUP BY语法对字符串列进行分组统计。
  • 使用GROUP BY语法对多列(大于5列)字段进行分组统计。
  • 在SQL分析语句中有生成字符串的操作。
您可以通过如下方法优化分析语句。
  • 尽量避免生成字符串的操作。
    例如使用date_format函数生成格式化的时间戳,导致查询效率低。针对时间戳的计算,建议使用date_trunc或者time_series函数进行计算。
    * | select date_format(from_unixtime(__time__) , '%H_%i') as t, count(1) group by t
  • 尽量避免对字符串列进行分组统计。

    使用GROUP BY语法对字符串列进行分组统计,会导致大量的Hash计算,这部分计算量占据整体计算量的50%以上。示例如下:

    • 查询和分析语句(速度快)
      * | select count(1) as pv , from_unixtime(__time__-__time__%3600) as time group by __time__-__time__%3600
    • 查询和分析语句(速度慢)
      * | select count(1) as pv , date_trunc('hour',__time__) as time group by time

    上述两条查询分析语句都是计算每小时的日志条数。第二条语句先把时间戳转化成字符串格式(例如2021-12-12 00:00:00),然后对这个字符串列进行分组统计。第一条语句对时间整点值进行计算,并且通过分组统计后再将时间戳转化为字符串格式。

  • 对多列进行分组统计时,把字典大的字段放在前面。
    例如字段的值有13个,uid字段的值有1亿个,则建议在GROUP BY子句中将uid字段放在前面。示例如下:
    • 查询和分析语句(速度快)
      * | select province,uid,count(1) group by uid,province
    • 查询和分析语句(速度慢)
       * | select province,uid,count(1) group by province,uid
  • 使用估算函数。
    估算函数的性能比精算函数的好。估算会损失一定的精确度,用于达到快速计算的效果。示例如下:
    • 查询和分析语句(速度快)
       * |select approx_distinct(ip)
    • 查询和分析语句(速度慢)
       * | select count(distinct(ip))
  • 在SQL分析语句中指定获取需要的列,尽量不要读取所有列。
    在SQL分析语句中,尽量只读取需要参与计算的列。如果要获取所有列,请使用查询语法。
    • 查询和分析语句(速度快)
      * |select a,b c 
    • 查询和分析语句(速度慢)
      * |select *
  • 不是用于分组的列,尽量放在聚合函数中。
    例如userid与用户名必定是一一对应的,您只需使用GROUP BY语法对userid进行分组统计即可。示例如下:
    • 查询和分析语句(速度快)
       * | select userid, arbitrary(username), count(1) group by userid 
    • 查询和分析语句(速度慢)
      * | select userid, username, count(1) group by userid,username
  • 尽量避免使用IN语法
    尽量避免在分析语句中使用IN语法,您可以在查询语句中使用OR语法代替。示例如下:
    • 查询和分析语句(速度快)
      key: a or key: b or key: c | select count(1)
    • 查询和分析语句(速度慢)
      * | select count(1) where key in ('a','b')