github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/opt/memo/statistics_builder_test.go (about)

     1  // Copyright 2018 The Cockroach Authors.
     2  //
     3  // Use of this software is governed by the Business Source License
     4  // included in the file licenses/BSL.txt.
     5  //
     6  // As of the Change Date specified in that file, in accordance with
     7  // the Business Source License, use of this software will be governed
     8  // by the Apache License, Version 2.0, included in the file
     9  // licenses/APL.txt.
    10  
    11  package memo
    12  
    13  import (
    14  	"testing"
    15  
    16  	"github.com/cockroachdb/cockroach/pkg/settings/cluster"
    17  	"github.com/cockroachdb/cockroach/pkg/sql/opt"
    18  	"github.com/cockroachdb/cockroach/pkg/sql/opt/constraint"
    19  	"github.com/cockroachdb/cockroach/pkg/sql/opt/props"
    20  	"github.com/cockroachdb/cockroach/pkg/sql/opt/testutils/testcat"
    21  	"github.com/cockroachdb/cockroach/pkg/sql/sem/tree"
    22  )
    23  
    24  // Most of the functionality in statistics.go is tested by the data-driven
    25  // testing in logical_props_factory_test.go. This file contains tests for
    26  // functions in statistics.go that cannot be tested using the data-driven
    27  // testing framework.
    28  
    29  // Test getting statistics from constraints that cannot yet be inferred
    30  // by the optimizer.
    31  func TestGetStatsFromConstraint(t *testing.T) {
    32  	evalCtx := tree.MakeTestingEvalContext(cluster.MakeTestingClusterSettings())
    33  	evalCtx.SessionData.OptimizerUseMultiColStats = true
    34  
    35  	catalog := testcat.New()
    36  	if _, err := catalog.ExecuteDDL(
    37  		"CREATE TABLE sel (a INT, b INT, c INT, d STRING, e STRING)",
    38  	); err != nil {
    39  		t.Fatal(err)
    40  	}
    41  
    42  	if _, err := catalog.ExecuteDDL(
    43  		`ALTER TABLE sel INJECT STATISTICS '[
    44  		{
    45  			"columns": ["a"],
    46  			"created_at": "2018-01-01 1:00:00.00000+00:00",
    47  			"row_count": 10000000000,
    48  			"distinct_count": 500
    49  		},
    50  		{
    51  			"columns": ["b"],
    52  			"created_at": "2018-01-01 1:30:00.00000+00:00",
    53  			"row_count": 10000000000,
    54  			"distinct_count": 500
    55  		},
    56  		{
    57  			"columns": ["c"],
    58  			"created_at": "2018-01-01 1:30:00.00000+00:00",
    59  			"row_count": 10000000000,
    60  			"distinct_count": 500
    61  		},
    62  		{
    63  			"columns": ["a","b","c"],
    64  			"created_at": "2018-01-01 1:30:00.00000+00:00",
    65  			"row_count": 10000000000,
    66  			"distinct_count": 9900
    67  		},
    68  		{
    69  			"columns": ["d"],
    70  			"created_at": "2018-01-01 1:30:00.00000+00:00",
    71  			"row_count": 10000000000,
    72  			"distinct_count": 10
    73  		},
    74  		{
    75  			"columns": ["e"],
    76  			"created_at": "2018-01-01 1:30:00.00000+00:00",
    77  			"row_count": 10000000000,
    78  			"distinct_count": 10
    79  		},
    80  		{
    81  			"columns": ["d","e"],
    82  			"created_at": "2018-01-01 1:30:00.00000+00:00",
    83  			"row_count": 10000000000,
    84  			"distinct_count": 100
    85  		}
    86  	]'`); err != nil {
    87  		t.Fatal(err)
    88  	}
    89  
    90  	var mem Memo
    91  	mem.Init(&evalCtx)
    92  	tn := tree.NewUnqualifiedTableName("sel")
    93  	tab := catalog.Table(tn)
    94  	tabID := mem.Metadata().AddTable(tab, tn)
    95  
    96  	// Test that applyConstraintSet correctly updates the statistics from
    97  	// constraint set cs.
    98  	statsFunc := func(cs *constraint.Set, expectedStats string) {
    99  		t.Helper()
   100  
   101  		var cols opt.ColSet
   102  		for i := 0; i < tab.ColumnCount(); i++ {
   103  			cols.Add(tabID.ColumnID(i))
   104  		}
   105  
   106  		sb := &statisticsBuilder{}
   107  		sb.init(&evalCtx, mem.Metadata())
   108  
   109  		// Make the scan.
   110  		scan := mem.MemoizeScan(&ScanPrivate{Table: tabID, Cols: cols})
   111  
   112  		// Make the select.
   113  		sel := mem.MemoizeSelect(scan, TrueFilter)
   114  
   115  		relProps := &props.Relational{Cardinality: props.AnyCardinality}
   116  		relProps.NotNullCols = cs.ExtractNotNullCols(&evalCtx)
   117  		s := &relProps.Stats
   118  		s.Init(relProps)
   119  
   120  		// Calculate distinct counts.
   121  		sb.applyConstraintSet(cs, true /* tight */, sel, relProps)
   122  
   123  		// Calculate row count and selectivity.
   124  		s.RowCount = scan.Relational().Stats.RowCount
   125  		s.ApplySelectivity(sb.selectivityFromMultiColDistinctCounts(cols, sel, s))
   126  
   127  		// Update null counts.
   128  		sb.updateNullCountsFromProps(sel, relProps)
   129  
   130  		// Check if the statistics match the expected value.
   131  		testStats(t, s, expectedStats)
   132  	}
   133  
   134  	c1 := constraint.ParseConstraint(&evalCtx, "/1: [/2 - /5] [/8 - /10]")
   135  	c2 := constraint.ParseConstraint(&evalCtx, "/2: [/3 - ]")
   136  	c3 := constraint.ParseConstraint(&evalCtx, "/3: [/6 - /6]")
   137  	c12 := constraint.ParseConstraint(&evalCtx, "/1/2/3: [/1/2 - /1/3] [/1/4 - /1]")
   138  	c123 := constraint.ParseConstraint(&evalCtx, "/1/2/3: [/1/2/3 - /1/2/3] [/1/2/5 - /1/2/8]")
   139  	c123n := constraint.ParseConstraint(&evalCtx, "/1/2/3: [/1/2/NULL - /1/2/3] [/1/2/5 - /1/2/8]")
   140  	c32 := constraint.ParseConstraint(&evalCtx, "/3/-2: [/5/3 - /5/2]")
   141  	c321 := constraint.ParseConstraint(&evalCtx, "/-3/2/1: [/5/3/1 - /5/3/4] [/3/5/1 - /3/5/4]")
   142  	c312 := constraint.ParseConstraint(&evalCtx, "/3/1/-2: [/5/3/8 - /5/3/6] [/9/5/4 - /9/5/1]")
   143  	c312n := constraint.ParseConstraint(&evalCtx, "/3/1/-2: [/5/3/8 - /5/3/6] [/9/5/4 - /9/5/NULL]")
   144  
   145  	// /4/5: [/'apple'/'cherry' - /'apple'/'mango']
   146  	appleCherry := constraint.MakeCompositeKey(tree.NewDString("apple"), tree.NewDString("cherry"))
   147  	appleMango := constraint.MakeCompositeKey(tree.NewDString("apple"), tree.NewDString("mango"))
   148  	var sp45 constraint.Span
   149  	sp45.Init(appleCherry, constraint.IncludeBoundary, appleMango, constraint.IncludeBoundary)
   150  
   151  	var columns45 constraint.Columns
   152  	columns45.Init([]opt.OrderingColumn{4, 5})
   153  	keyCtx45 := constraint.MakeKeyContext(&columns45, &evalCtx)
   154  
   155  	cs1 := constraint.SingleConstraint(&c1)
   156  	statsFunc(
   157  		cs1,
   158  		"[rows=140000000, distinct(1)=7, null(1)=0]",
   159  	)
   160  
   161  	cs2 := constraint.SingleConstraint(&c2)
   162  	statsFunc(
   163  		cs2,
   164  		"[rows=3.33333333e+09, distinct(2)=166.666667, null(2)=0]",
   165  	)
   166  
   167  	cs3 := constraint.SingleConstraint(&c3)
   168  	statsFunc(
   169  		cs3,
   170  		"[rows=20000000, distinct(3)=1, null(3)=0]",
   171  	)
   172  
   173  	cs12 := constraint.SingleConstraint(&c12)
   174  	statsFunc(
   175  		cs12,
   176  		"[rows=20000000, distinct(1)=1, null(1)=0]",
   177  	)
   178  
   179  	cs123 := constraint.SingleConstraint(&c123)
   180  	statsFunc(
   181  		cs123,
   182  		"[rows=36040, distinct(1)=1, null(1)=0, distinct(2)=1, null(2)=0, distinct(3)=5, null(3)=0, distinct(1,2)=1, null(1,2)=0, distinct(1-3)=5, null(1-3)=0]",
   183  	)
   184  
   185  	cs123n := constraint.SingleConstraint(&c123n)
   186  	statsFunc(
   187  		cs123n,
   188  		"[rows=40000, distinct(1)=1, null(1)=0, distinct(2)=1, null(2)=0, distinct(1,2)=1, null(1,2)=0]",
   189  	)
   190  
   191  	cs32 := constraint.SingleConstraint(&c32)
   192  	statsFunc(
   193  		cs32,
   194  		"[rows=80000, distinct(2)=2, null(2)=0, distinct(3)=1, null(3)=0, distinct(2,3)=2, null(2,3)=0]",
   195  	)
   196  
   197  	cs321 := constraint.SingleConstraint(&c321)
   198  	statsFunc(
   199  		cs321,
   200  		"[rows=160000, distinct(2)=2, null(2)=0, distinct(3)=2, null(3)=0, distinct(2,3)=4, null(2,3)=0]",
   201  	)
   202  
   203  	cs312 := constraint.SingleConstraint(&c312)
   204  	statsFunc(
   205  		cs312,
   206  		"[rows=24490654.6, distinct(1)=2, null(1)=0, distinct(2)=7, null(2)=0, distinct(3)=2, null(3)=0, distinct(1-3)=26.9394737, null(1-3)=0]",
   207  	)
   208  
   209  	cs312n := constraint.SingleConstraint(&c312n)
   210  	statsFunc(
   211  		cs312n,
   212  		"[rows=160000, distinct(1)=2, null(1)=0, distinct(3)=2, null(3)=0, distinct(1,3)=4, null(1,3)=0]",
   213  	)
   214  
   215  	cs := cs3.Intersect(&evalCtx, cs123)
   216  	statsFunc(
   217  		cs,
   218  		"[rows=909098.909, distinct(1)=1, null(1)=0, distinct(2)=1, null(2)=0, distinct(3)=1, null(3)=0, distinct(1-3)=1, null(1-3)=0]",
   219  	)
   220  
   221  	cs = cs32.Intersect(&evalCtx, cs123)
   222  	statsFunc(
   223  		cs,
   224  		"[rows=909098.909, distinct(1)=1, null(1)=0, distinct(2)=1, null(2)=0, distinct(3)=1, null(3)=0, distinct(1-3)=1, null(1-3)=0]",
   225  	)
   226  
   227  	cs45 := constraint.SingleSpanConstraint(&keyCtx45, &sp45)
   228  	statsFunc(
   229  		cs45,
   230  		"[rows=1e+09, distinct(4)=1, null(4)=0]",
   231  	)
   232  }
   233  
   234  func testStats(t *testing.T, s *props.Statistics, expectedStats string) {
   235  	t.Helper()
   236  
   237  	actual := s.String()
   238  	if actual != expectedStats {
   239  		t.Fatalf("\nexpected: %s\nactual  : %s", expectedStats, actual)
   240  	}
   241  }