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