execution_plan_fast_path_test.go 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. package engine
  2. import (
  3. "testing"
  4. "github.com/seaweedfs/seaweedfs/weed/pb/schema_pb"
  5. "github.com/stretchr/testify/assert"
  6. )
  7. // TestExecutionPlanFastPathDisplay tests that the execution plan correctly shows
  8. // "Parquet Statistics (fast path)" when fast path is used, not "Parquet Files (full scan)"
  9. func TestExecutionPlanFastPathDisplay(t *testing.T) {
  10. engine := NewMockSQLEngine()
  11. // Create realistic data sources for fast path scenario
  12. dataSources := &TopicDataSources{
  13. ParquetFiles: map[string][]*ParquetFileStats{
  14. "/topics/test/topic/partition-1": {
  15. {
  16. RowCount: 500,
  17. ColumnStats: map[string]*ParquetColumnStats{
  18. "id": {
  19. ColumnName: "id",
  20. MinValue: &schema_pb.Value{Kind: &schema_pb.Value_Int64Value{Int64Value: 1}},
  21. MaxValue: &schema_pb.Value{Kind: &schema_pb.Value_Int64Value{Int64Value: 500}},
  22. NullCount: 0,
  23. RowCount: 500,
  24. },
  25. },
  26. },
  27. },
  28. },
  29. ParquetRowCount: 500,
  30. LiveLogRowCount: 0, // Pure parquet scenario - ideal for fast path
  31. PartitionsCount: 1,
  32. }
  33. t.Run("Fast path execution plan shows correct data sources", func(t *testing.T) {
  34. optimizer := NewFastPathOptimizer(engine.SQLEngine)
  35. aggregations := []AggregationSpec{
  36. {Function: FuncCOUNT, Column: "*", Alias: "COUNT(*)"},
  37. }
  38. // Test the strategy determination
  39. strategy := optimizer.DetermineStrategy(aggregations)
  40. assert.True(t, strategy.CanUseFastPath, "Strategy should allow fast path for COUNT(*)")
  41. assert.Equal(t, "all_aggregations_supported", strategy.Reason)
  42. // Test data source list building
  43. builder := &ExecutionPlanBuilder{}
  44. dataSources := &TopicDataSources{
  45. ParquetFiles: map[string][]*ParquetFileStats{
  46. "/topics/test/topic/partition-1": {
  47. {RowCount: 500},
  48. },
  49. },
  50. ParquetRowCount: 500,
  51. LiveLogRowCount: 0,
  52. PartitionsCount: 1,
  53. }
  54. dataSourcesList := builder.buildDataSourcesList(strategy, dataSources)
  55. // When fast path is used, should show "parquet_stats" not "parquet_files"
  56. assert.Contains(t, dataSourcesList, "parquet_stats",
  57. "Data sources should contain 'parquet_stats' when fast path is used")
  58. assert.NotContains(t, dataSourcesList, "parquet_files",
  59. "Data sources should NOT contain 'parquet_files' when fast path is used")
  60. // Test that the formatting works correctly
  61. formattedSource := engine.SQLEngine.formatDataSource("parquet_stats")
  62. assert.Equal(t, "Parquet Statistics (fast path)", formattedSource,
  63. "parquet_stats should format to 'Parquet Statistics (fast path)'")
  64. formattedFullScan := engine.SQLEngine.formatDataSource("parquet_files")
  65. assert.Equal(t, "Parquet Files (full scan)", formattedFullScan,
  66. "parquet_files should format to 'Parquet Files (full scan)'")
  67. })
  68. t.Run("Slow path execution plan shows full scan data sources", func(t *testing.T) {
  69. builder := &ExecutionPlanBuilder{}
  70. // Create strategy that cannot use fast path
  71. strategy := AggregationStrategy{
  72. CanUseFastPath: false,
  73. Reason: "unsupported_aggregation_functions",
  74. }
  75. dataSourcesList := builder.buildDataSourcesList(strategy, dataSources)
  76. // When slow path is used, should show "parquet_files" and "live_logs"
  77. assert.Contains(t, dataSourcesList, "parquet_files",
  78. "Slow path should contain 'parquet_files'")
  79. assert.Contains(t, dataSourcesList, "live_logs",
  80. "Slow path should contain 'live_logs'")
  81. assert.NotContains(t, dataSourcesList, "parquet_stats",
  82. "Slow path should NOT contain 'parquet_stats'")
  83. })
  84. t.Run("Data source formatting works correctly", func(t *testing.T) {
  85. // Test just the data source formatting which is the key fix
  86. // Test parquet_stats formatting (fast path)
  87. fastPathFormatted := engine.SQLEngine.formatDataSource("parquet_stats")
  88. assert.Equal(t, "Parquet Statistics (fast path)", fastPathFormatted,
  89. "parquet_stats should format to show fast path usage")
  90. // Test parquet_files formatting (slow path)
  91. slowPathFormatted := engine.SQLEngine.formatDataSource("parquet_files")
  92. assert.Equal(t, "Parquet Files (full scan)", slowPathFormatted,
  93. "parquet_files should format to show full scan")
  94. // Test that data sources list is built correctly for fast path
  95. builder := &ExecutionPlanBuilder{}
  96. fastStrategy := AggregationStrategy{CanUseFastPath: true}
  97. fastSources := builder.buildDataSourcesList(fastStrategy, dataSources)
  98. assert.Contains(t, fastSources, "parquet_stats",
  99. "Fast path should include parquet_stats")
  100. assert.NotContains(t, fastSources, "parquet_files",
  101. "Fast path should NOT include parquet_files")
  102. // Test that data sources list is built correctly for slow path
  103. slowStrategy := AggregationStrategy{CanUseFastPath: false}
  104. slowSources := builder.buildDataSourcesList(slowStrategy, dataSources)
  105. assert.Contains(t, slowSources, "parquet_files",
  106. "Slow path should include parquet_files")
  107. assert.NotContains(t, slowSources, "parquet_stats",
  108. "Slow path should NOT include parquet_stats")
  109. })
  110. }