diff --git a/TreeDB/collections/column_physical_q2_1950_test.go b/TreeDB/collections/column_physical_q2_1950_test.go index e38e6524e4..b2e94b4891 100644 --- a/TreeDB/collections/column_physical_q2_1950_test.go +++ b/TreeDB/collections/column_physical_q2_1950_test.go @@ -51,6 +51,7 @@ func TestTypedColumnQ2SortedGroupedDistinctStreaming1950(t *testing.T) { } defer func() { _ = runner.Close() }() assertTypedColumnQ2SortedGroupedDistinctPostPrepareDiagnostics3324(t, "prepared setup", runner.PrepareDiagnostics(), true) + assertTypedColumnQ2PreparedGlobalRanksNoGlobalCodes1950(t, runner, false) prepared, err := runner.Run() if err != nil { t.Fatalf("prepared q2: %v", err) @@ -574,7 +575,7 @@ func TestTypedColumnQ2SortedGroupedDistinctLocalDictionariesAndEmptyValues1950(t t.Fatalf("PrepareColumnPhysicalQuery(q2 local dictionaries): %v", err) } defer func() { _ = runner.Close() }() - assertTypedColumnQ2PreparedGlobalCodes1950(t, runner) + assertTypedColumnQ2PreparedGlobalRanksNoGlobalCodes1950(t, runner, true) prepared, err := runner.Run() if err != nil { t.Fatalf("prepared q2 local dictionaries: %v", err) @@ -770,7 +771,7 @@ func flattenColumnPhysicalEvents1950(batches [][]columnPhysicalJSONBenchParityEv return events } -func assertTypedColumnQ2PreparedGlobalCodes1950(tb testing.TB, runner *ColumnPhysicalQueryRunner) { +func assertTypedColumnQ2PreparedGlobalRanksNoGlobalCodes1950(tb testing.TB, runner *ColumnPhysicalQueryRunner, requireSharedDidM bool) { tb.Helper() if runner == nil || runner.typedColumn == nil { tb.Fatalf("prepared q2 runner missing typed-column state") @@ -785,20 +786,35 @@ func assertTypedColumnQ2PreparedGlobalCodes1950(tb testing.TB, runner *ColumnPhy if part == nil { tb.Fatalf("part %d missing sorted grouped-distinct state", partIdx) } - if len(part.Group.GlobalCodes) != part.Rows || len(part.Distinct.GlobalCodes) != part.Rows { - tb.Fatalf("part %d global code rows group=%d distinct=%d want %d", partIdx, len(part.Group.GlobalCodes), len(part.Distinct.GlobalCodes), part.Rows) + if len(part.Group.GlobalCodes) != 0 || len(part.Distinct.GlobalCodes) != 0 { + tb.Fatalf("part %d global code rows group=%d distinct=%d want 0", partIdx, len(part.Group.GlobalCodes), len(part.Distinct.GlobalCodes)) + } + if part.Group.GlobalDictionary == nil || !sort.StringsAreSorted(part.Group.GlobalDictionary) { + tb.Fatalf("part %d group global dictionary not lexicographically sorted group=%v", partIdx, part.Group.GlobalDictionary) } - if !sort.StringsAreSorted(part.Group.GlobalDictionary) || !sort.StringsAreSorted(part.Distinct.GlobalDictionary) { - tb.Fatalf("part %d global dictionaries not lexicographically sorted group=%v distinct=%v", partIdx, part.Group.GlobalDictionary, part.Distinct.GlobalDictionary) + if !part.Group.GlobalCardinalityOK || part.Group.GlobalCardinality != len(part.Group.GlobalDictionary) { + tb.Fatalf("part %d group global cardinality=%d ok=%t want dictionary=%d", partIdx, part.Group.GlobalCardinality, part.Group.GlobalCardinalityOK, len(part.Group.GlobalDictionary)) } - for row, code := range part.Group.GlobalCodes { - if int(code) >= len(part.Group.GlobalDictionary) { - tb.Fatalf("part %d group global code row=%d code=%d outside cardinality=%d", partIdx, row, code, len(part.Group.GlobalDictionary)) + if len(part.Group.GlobalLocalRanks) != len(part.Group.Dictionary) { + tb.Fatalf("part %d group local rank entries=%d want dictionary=%d", partIdx, len(part.Group.GlobalLocalRanks), len(part.Group.Dictionary)) + } + for localCode, rank := range part.Group.GlobalLocalRanks { + if int(rank) >= part.Group.GlobalCardinality { + tb.Fatalf("part %d group local code=%d rank=%d outside cardinality=%d", partIdx, localCode, rank, part.Group.GlobalCardinality) } } - for row, code := range part.Distinct.GlobalCodes { - if int(code) >= len(part.Distinct.GlobalDictionary) { - tb.Fatalf("part %d distinct global code row=%d code=%d outside cardinality=%d", partIdx, row, code, len(part.Distinct.GlobalDictionary)) + if part.Distinct.GlobalDictionary != nil { + tb.Fatalf("part %d distinct global dictionary allocated=%d want nil", partIdx, len(part.Distinct.GlobalDictionary)) + } + if !part.Distinct.GlobalCardinalityOK || part.Distinct.GlobalCardinality == 0 { + tb.Fatalf("part %d distinct global cardinality=%d ok=%t want nonzero prepared cardinality", partIdx, part.Distinct.GlobalCardinality, part.Distinct.GlobalCardinalityOK) + } + if len(part.Distinct.GlobalLocalRanks) != len(part.Distinct.Dictionary) { + tb.Fatalf("part %d distinct local rank entries=%d want dictionary=%d", partIdx, len(part.Distinct.GlobalLocalRanks), len(part.Distinct.Dictionary)) + } + for localCode, rank := range part.Distinct.GlobalLocalRanks { + if int(rank) >= part.Distinct.GlobalCardinality { + tb.Fatalf("part %d distinct local code=%d rank=%d outside cardinality=%d", partIdx, localCode, rank, part.Distinct.GlobalCardinality) } } localDidM := -1 @@ -811,28 +827,19 @@ func assertTypedColumnQ2PreparedGlobalCodes1950(tb testing.TB, runner *ColumnPhy if localDidM < 0 { continue } - partDidMRank := -1 - for rank, value := range part.Distinct.GlobalDictionary { - if value == "did:m" { - partDidMRank = rank - break - } - } - if partDidMRank < 0 { - tb.Fatalf("part %d distinct global dictionary missing did:m", partIdx) + if localDidM >= len(part.Distinct.GlobalLocalRanks) { + tb.Fatalf("part %d local did:m code=%d outside distinct global local ranks=%d", partIdx, localDidM, len(part.Distinct.GlobalLocalRanks)) } + partDidMRank := int(part.Distinct.GlobalLocalRanks[localDidM]) if didMRank < 0 { didMRank = partDidMRank } else if didMRank != partDidMRank { tb.Fatalf("did:m global rank part %d=%d want %d", partIdx, partDidMRank, didMRank) } seenDidMRow := false - for row, localCode := range part.Distinct.Codes { + for _, localCode := range part.Distinct.Codes { if localCode == int64(localDidM) { seenDidMRow = true - if part.Distinct.GlobalCodes[row] != uint32(partDidMRank) { - tb.Fatalf("part %d did:m row=%d global code=%d want %d", partIdx, row, part.Distinct.GlobalCodes[row], partDidMRank) - } } } if !seenDidMRow { @@ -840,7 +847,7 @@ func assertTypedColumnQ2PreparedGlobalCodes1950(tb testing.TB, runner *ColumnPhy } didMParts++ } - if didMParts < 2 { + if requireSharedDidM && didMParts < 2 { tb.Fatalf("did:m appeared in %d parts want at least two to prove cross-part global rank reuse", didMParts) } } @@ -1039,22 +1046,28 @@ func assertTypedColumnQ2DenseGroupCountDistinctDiagnostics1950(tb testing.TB, la func assertTypedColumnQ2SortedGroupedDistinctPostPrepareDiagnostics3324(tb testing.TB, label string, diag ColumnPhysicalQueryDiagnostics, want bool) { tb.Helper() - total := diag.TypedColumnPrepareQ2GroupGlobalDictionaryRankNanos + - diag.TypedColumnPrepareQ2DistinctGlobalDictionaryRankNanos + - diag.TypedColumnPrepareQ2GroupGlobalCodeRemapNanos + + remapTotal := diag.TypedColumnPrepareQ2GroupGlobalCodeRemapNanos + diag.TypedColumnPrepareQ2DistinctGlobalCodeRemapNanos + if remapTotal != 0 { + tb.Fatalf("%s sorted grouped-distinct per-row remap nanos=%d want 0 diagnostics=%+v", label, remapTotal, diag) + } + dictionaryTotal := diag.TypedColumnPrepareQ2GroupGlobalDictionaryRankNanos + + diag.TypedColumnPrepareQ2DistinctGlobalDictionaryRankNanos + localRankTotal := diag.TypedColumnPrepareQ2GroupGlobalLocalRankNanos + + diag.TypedColumnPrepareQ2DistinctGlobalLocalRankNanos if !want { - if total != 0 { - tb.Fatalf("%s sorted grouped-distinct post-prepare split nanos=%d want 0 diagnostics=%+v", label, total, diag) + if dictionaryTotal+localRankTotal != 0 { + tb.Fatalf("%s sorted grouped-distinct dictionary/rank/local-rank nanos=%d want 0 diagnostics=%+v", label, dictionaryTotal+localRankTotal, diag) } return } - if total == 0 { + if dictionaryTotal+localRankTotal == 0 { return } - dictionaryTotal := diag.TypedColumnPrepareQ2GroupGlobalDictionaryRankNanos + - diag.TypedColumnPrepareQ2DistinctGlobalDictionaryRankNanos - if dictionaryTotal <= 0 { - tb.Fatalf("%s sorted grouped-distinct post-prepare split diagnostics=%+v want dictionary/rank split work when timer resolution records split work", label, diag) + if diag.TypedColumnPrepareQ2GroupGlobalDictionaryRankNanos <= 0 || diag.TypedColumnPrepareQ2DistinctGlobalDictionaryRankNanos <= 0 { + tb.Fatalf("%s sorted grouped-distinct post-prepare split diagnostics=%+v want group/distinct dictionary/rank work when timer resolution records split work", label, diag) + } + if diag.TypedColumnPrepareQ2GroupGlobalLocalRankNanos <= 0 || diag.TypedColumnPrepareQ2DistinctGlobalLocalRankNanos <= 0 { + tb.Fatalf("%s sorted grouped-distinct post-prepare split diagnostics=%+v want group/distinct local-rank work when timer resolution records split work", label, diag) } } diff --git a/TreeDB/collections/column_physical_query.go b/TreeDB/collections/column_physical_query.go index f6566f94c9..889b03e2a6 100644 --- a/TreeDB/collections/column_physical_query.go +++ b/TreeDB/collections/column_physical_query.go @@ -222,6 +222,8 @@ type ColumnPhysicalQueryDiagnostics struct { TypedColumnPrepareQ2GroupGlobalDictionaryRankNanos int64 TypedColumnPrepareQ2DistinctGlobalDictionaryRankNanos int64 + TypedColumnPrepareQ2GroupGlobalLocalRankNanos int64 + TypedColumnPrepareQ2DistinctGlobalLocalRankNanos int64 TypedColumnPrepareQ2GroupGlobalCodeRemapNanos int64 TypedColumnPrepareQ2DistinctGlobalCodeRemapNanos int64 @@ -1516,6 +1518,8 @@ func mergeColumnPhysicalQueryDiagnostics(left, right ColumnPhysicalQueryDiagnost } left.TypedColumnPrepareQ2GroupGlobalDictionaryRankNanos += right.TypedColumnPrepareQ2GroupGlobalDictionaryRankNanos left.TypedColumnPrepareQ2DistinctGlobalDictionaryRankNanos += right.TypedColumnPrepareQ2DistinctGlobalDictionaryRankNanos + left.TypedColumnPrepareQ2GroupGlobalLocalRankNanos += right.TypedColumnPrepareQ2GroupGlobalLocalRankNanos + left.TypedColumnPrepareQ2DistinctGlobalLocalRankNanos += right.TypedColumnPrepareQ2DistinctGlobalLocalRankNanos left.TypedColumnPrepareQ2GroupGlobalCodeRemapNanos += right.TypedColumnPrepareQ2GroupGlobalCodeRemapNanos left.TypedColumnPrepareQ2DistinctGlobalCodeRemapNanos += right.TypedColumnPrepareQ2DistinctGlobalCodeRemapNanos return left diff --git a/TreeDB/collections/column_physical_typed_column_one_shot_cache_3088_test.go b/TreeDB/collections/column_physical_typed_column_one_shot_cache_3088_test.go index 55d791fe3c..5865efe16b 100644 --- a/TreeDB/collections/column_physical_typed_column_one_shot_cache_3088_test.go +++ b/TreeDB/collections/column_physical_typed_column_one_shot_cache_3088_test.go @@ -607,6 +607,8 @@ func assertTypedColumnQ2PostPrepareSubphaseDiagnostics3158(tb testing.TB, label diag.TypedColumnPrepareQ2DensePartLocalRankNanos globalCodeTotal := diag.TypedColumnPrepareQ2GroupGlobalDictionaryRankNanos + diag.TypedColumnPrepareQ2DistinctGlobalDictionaryRankNanos + + diag.TypedColumnPrepareQ2GroupGlobalLocalRankNanos + + diag.TypedColumnPrepareQ2DistinctGlobalLocalRankNanos + diag.TypedColumnPrepareQ2GroupGlobalCodeRemapNanos + diag.TypedColumnPrepareQ2DistinctGlobalCodeRemapNanos if !want { diff --git a/TreeDB/collections/column_physical_typed_column_query.go b/TreeDB/collections/column_physical_typed_column_query.go index 29f1121dd2..d2ffef168a 100644 --- a/TreeDB/collections/column_physical_typed_column_query.go +++ b/TreeDB/collections/column_physical_typed_column_query.go @@ -125,10 +125,13 @@ type columnTypedColumnDenseInt64SpanPart struct { } type columnTypedColumnSortedGroupedDistinctCodeColumn struct { - Codes []int64 - Dictionary []string - GlobalCodes []uint32 - GlobalDictionary []string + Codes []int64 + Dictionary []string + GlobalCodes []uint32 + GlobalDictionary []string + GlobalCardinality int + GlobalCardinalityOK bool + GlobalLocalRanks []uint32 } type columnTypedColumnSortedGroupedDistinctPredicate struct { @@ -273,6 +276,8 @@ type columnTypedColumnPhysicalQueryPrepareDiagnostics struct { Q2GroupGlobalDictionaryRankNanos int64 Q2DistinctGlobalDictionaryRankNanos int64 + Q2GroupGlobalLocalRankNanos int64 + Q2DistinctGlobalLocalRankNanos int64 Q2GroupGlobalCodeRemapNanos int64 Q2DistinctGlobalCodeRemapNanos int64 } @@ -324,6 +329,8 @@ func (d columnTypedColumnPhysicalQueryPrepareDiagnostics) applyTo(diag *ColumnPh } diag.TypedColumnPrepareQ2GroupGlobalDictionaryRankNanos += d.Q2GroupGlobalDictionaryRankNanos diag.TypedColumnPrepareQ2DistinctGlobalDictionaryRankNanos += d.Q2DistinctGlobalDictionaryRankNanos + diag.TypedColumnPrepareQ2GroupGlobalLocalRankNanos += d.Q2GroupGlobalLocalRankNanos + diag.TypedColumnPrepareQ2DistinctGlobalLocalRankNanos += d.Q2DistinctGlobalLocalRankNanos diag.TypedColumnPrepareQ2GroupGlobalCodeRemapNanos += d.Q2GroupGlobalCodeRemapNanos diag.TypedColumnPrepareQ2DistinctGlobalCodeRemapNanos += d.Q2DistinctGlobalCodeRemapNanos } @@ -375,6 +382,8 @@ func (d *columnTypedColumnPhysicalQueryPrepareDiagnostics) add(src columnTypedCo } d.Q2GroupGlobalDictionaryRankNanos += src.Q2GroupGlobalDictionaryRankNanos d.Q2DistinctGlobalDictionaryRankNanos += src.Q2DistinctGlobalDictionaryRankNanos + d.Q2GroupGlobalLocalRankNanos += src.Q2GroupGlobalLocalRankNanos + d.Q2DistinctGlobalLocalRankNanos += src.Q2DistinctGlobalLocalRankNanos d.Q2GroupGlobalCodeRemapNanos += src.Q2GroupGlobalCodeRemapNanos d.Q2DistinctGlobalCodeRemapNanos += src.Q2DistinctGlobalCodeRemapNanos } @@ -801,7 +810,7 @@ func decodeColumnTypedColumnPhysicalQueryRunnerParts(view columnPhysicalScanSnap } phaseStart = time.Now() if columnTypedColumnPhysicalQueryUseSortedGroupedDistinct(plan, req) { - if err := prepareColumnTypedColumnSortedGroupedDistinctGlobalCodesWithDiagnostics(runner.parts, prepareDiagnostics); err != nil { + if err := prepareColumnTypedColumnSortedGroupedDistinctGlobalRanksWithDiagnostics(runner.parts, prepareDiagnostics); err != nil { if prepareDiagnostics != nil { prepareDiagnostics.PostPrepareNanos += time.Since(phaseStart).Nanoseconds() } @@ -1206,11 +1215,11 @@ func buildColumnTypedColumnDenseGroupHourCountSummary(parts []columnTypedColumnP }, nil } -func prepareColumnTypedColumnSortedGroupedDistinctGlobalCodes(parts []columnTypedColumnPhysicalQueryPart) error { - return prepareColumnTypedColumnSortedGroupedDistinctGlobalCodesWithDiagnostics(parts, nil) +func prepareColumnTypedColumnSortedGroupedDistinctGlobalRanks(parts []columnTypedColumnPhysicalQueryPart) error { + return prepareColumnTypedColumnSortedGroupedDistinctGlobalRanksWithDiagnostics(parts, nil) } -func prepareColumnTypedColumnSortedGroupedDistinctGlobalCodesWithDiagnostics(parts []columnTypedColumnPhysicalQueryPart, prepareDiagnostics *columnTypedColumnPhysicalQueryPrepareDiagnostics) error { +func prepareColumnTypedColumnSortedGroupedDistinctGlobalRanksWithDiagnostics(parts []columnTypedColumnPhysicalQueryPart, prepareDiagnostics *columnTypedColumnPhysicalQueryPrepareDiagnostics) error { phaseStart := time.Now() groupDict, groupRanks, err := columnTypedColumnSortedGroupedDistinctGlobalDictionary(parts, func(part *columnTypedColumnSortedGroupedDistinctPart) *columnTypedColumnSortedGroupedDistinctCodeColumn { return &part.Group @@ -1222,6 +1231,24 @@ func prepareColumnTypedColumnSortedGroupedDistinctGlobalCodesWithDiagnostics(par return err } phaseStart = time.Now() + for partIdx := range parts { + part := parts[partIdx].SortedGroupedDistinct + if part == nil { + err = fmt.Errorf("collections: sorted grouped-distinct missing prepared part %d", partIdx) + break + } + if rankErr := prepareColumnTypedColumnSortedGroupedDistinctGlobalColumnRanks(&part.Group, groupDict, len(groupDict), groupRanks); rankErr != nil { + err = fmt.Errorf("collections: sorted grouped-distinct group part %d: %w", partIdx, rankErr) + break + } + } + if prepareDiagnostics != nil { + prepareDiagnostics.Q2GroupGlobalLocalRankNanos += time.Since(phaseStart).Nanoseconds() + } + if err != nil { + return err + } + phaseStart = time.Now() distinctDict, distinctRanks, err := columnTypedColumnSortedGroupedDistinctGlobalDictionary(parts, func(part *columnTypedColumnSortedGroupedDistinctPart) *columnTypedColumnSortedGroupedDistinctCodeColumn { return &part.Distinct }) @@ -1231,28 +1258,24 @@ func prepareColumnTypedColumnSortedGroupedDistinctGlobalCodesWithDiagnostics(par if err != nil { return err } + phaseStart = time.Now() for partIdx := range parts { part := parts[partIdx].SortedGroupedDistinct if part == nil { - return fmt.Errorf("collections: sorted grouped-distinct missing prepared part %d", partIdx) - } - phaseStart = time.Now() - err := prepareColumnTypedColumnSortedGroupedDistinctGlobalColumnCodes(&part.Group, groupDict, groupRanks) - if prepareDiagnostics != nil { - prepareDiagnostics.Q2GroupGlobalCodeRemapNanos += time.Since(phaseStart).Nanoseconds() - } - if err != nil { - return fmt.Errorf("collections: sorted grouped-distinct group part %d: %w", partIdx, err) - } - phaseStart = time.Now() - err = prepareColumnTypedColumnSortedGroupedDistinctGlobalColumnCodes(&part.Distinct, distinctDict, distinctRanks) - if prepareDiagnostics != nil { - prepareDiagnostics.Q2DistinctGlobalCodeRemapNanos += time.Since(phaseStart).Nanoseconds() + err = fmt.Errorf("collections: sorted grouped-distinct missing prepared part %d", partIdx) + break } - if err != nil { - return fmt.Errorf("collections: sorted grouped-distinct distinct part %d: %w", partIdx, err) + if rankErr := prepareColumnTypedColumnSortedGroupedDistinctGlobalColumnRanks(&part.Distinct, nil, len(distinctDict), distinctRanks); rankErr != nil { + err = fmt.Errorf("collections: sorted grouped-distinct distinct part %d: %w", partIdx, rankErr) + break } } + if prepareDiagnostics != nil { + prepareDiagnostics.Q2DistinctGlobalLocalRankNanos += time.Since(phaseStart).Nanoseconds() + } + if err != nil { + return err + } return nil } @@ -1283,7 +1306,7 @@ func columnTypedColumnSortedGroupedDistinctGlobalDictionary(parts []columnTypedC return dictionary, ranks, nil } -func prepareColumnTypedColumnSortedGroupedDistinctGlobalColumnCodes(column *columnTypedColumnSortedGroupedDistinctCodeColumn, globalDictionary []string, ranks map[string]uint32) error { +func prepareColumnTypedColumnSortedGroupedDistinctGlobalColumnRanks(column *columnTypedColumnSortedGroupedDistinctCodeColumn, globalDictionary []string, cardinality int, ranks map[string]uint32) error { localRanks := make([]uint32, len(column.Dictionary)) for localCode, value := range column.Dictionary { rank, ok := ranks[value] @@ -1292,15 +1315,11 @@ func prepareColumnTypedColumnSortedGroupedDistinctGlobalColumnCodes(column *colu } localRanks[localCode] = rank } - globalCodes := make([]uint32, len(column.Codes)) - for row, localCode := range column.Codes { - if localCode < 0 || localCode >= int64(len(localRanks)) { - return fmt.Errorf("row=%d code=%d outside cardinality=%d", row, localCode, len(localRanks)) - } - globalCodes[row] = localRanks[localCode] - } - column.GlobalCodes = globalCodes + column.GlobalCodes = nil column.GlobalDictionary = globalDictionary + column.GlobalCardinality = cardinality + column.GlobalCardinalityOK = true + column.GlobalLocalRanks = localRanks return nil } @@ -5722,7 +5741,7 @@ type columnTypedColumnSortedGroupedDistinctIterator struct { currentDistinct string currentGroupCode uint32 currentDistinctCode uint32 - globalCodes bool + globalRanks bool done bool rowsScanned int matchedRows int @@ -5737,7 +5756,7 @@ func newColumnTypedColumnSortedGroupedDistinctIterator(part *columnTypedColumnPh physicalRows: part.SortedGroupedDistinct.PhysicalRows, visibility: visibility, codePart: part.SortedGroupedDistinct, - globalCodes: columnTypedColumnSortedGroupedDistinctPartHasGlobalCodes(part.SortedGroupedDistinct), + globalRanks: columnTypedColumnSortedGroupedDistinctPartHasGlobalRanks(part.SortedGroupedDistinct), }, nil } partRows := len(part.RowIndexes) @@ -5856,17 +5875,22 @@ func (it *columnTypedColumnSortedGroupedDistinctIterator) advanceCodes() error { if len(it.codePart.Predicates) != 0 { it.matchedRows++ } - if it.globalCodes { - if rowIdx >= len(it.codePart.Group.GlobalCodes) || rowIdx >= len(it.codePart.Distinct.GlobalCodes) { - return fmt.Errorf("collections: sorted grouped-distinct row=%d outside global code rows group=%d distinct=%d", rowIdx, len(it.codePart.Group.GlobalCodes), len(it.codePart.Distinct.GlobalCodes)) + if it.globalRanks { + groupCode := it.codePart.Group.Codes[rowIdx] + distinctCode := it.codePart.Distinct.Codes[rowIdx] + if groupCode < 0 || groupCode >= int64(len(it.codePart.Group.GlobalLocalRanks)) { + return fmt.Errorf("collections: sorted grouped-distinct group code=%d outside global rank cardinality=%d", groupCode, len(it.codePart.Group.GlobalLocalRanks)) + } + if distinctCode < 0 || distinctCode >= int64(len(it.codePart.Distinct.GlobalLocalRanks)) { + return fmt.Errorf("collections: sorted grouped-distinct distinct code=%d outside global rank cardinality=%d", distinctCode, len(it.codePart.Distinct.GlobalLocalRanks)) } - it.currentGroupCode = it.codePart.Group.GlobalCodes[rowIdx] - it.currentDistinctCode = it.codePart.Distinct.GlobalCodes[rowIdx] - if int(it.currentGroupCode) >= len(it.codePart.Group.GlobalDictionary) { - return fmt.Errorf("collections: sorted grouped-distinct global group code=%d outside cardinality=%d", it.currentGroupCode, len(it.codePart.Group.GlobalDictionary)) + it.currentGroupCode = it.codePart.Group.GlobalLocalRanks[groupCode] + it.currentDistinctCode = it.codePart.Distinct.GlobalLocalRanks[distinctCode] + if int(it.currentGroupCode) >= it.codePart.Group.GlobalCardinality { + return fmt.Errorf("collections: sorted grouped-distinct global group rank=%d outside cardinality=%d", it.currentGroupCode, it.codePart.Group.GlobalCardinality) } - if int(it.currentDistinctCode) >= len(it.codePart.Distinct.GlobalDictionary) { - return fmt.Errorf("collections: sorted grouped-distinct global distinct code=%d outside cardinality=%d", it.currentDistinctCode, len(it.codePart.Distinct.GlobalDictionary)) + if int(it.currentDistinctCode) >= it.codePart.Distinct.GlobalCardinality { + return fmt.Errorf("collections: sorted grouped-distinct global distinct rank=%d outside cardinality=%d", it.currentDistinctCode, it.codePart.Distinct.GlobalCardinality) } return nil } @@ -5890,22 +5914,24 @@ func (it *columnTypedColumnSortedGroupedDistinctIterator) advanceCodes() error { return nil } -func columnTypedColumnSortedGroupedDistinctPartHasGlobalCodes(part *columnTypedColumnSortedGroupedDistinctPart) bool { +func columnTypedColumnSortedGroupedDistinctPartHasGlobalRanks(part *columnTypedColumnSortedGroupedDistinctPart) bool { return part != nil && - len(part.Group.GlobalCodes) == part.Rows && - len(part.Distinct.GlobalCodes) == part.Rows && part.Group.GlobalDictionary != nil && - part.Distinct.GlobalDictionary != nil + part.Group.GlobalCardinalityOK && + part.Group.GlobalCardinality == len(part.Group.GlobalDictionary) && + part.Distinct.GlobalCardinalityOK && + len(part.Group.GlobalLocalRanks) == len(part.Group.Dictionary) && + len(part.Distinct.GlobalLocalRanks) == len(part.Distinct.Dictionary) } func (r *columnTypedColumnPhysicalQueryRunner) reduceSortedGroupedDistinct(iterators []*columnTypedColumnSortedGroupedDistinctIterator, heap *columnTypedColumnSortedGroupedDistinctHeap) ([]ColumnPhysicalQueryGroup, int, error) { - if columnTypedColumnSortedGroupedDistinctHeapUsesGlobalCodes(iterators, heap) { - return r.reduceSortedGroupedDistinctGlobalCodes(iterators, heap) + if columnTypedColumnSortedGroupedDistinctHeapUsesGlobalRanks(iterators, heap) { + return r.reduceSortedGroupedDistinctGlobalRanks(iterators, heap) } return r.reduceSortedGroupedDistinctStrings(iterators, heap) } -func (r *columnTypedColumnPhysicalQueryRunner) reduceSortedGroupedDistinctGlobalCodes(iterators []*columnTypedColumnSortedGroupedDistinctIterator, heap *columnTypedColumnSortedGroupedDistinctHeap) ([]ColumnPhysicalQueryGroup, int, error) { +func (r *columnTypedColumnPhysicalQueryRunner) reduceSortedGroupedDistinctGlobalRanks(iterators []*columnTypedColumnSortedGroupedDistinctIterator, heap *columnTypedColumnSortedGroupedDistinctHeap) ([]ColumnPhysicalQueryGroup, int, error) { groups := r.resultGroups[:0] firstGroup := true var currentGroupCode uint32 @@ -6008,12 +6034,12 @@ func (r *columnTypedColumnPhysicalQueryRunner) reduceSortedGroupedDistinctString return groups, reduceRows, nil } -func columnTypedColumnSortedGroupedDistinctHeapUsesGlobalCodes(iterators []*columnTypedColumnSortedGroupedDistinctIterator, heap *columnTypedColumnSortedGroupedDistinctHeap) bool { +func columnTypedColumnSortedGroupedDistinctHeapUsesGlobalRanks(iterators []*columnTypedColumnSortedGroupedDistinctIterator, heap *columnTypedColumnSortedGroupedDistinctHeap) bool { if heap.len() == 0 { return false } for _, iteratorIdx := range heap.items { - if iteratorIdx < 0 || iteratorIdx >= len(iterators) || !iterators[iteratorIdx].globalCodes { + if iteratorIdx < 0 || iteratorIdx >= len(iterators) || !iterators[iteratorIdx].globalRanks { return false } } @@ -6066,7 +6092,7 @@ func (h *columnTypedColumnSortedGroupedDistinctHeap) pop(iterators []*columnType } func columnTypedColumnSortedGroupedDistinctIteratorLess(left, right *columnTypedColumnSortedGroupedDistinctIterator) bool { - if left.globalCodes && right.globalCodes { + if left.globalRanks && right.globalRanks { if left.currentGroupCode != right.currentGroupCode { return left.currentGroupCode < right.currentGroupCode } diff --git a/cmd/unified_bench/suite_column_store.go b/cmd/unified_bench/suite_column_store.go index 09523c1ffe..0af0992e90 100644 --- a/cmd/unified_bench/suite_column_store.go +++ b/cmd/unified_bench/suite_column_store.go @@ -421,6 +421,8 @@ type columnStoreQueryMetric struct { TypedColumnPrepareQ2GroupGlobalDictionaryRankMS float64 `json:"typed_column_prepare_q2_group_global_dictionary_rank_duration_ms,omitempty"` TypedColumnPrepareQ2DistinctGlobalDictionaryRankMS float64 `json:"typed_column_prepare_q2_distinct_global_dictionary_rank_duration_ms,omitempty"` + TypedColumnPrepareQ2GroupGlobalLocalRankMS float64 `json:"typed_column_prepare_q2_group_global_local_rank_duration_ms,omitempty"` + TypedColumnPrepareQ2DistinctGlobalLocalRankMS float64 `json:"typed_column_prepare_q2_distinct_global_local_rank_duration_ms,omitempty"` TypedColumnPrepareQ2GroupGlobalCodeRemapMS float64 `json:"typed_column_prepare_q2_group_global_code_remap_duration_ms,omitempty"` TypedColumnPrepareQ2DistinctGlobalCodeRemapMS float64 `json:"typed_column_prepare_q2_distinct_global_code_remap_duration_ms,omitempty"` @@ -564,6 +566,8 @@ type columnStoreJSONBenchCell struct { TypedColumnPrepareQ2GroupGlobalDictionaryRankMS float64 `json:"typed_column_prepare_q2_group_global_dictionary_rank_duration_ms,omitempty"` TypedColumnPrepareQ2DistinctGlobalDictionaryRankMS float64 `json:"typed_column_prepare_q2_distinct_global_dictionary_rank_duration_ms,omitempty"` + TypedColumnPrepareQ2GroupGlobalLocalRankMS float64 `json:"typed_column_prepare_q2_group_global_local_rank_duration_ms,omitempty"` + TypedColumnPrepareQ2DistinctGlobalLocalRankMS float64 `json:"typed_column_prepare_q2_distinct_global_local_rank_duration_ms,omitempty"` TypedColumnPrepareQ2GroupGlobalCodeRemapMS float64 `json:"typed_column_prepare_q2_group_global_code_remap_duration_ms,omitempty"` TypedColumnPrepareQ2DistinctGlobalCodeRemapMS float64 `json:"typed_column_prepare_q2_distinct_global_code_remap_duration_ms,omitempty"` } @@ -700,6 +704,8 @@ type columnStoreQueryExecution struct { TypedColumnPrepareQ2GroupGlobalDictionaryRank time.Duration TypedColumnPrepareQ2DistinctGlobalDictionaryRank time.Duration + TypedColumnPrepareQ2GroupGlobalLocalRank time.Duration + TypedColumnPrepareQ2DistinctGlobalLocalRank time.Duration TypedColumnPrepareQ2GroupGlobalCodeRemap time.Duration TypedColumnPrepareQ2DistinctGlobalCodeRemap time.Duration @@ -2254,6 +2260,8 @@ func runColumnStoreSuiteQueries(collection *collections.Collection, rows int, ra TypedColumnPrepareQ2GroupGlobalDictionaryRankMS: durationMS(exec.TypedColumnPrepareQ2GroupGlobalDictionaryRank), TypedColumnPrepareQ2DistinctGlobalDictionaryRankMS: durationMS(exec.TypedColumnPrepareQ2DistinctGlobalDictionaryRank), + TypedColumnPrepareQ2GroupGlobalLocalRankMS: durationMS(exec.TypedColumnPrepareQ2GroupGlobalLocalRank), + TypedColumnPrepareQ2DistinctGlobalLocalRankMS: durationMS(exec.TypedColumnPrepareQ2DistinctGlobalLocalRank), TypedColumnPrepareQ2GroupGlobalCodeRemapMS: durationMS(exec.TypedColumnPrepareQ2GroupGlobalCodeRemap), TypedColumnPrepareQ2DistinctGlobalCodeRemapMS: durationMS(exec.TypedColumnPrepareQ2DistinctGlobalCodeRemap), } @@ -2739,6 +2747,8 @@ func executeColumnStoreSuitePhysicalQuery(collection *collections.Collection, qu TypedColumnPrepareQ2GroupGlobalDictionaryRank: time.Duration(diag.TypedColumnPrepareQ2GroupGlobalDictionaryRankNanos), TypedColumnPrepareQ2DistinctGlobalDictionaryRank: time.Duration(diag.TypedColumnPrepareQ2DistinctGlobalDictionaryRankNanos), + TypedColumnPrepareQ2GroupGlobalLocalRank: time.Duration(diag.TypedColumnPrepareQ2GroupGlobalLocalRankNanos), + TypedColumnPrepareQ2DistinctGlobalLocalRank: time.Duration(diag.TypedColumnPrepareQ2DistinctGlobalLocalRankNanos), TypedColumnPrepareQ2GroupGlobalCodeRemap: time.Duration(diag.TypedColumnPrepareQ2GroupGlobalCodeRemapNanos), TypedColumnPrepareQ2DistinctGlobalCodeRemap: time.Duration(diag.TypedColumnPrepareQ2DistinctGlobalCodeRemapNanos), }, nil @@ -2890,6 +2900,8 @@ func executeColumnStoreSuitePreparedPhysicalQuery(collection *collections.Collec TypedColumnPrepareQ2GroupGlobalDictionaryRank: time.Duration(setupDiagnostics.TypedColumnPrepareQ2GroupGlobalDictionaryRankNanos), TypedColumnPrepareQ2DistinctGlobalDictionaryRank: time.Duration(setupDiagnostics.TypedColumnPrepareQ2DistinctGlobalDictionaryRankNanos), + TypedColumnPrepareQ2GroupGlobalLocalRank: time.Duration(setupDiagnostics.TypedColumnPrepareQ2GroupGlobalLocalRankNanos), + TypedColumnPrepareQ2DistinctGlobalLocalRank: time.Duration(setupDiagnostics.TypedColumnPrepareQ2DistinctGlobalLocalRankNanos), TypedColumnPrepareQ2GroupGlobalCodeRemap: time.Duration(setupDiagnostics.TypedColumnPrepareQ2GroupGlobalCodeRemapNanos), TypedColumnPrepareQ2DistinctGlobalCodeRemap: time.Duration(setupDiagnostics.TypedColumnPrepareQ2DistinctGlobalCodeRemapNanos), }, nil @@ -3350,6 +3362,8 @@ func columnStoreJSONBenchCellFromQueryMetric(q columnStoreQueryMetric, cfg *coll cell.TypedColumnPrepareQ2DenseDistinctGlobalRanks = q.TypedColumnPrepareQ2DenseDistinctGlobalRanks cell.TypedColumnPrepareQ2GroupGlobalDictionaryRankMS = q.TypedColumnPrepareQ2GroupGlobalDictionaryRankMS cell.TypedColumnPrepareQ2DistinctGlobalDictionaryRankMS = q.TypedColumnPrepareQ2DistinctGlobalDictionaryRankMS + cell.TypedColumnPrepareQ2GroupGlobalLocalRankMS = q.TypedColumnPrepareQ2GroupGlobalLocalRankMS + cell.TypedColumnPrepareQ2DistinctGlobalLocalRankMS = q.TypedColumnPrepareQ2DistinctGlobalLocalRankMS cell.TypedColumnPrepareQ2GroupGlobalCodeRemapMS = q.TypedColumnPrepareQ2GroupGlobalCodeRemapMS cell.TypedColumnPrepareQ2DistinctGlobalCodeRemapMS = q.TypedColumnPrepareQ2DistinctGlobalCodeRemapMS cell.ScanDurationMS = q.ScanDurationMS @@ -3488,6 +3502,8 @@ func columnStoreJSONBenchCellFromPreparedExecution(name string, rawHash uint64, cell.TypedColumnPrepareQ2DenseDistinctGlobalRanks = exec.TypedColumnPrepareQ2DenseDistinctGlobalRanks cell.TypedColumnPrepareQ2GroupGlobalDictionaryRankMS = durationMS(exec.TypedColumnPrepareQ2GroupGlobalDictionaryRank) cell.TypedColumnPrepareQ2DistinctGlobalDictionaryRankMS = durationMS(exec.TypedColumnPrepareQ2DistinctGlobalDictionaryRank) + cell.TypedColumnPrepareQ2GroupGlobalLocalRankMS = durationMS(exec.TypedColumnPrepareQ2GroupGlobalLocalRank) + cell.TypedColumnPrepareQ2DistinctGlobalLocalRankMS = durationMS(exec.TypedColumnPrepareQ2DistinctGlobalLocalRank) cell.TypedColumnPrepareQ2GroupGlobalCodeRemapMS = durationMS(exec.TypedColumnPrepareQ2GroupGlobalCodeRemap) cell.TypedColumnPrepareQ2DistinctGlobalCodeRemapMS = durationMS(exec.TypedColumnPrepareQ2DistinctGlobalCodeRemap) cell.TypedColumnPrepareWorkerCount = exec.TypedColumnPrepareWorkerCount @@ -5079,13 +5095,13 @@ func renderColumnStoreTypedColumnSetupDiagnosticsMarkdown(sb *strings.Builder, r return } sb.WriteString("## Typed Column Setup Diagnostics\n\n") - sb.WriteString("| cell | query | mode | query mode | metadata mode | prepare/setup ms | typed prep workers | one-shot build ms | prep plan ms | prep refs ms | prep pair ms | prep decode ms | prep post ms | q2 group rank ms | q2 distinct rank ms | q2 local rank ms | q2 dense group global rank ms | q2 dense distinct global rank ms | q2 dense part local rank ms | q2 dense distinct rank plan ms | q2 dense distinct rank collect refs ms | q2 dense distinct rank build shards ms | q2 dense distinct rank shards | q2 dense distinct rank refs | q2 dense distinct rank max shard refs | q2 dense distinct global ranks | q2 group global dict/rank ms | q2 distinct global dict/rank ms | q2 group global-code remap ms | q2 distinct global-code remap ms | prep summary ms | cache store ms | read image ms | state build ms | dictionary ms | pruning ms | sort key ms | stats ms | range read ms | range read B | adapter ms | dense group ms | dense value ms | dense predicate ms | dense preapply ms |\n") - sb.WriteString("|---|---|---|---|---|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|\n") + sb.WriteString("| cell | query | mode | query mode | metadata mode | prepare/setup ms | typed prep workers | one-shot build ms | prep plan ms | prep refs ms | prep pair ms | prep decode ms | prep post ms | q2 group rank ms | q2 distinct rank ms | q2 local rank ms | q2 dense group global rank ms | q2 dense distinct global rank ms | q2 dense part local rank ms | q2 dense distinct rank plan ms | q2 dense distinct rank collect refs ms | q2 dense distinct rank build shards ms | q2 dense distinct rank shards | q2 dense distinct rank refs | q2 dense distinct rank max shard refs | q2 dense distinct global ranks | q2 group global dict/rank ms | q2 distinct global dict/rank ms | q2 group global local-rank ms | q2 distinct global local-rank ms | q2 group global-code remap ms | q2 distinct global-code remap ms | prep summary ms | cache store ms | read image ms | state build ms | dictionary ms | pruning ms | sort key ms | stats ms | range read ms | range read B | adapter ms | dense group ms | dense value ms | dense predicate ms | dense preapply ms |\n") + sb.WriteString("|---|---|---|---|---|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|\n") for _, cell := range report.JSONBenchCells { if !columnStoreJSONBenchCellHasTypedColumnSetupDiagnostics(cell) { continue } - sb.WriteString(fmt.Sprintf("| %s | %s | %s | %s | %s | %.3f | %d | %.3f | %.3f | %.3f | %.3f | %.3f | %.3f | %.3f | %.3f | %.3f | %.3f | %.3f | %.3f | %.3f | %.3f | %.3f | %d | %d | %d | %d | %.3f | %.3f | %.3f | %.3f | %.3f | %.3f | %.3f | %.3f | %.3f | %.3f | %.3f | %.3f | %.3f | %d | %.3f | %.3f | %.3f | %.3f | %.3f |\n", + sb.WriteString(fmt.Sprintf("| %s | %s | %s | %s | %s | %.3f | %d | %.3f | %.3f | %.3f | %.3f | %.3f | %.3f | %.3f | %.3f | %.3f | %.3f | %.3f | %.3f | %.3f | %.3f | %.3f | %d | %d | %d | %d | %.3f | %.3f | %.3f | %.3f | %.3f | %.3f | %.3f | %.3f | %.3f | %.3f | %.3f | %.3f | %.3f | %.3f | %.3f | %d | %.3f | %.3f | %.3f | %.3f | %.3f |\n", markdownCodeTableText(cell.CellLabel), markdownCodeTableText(cell.Query), markdownCodeTableText(cell.ExecutionMode), @@ -5114,6 +5130,8 @@ func renderColumnStoreTypedColumnSetupDiagnosticsMarkdown(sb *strings.Builder, r cell.TypedColumnPrepareQ2DenseDistinctGlobalRanks, cell.TypedColumnPrepareQ2GroupGlobalDictionaryRankMS, cell.TypedColumnPrepareQ2DistinctGlobalDictionaryRankMS, + cell.TypedColumnPrepareQ2GroupGlobalLocalRankMS, + cell.TypedColumnPrepareQ2DistinctGlobalLocalRankMS, cell.TypedColumnPrepareQ2GroupGlobalCodeRemapMS, cell.TypedColumnPrepareQ2DistinctGlobalCodeRemapMS, cell.TypedColumnPrepareSummaryDurationMS, @@ -5173,6 +5191,8 @@ func columnStoreJSONBenchCellHasTypedColumnSetupDiagnostics(cell columnStoreJSON cell.TypedColumnPrepareQ2DenseDistinctGlobalRanks != 0 || cell.TypedColumnPrepareQ2GroupGlobalDictionaryRankMS != 0 || cell.TypedColumnPrepareQ2DistinctGlobalDictionaryRankMS != 0 || + cell.TypedColumnPrepareQ2GroupGlobalLocalRankMS != 0 || + cell.TypedColumnPrepareQ2DistinctGlobalLocalRankMS != 0 || cell.TypedColumnPrepareQ2GroupGlobalCodeRemapMS != 0 || cell.TypedColumnPrepareQ2DistinctGlobalCodeRemapMS != 0 || cell.TypedColumnPrepareWorkerCount != 0 diff --git a/cmd/unified_bench/suite_column_store_test.go b/cmd/unified_bench/suite_column_store_test.go index 5192c0b7f1..a8f78484eb 100644 --- a/cmd/unified_bench/suite_column_store_test.go +++ b/cmd/unified_bench/suite_column_store_test.go @@ -2613,8 +2613,10 @@ func TestColumnStoreJSONBenchCellFromQueryMetricUsesDirectDiagnostics1955(t *tes TypedColumnPrepareQ2GroupGlobalDictionaryRankMS: 0.034, TypedColumnPrepareQ2DistinctGlobalDictionaryRankMS: 0.035, - TypedColumnPrepareQ2GroupGlobalCodeRemapMS: 0.036, - TypedColumnPrepareQ2DistinctGlobalCodeRemapMS: 0.037, + TypedColumnPrepareQ2GroupGlobalLocalRankMS: 0.036, + TypedColumnPrepareQ2DistinctGlobalLocalRankMS: 0.037, + TypedColumnPrepareQ2GroupGlobalCodeRemapMS: 0.041, + TypedColumnPrepareQ2DistinctGlobalCodeRemapMS: 0.042, CompressionAttribution: columnStoreCompressionAttribution{ CompressionPolicyLabel: "default", @@ -2760,6 +2762,12 @@ func TestColumnStoreJSONBenchCellFromQueryMetricUsesDirectDiagnostics1955(t *tes if got, want := cell.TypedColumnPrepareQ2DistinctGlobalDictionaryRankMS, q.TypedColumnPrepareQ2DistinctGlobalDictionaryRankMS; got != want { t.Fatalf("typed_column_prepare_q2_distinct_global_dictionary_rank_duration_ms=%v want %v", got, want) } + if got, want := cell.TypedColumnPrepareQ2GroupGlobalLocalRankMS, q.TypedColumnPrepareQ2GroupGlobalLocalRankMS; got != want { + t.Fatalf("typed_column_prepare_q2_group_global_local_rank_duration_ms=%v want %v", got, want) + } + if got, want := cell.TypedColumnPrepareQ2DistinctGlobalLocalRankMS, q.TypedColumnPrepareQ2DistinctGlobalLocalRankMS; got != want { + t.Fatalf("typed_column_prepare_q2_distinct_global_local_rank_duration_ms=%v want %v", got, want) + } if got, want := cell.TypedColumnPrepareQ2GroupGlobalCodeRemapMS, q.TypedColumnPrepareQ2GroupGlobalCodeRemapMS; got != want { t.Fatalf("typed_column_prepare_q2_group_global_code_remap_duration_ms=%v want %v", got, want) } @@ -2877,6 +2885,8 @@ func TestRenderColumnStoreTypedColumnSetupDiagnosticsMarkdownQ2Splits3324(t *tes TypedColumnPrepareQ2DenseDistinctGlobalRanks: 99, TypedColumnPrepareQ2GroupGlobalDictionaryRankMS: 1.25, TypedColumnPrepareQ2DistinctGlobalDictionaryRankMS: 2.5, + TypedColumnPrepareQ2GroupGlobalLocalRankMS: 3.0, + TypedColumnPrepareQ2DistinctGlobalLocalRankMS: 3.5, TypedColumnPrepareQ2GroupGlobalCodeRemapMS: 3.75, TypedColumnPrepareQ2DistinctGlobalCodeRemapMS: 4.5, }, @@ -2888,6 +2898,8 @@ func TestRenderColumnStoreTypedColumnSetupDiagnosticsMarkdownQ2Splits3324(t *tes for _, want := range []string{ "q2 group global dict/rank ms", "q2 distinct global dict/rank ms", + "q2 group global local-rank ms", + "q2 distinct global local-rank ms", "q2 dense group global rank ms", "q2 dense distinct global rank ms", "q2 dense part local rank ms", @@ -2908,6 +2920,8 @@ func TestRenderColumnStoreTypedColumnSetupDiagnosticsMarkdownQ2Splits3324(t *tes "q2 distinct global-code remap ms", "1.250", "2.500", + "3.000", + "3.500", "3.750", "4.500", } {