Skip to content
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

Merged
merged 17 commits into from
Jul 12, 2018

Conversation

XuHuaiyu
Copy link
Contributor

@XuHuaiyu XuHuaiyu commented Jul 3, 2018

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)

@XuHuaiyu
Copy link
Contributor Author

XuHuaiyu commented Jul 3, 2018

PTAL @zz-jason

if isNull {
continue
}
if !e.isUnsigned {
Copy link
Member

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

}

func (e *maxMin4Int) UpdatePartialResult(sctx sessionctx.Context, rowsInGroup []chunk.Row, pr PartialResult) error {
tmp := (*partialResult4MaxMinInt)(pr)
Copy link
Member

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/

continue
}
if !e.isUnsigned {
if f0, f1 := int64(*tmp), int64(input); e.isMax && f1 > f0 || !e.isMax && f1 < f0 {
Copy link
Member

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

@zz-jason
Copy link
Member

zz-jason commented Jul 4, 2018

@XuHuaiyu When there is no input from child operator, we should return a NULL. Maybe we can do it in the stream aggregate operator.

"github.com/pingcap/tidb/util/chunk"
)

type partialResult4MaxMinInt int64
Copy link
Contributor

@crazycs520 crazycs520 Jul 5, 2018

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

@zz-jason zz-jason added this to the 2.1 milestone Jul 6, 2018
@XuHuaiyu
Copy link
Contributor Author

XuHuaiyu commented Jul 6, 2018

Wait for #7002 ,
please review it first.

}
if f0, f1 := *p, input; e.isMax && f1 > f0 || !e.isMax && f1 < f0 {
*p = f1
}
Copy link
Contributor

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
}

}

func (e *maxMin4Float32) AppendFinalResult2Chunk(sctx sessionctx.Context, pr PartialResult, chk *chunk.Chunk) error {
chk.AppendFloat32(e.ordinal, float32(*(*partialResult4MaxMinFloat32)(pr)))
Copy link
Contributor

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))

}
if f0, f1 := float32(*p), float32(input); e.isMax && f1 > f0 || !e.isMax && f1 < f0 {
*p = partialResult4MaxMinFloat32(f1)
}
Copy link
Contributor

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
		}

}
if f0, f1 := *p, uint64(input); e.isMax && f1 > f0 || !e.isMax && f1 < f0 {
*p = partialResult4MaxMinUint(f1)
}
Copy link
Contributor

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
		}

}

func (e *maxMin4Float64) AppendFinalResult2Chunk(sctx sessionctx.Context, pr PartialResult, chk *chunk.Chunk) error {
chk.AppendFloat64(e.ordinal, float64(*(*partialResult4MaxMinFloat64)(pr)))
Copy link
Contributor

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))

}
if f0, f1 := *p, input; e.isMax && f1 > f0 || !e.isMax && f1 < f0 {
*p = partialResult4MaxMinFloat64(f1)
}
Copy link
Contributor

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
		}

cmp := f1.Compare(f0)
if e.isMax && cmp == 1 || !e.isMax && cmp == -1 {
*p = partialResult4MaxMinDecimal(f1)
}
Copy link
Contributor

@crazycs520 crazycs520 Jul 6, 2018

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
		}

}

func (e *maxMin4Decimal) AppendFinalResult2Chunk(sctx sessionctx.Context, pr PartialResult, chk *chunk.Chunk) error {
chk.AppendMyDecimal(e.ordinal, (*types.MyDecimal)(*(*partialResult4MaxMinDecimal)(pr)))
Copy link
Contributor

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))

@XuHuaiyu
Copy link
Contributor Author

/run-all-tests

// 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
Copy link
Member

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

// 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
Copy link
Member

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.

Copy link
Contributor Author

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

if isNull {
continue
}
i := uint64(input)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/i/uintVal/?

}

type partialResult4MaxMinDecimal struct {
val *types.MyDecimal
Copy link
Member

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.

@@ -255,13 +255,14 @@ type maxMin4Decimal struct {

func (e *maxMin4Decimal) AllocPartialResult() PartialResult {
p := new(partialResult4MaxMinDecimal)
p.val = *new(types.MyDecimal)
Copy link
Member

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.

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)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto

@zz-jason
Copy link
Member

LGTM

@zz-jason zz-jason added type/enhancement The issue or PR belongs to an enhancement. status/LGT1 Indicates that a PR has LGTM 1. sig/execution SIG execution labels Jul 11, 2018
@XuHuaiyu
Copy link
Contributor Author

/run-all-tests

@XuHuaiyu
Copy link
Contributor Author

PTAL @crazycs520

@XuHuaiyu XuHuaiyu added the priority/P2 The issue has P2 priority. label Jul 12, 2018
@winoros
Copy link
Member

winoros commented Jul 12, 2018

Seems that there's no unit test in expression/aggfuncs.

Copy link
Member

@winoros winoros left a 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.

@XuHuaiyu XuHuaiyu merged commit 0ef52ac into pingcap:master Jul 12, 2018
@XuHuaiyu XuHuaiyu deleted the dev/refactor/max_min branch July 12, 2018 07:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
priority/P2 The issue has P2 priority. sig/execution SIG execution status/LGT1 Indicates that a PR has LGTM 1. type/enhancement The issue or PR belongs to an enhancement.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants