TOPN 查询是指下面这种 ORDER BY LIMIT 查询,在日志检索等明细查询场景中很常见,Doris 会自动对这种类型的查询进行优化。

1. SELECT * FROM tablex WHERE xxx ORDER BY c1,c2 ... LIMIT n

TOPN 查询优化的优化点

  1. 执行过程中动态对排序列构建范围过滤条件(比如 c1 >= 10000),读数据时自动带上前面的条件,利用 zonemap 索引过滤到一些数据甚至文件。
  2. 如果排序字段c1,c2 正好是table key的前缀,则更进一步优化,读数据的时候只用读数据文件的头部或者尾部n行。
  3. SELECT * 延迟物化,读数据和排序过程中只读排序列不读其它列,得到符合条件的行号后,再去读那n行需要的全部列数据,大幅减少读取和排序的列。

TOPN 查询优化的限制

  1. 只能用于 duplicate 表和 unique mow 表,因为 mor 表用这个优化可能有结果错误。
  2. 对于过大的n,优化内存消耗会很大,所以超过 topn_opt_limit_threshold session 变量的n 不会使用优化。

配置参数和查询分析

下面两个参数都是 session variable,可以针对某个 SQL 或者全局设置。

  1. topn_opt_limit_threshold,LIMIT n 小于这个值才会有优化,默认值1024,将它设置为 0 可以关闭 TOPN 查询优化。
  2. enable_two_phase_read_opt,是否开启优化3,默认为 true,可以调为 false 关闭这个优化。

检查 TOPN 查询优化是否启用

explain SQL 拿到 query plan 可以确认这个sql是否启用 TOPN 查询优化,以下面的为例:

  • TOPN OPT 代表有优化1
  • VOlapScanNode 下面有 SORT LIMIT 代表有优化2
  • OPT TWO PHRASE 代表有优化3
1. 1:VTOP-N(137)
2. |  order by: @timestamp18 DESC
3. |  TOPN OPT
4. |  OPT TWO PHASE
5. |  offset: 0
6. |  limit: 10
7. |  distribute expr lists: applicationName5
8. |
9. 0:VOlapScanNode(106)
10. TABLE: log_db.log_core_all_no_index(log_core_all_no_index), PREAGGREGATION: ON
11. SORT INFO:
12. @timestamp18
13. SORT LIMIT: 10
14. TOPN OPT:1
15. PREDICATES: ZYCFC-TRACE-ID4 like '%flowId-1720055220933%'
16. partitions=1/8 (p20240704), tablets=250/250, tabletList=1727094,1727096,1727098 ...
17. cardinality=345472780, avgRowSize=0.0, numNodes=1
18. pushAggOp=NONE

检查 TOPN 查询优化执行时是否有效果

首先,可以将 topn_opt_limit_threshold 设置为 0 关闭 TOPN 查询优化,对比开启和关闭优化的 SQL 执行时间。

开启 TOPN查询优化后,在 query profile 中搜索 RuntimePredicate,关注下面几个指标:

  • RowsZonemapRuntimePredicateFiltered 这个代表过滤掉的行数,越大越好
  • NumSegmentFiltered 这个代表过滤掉的数据文件个数,越大越好
  • BlockConditionsFilteredZonemapRuntimePredicateTime 代表过滤数据的耗时,越小越好

2.0.3 之前的版本RuntimePredicate的指标没有独立出来,可以通过Zonamap指标大致观察。

1. SegmentIterator:
2. -  BitmapIndexFilterTimer:  46.54us
3. -  BlockConditionsFilteredBloomFilterTime:  10.352us
4. -  BlockConditionsFilteredDictTime:  7.299us
5. -  BlockConditionsFilteredTime:  202.23ms
6. -  BlockConditionsFilteredZonemapRuntimePredicateTime:  0ns
7. -  BlockConditionsFilteredZonemapTime:  402.917ms
8. -  BlockInitSeekCount:  399
9. -  BlockInitSeekTime:  11.309ms
10. -  BlockInitTime:  215.59ms
11. -  BlockLoadTime:  7s567ms
12. -  BlocksLoad:  392.97K  (392970)
13. -  CachedPagesNum:  0
14. -  CollectIteratorMergeTime:  0ns
15. -  CollectIteratorNormalTime:  0ns
16. -  CompressedBytesRead:  29.76  MB
17. -  DecompressorTimer:  427.713ms
18. -  ExprFilterEvalTime:  3s930ms
19. -  FirstReadSeekCount:  392.921K  (392921)
20. -  FirstReadSeekTime:  528.287ms
21. -  FirstReadTime:  1s134ms
22. -  IOTimer:  51.286ms
23. -  InvertedIndexFilterTime:  49.457us
24. -  InvertedIndexQueryBitmapCopyTime:  0ns
25. -  InvertedIndexQueryBitmapOpTime:  0ns
26. -  InvertedIndexQueryCacheHit:  0
27. -  InvertedIndexQueryCacheMiss:  0
28. -  InvertedIndexQueryTime:  0ns
29. -  InvertedIndexSearcherOpenTime:  0ns
30. -  InvertedIndexSearcherSearchTime:  0ns
31. -  LazyReadSeekCount:  0
32. -  LazyReadSeekTime:  0ns
33. -  LazyReadTime:  106.952us
34. -  NumSegmentFiltered:  0
35. -  NumSegmentTotal:  50
36. -  OutputColumnTime:  61.987ms
37. -  OutputIndexResultColumnTimer:  12.345ms
38. -  RawRowsRead:  3.929151M  (3929151)
39. -  RowsBitmapIndexFiltered:  0
40. -  RowsBloomFilterFiltered:  0
41. -  RowsConditionsFiltered:  6.38976M  (6389760)
42. -  RowsDictFiltered:  0
43. -  RowsInvertedIndexFiltered:  0
44. -  RowsKeyRangeFiltered:  0
45. -  RowsShortCircuitPredFiltered:  0
46. -  RowsShortCircuitPredInput:  0
47. -  RowsStatsFiltered:  6.38976M  (6389760)
48. -  RowsVectorPredFiltered:  0
49. -  RowsVectorPredInput:  0
50. -  RowsZonemapRuntimePredicateFiltered:  6.38976M  (6389760)
51. -  SecondReadTime:  0ns
52. -  ShortPredEvalTime:  0ns
53. -  TotalPagesNum:  2.301K  (2301)
54. -  UncompressedBytesRead:  137.99  MB
55. -  VectorPredEvalTime:  0ns