1、Prewhere替代where
Prewhere和where语句的作用相同,用来过滤数据。不同之处在于prewhere只支持 *MergeTree 族系列引擎的表,首先会读取指定的列数据,来判断数据过滤,等待数据过滤之后再读取select 声明的列字段来补全其余属性。当查询列明显多于筛选列时使用Prewhere可十倍提升查询性能,Prewhere会自动优化执行过滤阶段的数据读取方式,降低io操作。在某些场合下,prewhere语句比where语句处理的数据量更少性能更高。EXPLAIN SYNTAX select WatchID, JavaEnable, Title, GoodEvent, EventTime, EventDate, CounterID, ClientIP, ClientIP6, RegionID, UserID, CounterClass, OS, UserAgent, URL, Referer, URLDomain, RefererDomain, Refresh, IsRobot, RefererCategories, URLCategories, URLRegions, RefererRegions, ResolutionWidth, ResolutionHeight, ResolutionDepth, FlashMajor, FlashMinor, FlashMinor2 from datasets.hits_v1 where UserID='3198390223272470366'; 自动优化 from datasets.hits_v1 PREWHERE UserID = '3198390223272470366';set optimize_move_to_prewhere=0; 关闭自动优化后不会转变 PREWHERE 默认情况,我们肯定不会关闭where自动优化成prewhere,但是某些场景即使开启优化,也不会自动转换成prewhere,需要手动指定prewhere:
- 使用常量表达式
- 使用默认值为alias类型的字段
- 包含了arrayJOIN,globalIn,globalNotIn或者indexHint的查询
- select查询的列字段和where的谓词相同
- 使用了主键字段
2 数据采样
通过采样运算可极大提升数据分析的性能SELECT Title,count(*) AS PageViews FROM hits_v1 SAMPLE 0.1 #代表采样10%的数据,也可以是具体的条数 WHERE CounterID =57 GROUP BY Title ORDER BY PageViews DESC LIMIT 1000采样修饰符只有在MergeTree engine表中才有效,且在创建表时需要指定采样策略。
3 列裁剪与分区裁剪
数据量太大时应避免使用select * 操作,查询的性能会与查询的字段大小和数量成线性表换,字段越少,消耗的io资源越少,性能就会越高。反例: select * from datasets.hits_v1; 正例: select WatchID, JavaEnable, Title, GoodEvent, EventTime, EventDate, CounterID, ClientIP, ClientIP6, RegionID, UserID from datasets.hits_v1;分区裁剪就是只读取需要的分区,在过滤条件中指定。
select WatchID, JavaEnable, Title, GoodEvent, EventTime, EventDate, CounterID, ClientIP, ClientIP6, RegionID, UserID from datasets.hits_v1 where EventDate='2022-08-23';
4 orderby 结合 where、limit
千万以上数据集进行order by查询时需要搭配where条件和limit语句一起使用#正例: SELECT UserID,Age FROM hits_v1 WHERE CounterID=57 ORDER BY Age DESC LIMIT 1000 #反例: SELECT UserID,Age FROM hits_v1 ORDER BY Age DESC
5 避免构建虚拟列
如非必须,不要在结果集上构建虚拟列,虚拟列非常消耗资源浪费性能,可以考虑在前端进行处理,或者在表中构造实际字段进行额外存储。反例: SELECT Income,Age,Income/Age as IncRate FROM datasets.hits_v1; 正例:拿到Income和Age后,考虑在前端进行处理,或者在表中构造实际字段进行额外存储 SELECT Income,Age FROM datasets.hits_v1;
6 uniqCombined替代distinct
性能可提升10倍以上,uniqCombined底层采用类似HyperLogLog算法实现,能接收2%左右的数据误差,可直接使用这种去重方式提升查询性能。Count(distinct )会使用uniqExact精确去重。不建议在千万级不同数据上执行distinct去重查询,改为近似去重uniqCombined反例: select count(distinct rand()) from hits_v1; 正例: SELECT uniqCombined(rand()) from datasets.hits_v1