-
Notifications
You must be signed in to change notification settings - Fork 5.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
executor: support MAX/MIN in new evaluation framework partially #6971
Conversation
…actor/max_min Conflicts: executor/aggfuncs/aggfuncs.go executor/aggfuncs/builder.go
PTAL @zz-jason |
executor/aggfuncs/func_max_min.go
Outdated
if isNull { | ||
continue | ||
} | ||
if !e.isUnsigned { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
put this if
branch outside the for
loop
executor/aggfuncs/func_max_min.go
Outdated
} | ||
|
||
func (e *maxMin4Int) UpdatePartialResult(sctx sessionctx.Context, rowsInGroup []chunk.Row, pr PartialResult) error { | ||
tmp := (*partialResult4MaxMinInt)(pr) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
to keep consistent with avg
implementations: s/tmp/p/
executor/aggfuncs/func_max_min.go
Outdated
continue | ||
} | ||
if !e.isUnsigned { | ||
if f0, f1 := int64(*tmp), int64(input); e.isMax && f1 > f0 || !e.isMax && f1 < f0 { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no need to wrap a int64
@XuHuaiyu When there is no input from child operator, we should return a NULL. Maybe we can do it in the stream aggregate operator. |
executor/aggfuncs/func_max_min.go
Outdated
"github.com/pingcap/tidb/util/chunk" | ||
) | ||
|
||
type partialResult4MaxMinInt int64 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How aboult use type partialResult4MaxMinInt = int64
,
then we can use *(*partialResult4MaxMinInt)(pr)
instead of int64(*(*partialResult4MaxMinInt)(pr))
below partialResult4MaxMinDecimal, partialResult4MaxMinFloat32, partialResult4MaxMinFloat64 is same too.
here is a benchmark
type num1 = int
type num2 int
func BenchmarkT1(b *testing.B) {
var a1 num1
a1 = 1
for i := 0; i < b.N; {
i += a1
}
}
func BenchmarkT2(b *testing.B) {
var a2 num2
a2 = 1
for i := 0; i < b.N; {
i += int(a2)
}
}
▶ go test -bench=.
goos: darwin
goarch: amd64
pkg: test2
BenchmarkT1-8 2000000000 0.27 ns/op
BenchmarkT2-8 2000000000 0.54 ns/op
PASS
ok test2 1.757s
Wait for #7002 , |
executor/aggfuncs/func_max_min.go
Outdated
} | ||
if f0, f1 := *p, input; e.isMax && f1 > f0 || !e.isMax && f1 < f0 { | ||
*p = f1 | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if e.isMax && input > *p || !e.isMax && input < *p {
*p = input
}
executor/aggfuncs/func_max_min.go
Outdated
} | ||
|
||
func (e *maxMin4Float32) AppendFinalResult2Chunk(sctx sessionctx.Context, pr PartialResult, chk *chunk.Chunk) error { | ||
chk.AppendFloat32(e.ordinal, float32(*(*partialResult4MaxMinFloat32)(pr))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
chk.AppendFloat32(e.ordinal, *(*partialResult4MaxMinFloat32)(pr))
executor/aggfuncs/func_max_min.go
Outdated
} | ||
if f0, f1 := float32(*p), float32(input); e.isMax && f1 > f0 || !e.isMax && f1 < f0 { | ||
*p = partialResult4MaxMinFloat32(f1) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
float32Input := float32(input)
if !e.executed {
*p = float32Input
e.executed = true
continue
}
if e.isMax && float32Input > *p || !e.isMax && float32Input < *p {
*p = float32Input
}
executor/aggfuncs/func_max_min.go
Outdated
} | ||
if f0, f1 := *p, uint64(input); e.isMax && f1 > f0 || !e.isMax && f1 < f0 { | ||
*p = partialResult4MaxMinUint(f1) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
uint64Input := uint64(input)
if !e.executed {
*p = uint64Input
e.executed = true
continue
}
if e.isMax && uint64Input > *p || !e.isMax && uint64Input < *p {
*p = uint64Input
}
executor/aggfuncs/func_max_min.go
Outdated
} | ||
|
||
func (e *maxMin4Float64) AppendFinalResult2Chunk(sctx sessionctx.Context, pr PartialResult, chk *chunk.Chunk) error { | ||
chk.AppendFloat64(e.ordinal, float64(*(*partialResult4MaxMinFloat64)(pr))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
chk.AppendFloat64(e.ordinal, *(*partialResult4MaxMinFloat64)(pr))
executor/aggfuncs/func_max_min.go
Outdated
} | ||
if f0, f1 := *p, input; e.isMax && f1 > f0 || !e.isMax && f1 < f0 { | ||
*p = partialResult4MaxMinFloat64(f1) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if e.isMax && input > *p || !e.isMax && input < *p {
*p = input
}
executor/aggfuncs/func_max_min.go
Outdated
cmp := f1.Compare(f0) | ||
if e.isMax && cmp == 1 || !e.isMax && cmp == -1 { | ||
*p = partialResult4MaxMinDecimal(f1) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cmp := input.Compare(*p)
if e.isMax && cmp == 1 || !e.isMax && cmp == -1 {
*p = input
}
executor/aggfuncs/func_max_min.go
Outdated
} | ||
|
||
func (e *maxMin4Decimal) AppendFinalResult2Chunk(sctx sessionctx.Context, pr PartialResult, chk *chunk.Chunk) error { | ||
chk.AppendMyDecimal(e.ordinal, (*types.MyDecimal)(*(*partialResult4MaxMinDecimal)(pr))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
chk.AppendMyDecimal(e.ordinal, *(*partialResult4MaxMinDecimal)(pr))
…actor/max_min Conflicts: executor/aggfuncs/aggfuncs.go
796993e
to
4f2e0a4
Compare
/run-all-tests |
executor/aggfuncs/func_max_min.go
Outdated
// executed is used to indicates: | ||
// 1. whether the partial result is the initialization value which should not be compared during evaluation; | ||
// 2. whether all the values of arg are all null, if so, we should return null as the default value for MAX/MIN. | ||
executed bool |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this should be in the field of partial results, and should be reset for every group
… into dev/refactor/max_min :q!
…actor/max_min :q!
executor/aggfuncs/func_max_min.go
Outdated
// executed is used to indicates: | ||
// 1. whether the partial result is the initialization value which should not be compared during evaluation; | ||
// 2. whether all the values of arg are all null, if so, we should return null as the default value for MAX/MIN. | ||
executed bool |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we use isNull
instead? If isNull
is true, means there hasn't been any input values, and we should append a NULL
for this group in the Chunk.
executed
is confusion, because even it is false
, there can also exists a group with all NULL
values, and actually this partial result is executed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, isNull is better than executed
executor/aggfuncs/func_max_min.go
Outdated
if isNull { | ||
continue | ||
} | ||
i := uint64(input) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
s/i/uintVal/?
executor/aggfuncs/func_max_min.go
Outdated
} | ||
|
||
type partialResult4MaxMinDecimal struct { | ||
val *types.MyDecimal |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The input value may be changed when child operator reuses its input Chunk
, we should store the copied value to avoid this issue, change val *types.MyDecimal
to val types.MyDecimal
.
…actor/max_min �ý,�ý.�ý`:q!
executor/aggfuncs/func_max_min.go
Outdated
@@ -255,13 +255,14 @@ type maxMin4Decimal struct { | |||
|
|||
func (e *maxMin4Decimal) AllocPartialResult() PartialResult { | |||
p := new(partialResult4MaxMinDecimal) | |||
p.val = *new(types.MyDecimal) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This operation can be removed? since we only set it once the first non-NULL value comes.
executor/aggfuncs/func_max_min.go
Outdated
p.isNull = true | ||
return PartialResult(p) | ||
} | ||
|
||
func (e *maxMin4Decimal) ResetPartialResult(pr PartialResult) { | ||
p := (*partialResult4MaxMinDecimal)(pr) | ||
p.val = new(types.MyDecimal) | ||
p.val = *new(types.MyDecimal) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ditto
LGTM |
/run-all-tests |
PTAL @crazycs520 |
Seems that there's no unit test in expression/aggfuncs. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, but we need to find some way to add the unit tests.
What have you changed? (mandatory)
This PR implements max/min partially with new aggregation framework:
max/min( int )
max/min( float32 )
max/min( float64 )
max/min( decimal )
What are the type of the changes (mandatory)?
improvement
How has this PR been tested (mandatory)?
the existing test cases
Does this PR affect documentation (docs/docs-cn) update? (optional)
no
Refer to a related PR or issue link (optional)
#6952 #6852
Benchmark result if necessary (optional)
Add a few positive/negative examples (optional)