diff --git a/pkg/compare2/asc/dates/compare.go b/pkg/compare2/asc/dates/compare.go
new file mode 100644
index 0000000000000000000000000000000000000000..36330ac60afec76e599e07b012c8fd674f13432d
--- /dev/null
+++ b/pkg/compare2/asc/dates/compare.go
@@ -0,0 +1,60 @@
+// Copyright 2021 Matrix Origin
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package dates
+
+import (
+	"github.com/matrixorigin/matrixone/pkg/container/nulls"
+	"github.com/matrixorigin/matrixone/pkg/container/types"
+	"github.com/matrixorigin/matrixone/pkg/container/vector"
+	process "github.com/matrixorigin/matrixone/pkg/vm/process2"
+)
+
+func New() *compare {
+	return &compare{
+		xs: make([][]types.Date, 2),
+		ns: make([]*nulls.Nulls, 2),
+		vs: make([]*vector.Vector, 2),
+	}
+}
+
+func (c *compare) Vector() *vector.Vector {
+	return c.vs[0]
+}
+
+func (c *compare) Set(idx int, v *vector.Vector) {
+	c.vs[idx] = v
+	c.ns[idx] = v.Nsp
+	c.xs[idx] = v.Col.([]types.Date)
+}
+
+func (c *compare) Compare(veci, vecj int, vi, vj int64) int {
+	if c.xs[veci][vi] == c.xs[vecj][vj] {
+		return 0
+	}
+	if c.xs[veci][vi] < c.xs[vecj][vj] {
+		return -1
+	}
+	return +1
+}
+
+func (c *compare) Copy(vecSrc, vecDst int, src, dst int64, _ *process.Process) error {
+	if nulls.Any(c.ns[vecSrc]) && nulls.Contains(c.ns[vecSrc], (uint64(src))) {
+		nulls.Add(c.ns[vecDst], (uint64(dst)))
+	} else {
+		nulls.Del(c.ns[vecDst], (uint64(dst)))
+		c.xs[vecDst][dst] = c.xs[vecSrc][src]
+	}
+	return nil
+}
diff --git a/pkg/compare2/asc/dates/compare_test.go b/pkg/compare2/asc/dates/compare_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..ed4a27395b10c8502c9519c887d4584a14ca08c1
--- /dev/null
+++ b/pkg/compare2/asc/dates/compare_test.go
@@ -0,0 +1,56 @@
+// Copyright 2021 Matrix Origin
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package dates
+
+import (
+	"github.com/matrixorigin/matrixone/pkg/container/nulls"
+	"github.com/matrixorigin/matrixone/pkg/container/types"
+	"github.com/matrixorigin/matrixone/pkg/container/vector"
+	"github.com/stretchr/testify/require"
+	"testing"
+)
+
+func TestNew(t *testing.T) {
+	require.Equal(t, &compare{xs: make([][]types.Date, 2),
+		ns: make([]*nulls.Nulls, 2),
+		vs: make([]*vector.Vector, 2)}, New())
+}
+
+func TestCompare_Vector(t *testing.T) {
+	c := New()
+	c.vs[0] = vector.New(types.Type{Oid: types.T(types.T_date)})
+	require.Equal(t, vector.New(types.Type{Oid: types.T(types.T_date)}), c.Vector())
+}
+
+func TestCompare_Set(t *testing.T) {
+	c := New()
+	vector := vector.New(types.Type{Oid: types.T(types.T_date)})
+	c.Set(1, vector)
+	require.Equal(t, vector, c.vs[1])
+}
+
+func TestCompare_Compare(t *testing.T) {
+	c := New()
+	c.xs[0] = []types.Date{5, 6}
+	c.xs[1] = []types.Date{7, 8}
+	result := c.Compare(0, 1, 0, 0)
+	require.Equal(t, -1, result)
+	c.xs[1] = []types.Date{5, 6}
+	result = c.Compare(0, 1, 0, 0)
+	require.Equal(t, 0, result)
+	c.xs[1] = []types.Date{3, 4}
+	result = c.Compare(0, 1, 0, 0)
+	require.Equal(t, 1, result)
+}
diff --git a/pkg/compare2/asc/dates/types.go b/pkg/compare2/asc/dates/types.go
new file mode 100644
index 0000000000000000000000000000000000000000..9a330e7b8430769d6fa787e2cdf3066257647360
--- /dev/null
+++ b/pkg/compare2/asc/dates/types.go
@@ -0,0 +1,27 @@
+// Copyright 2021 Matrix Origin
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package dates
+
+import (
+	"github.com/matrixorigin/matrixone/pkg/container/nulls"
+	"github.com/matrixorigin/matrixone/pkg/container/types"
+	"github.com/matrixorigin/matrixone/pkg/container/vector"
+)
+
+type compare struct {
+	xs [][]types.Date
+	ns []*nulls.Nulls
+	vs []*vector.Vector
+}
diff --git a/pkg/compare2/asc/datetimes/compare.go b/pkg/compare2/asc/datetimes/compare.go
new file mode 100644
index 0000000000000000000000000000000000000000..bf19da68cfef624ae74e7e3bc2b424729c74f7c9
--- /dev/null
+++ b/pkg/compare2/asc/datetimes/compare.go
@@ -0,0 +1,60 @@
+// Copyright 2021 Matrix Origin
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package datetimes
+
+import (
+	"github.com/matrixorigin/matrixone/pkg/container/nulls"
+	"github.com/matrixorigin/matrixone/pkg/container/types"
+	"github.com/matrixorigin/matrixone/pkg/container/vector"
+	process "github.com/matrixorigin/matrixone/pkg/vm/process2"
+)
+
+func New() *compare {
+	return &compare{
+		xs: make([][]types.Datetime, 2),
+		ns: make([]*nulls.Nulls, 2),
+		vs: make([]*vector.Vector, 2),
+	}
+}
+
+func (c *compare) Vector() *vector.Vector {
+	return c.vs[0]
+}
+
+func (c *compare) Set(idx int, v *vector.Vector) {
+	c.vs[idx] = v
+	c.ns[idx] = v.Nsp
+	c.xs[idx] = v.Col.([]types.Datetime)
+}
+
+func (c *compare) Compare(veci, vecj int, vi, vj int64) int {
+	if c.xs[veci][vi] == c.xs[vecj][vj] {
+		return 0
+	}
+	if c.xs[veci][vi] < c.xs[vecj][vj] {
+		return -1
+	}
+	return +1
+}
+
+func (c *compare) Copy(vecSrc, vecDst int, src, dst int64, _ *process.Process) error {
+	if nulls.Any(c.ns[vecSrc]) && nulls.Contains(c.ns[vecSrc], (uint64(src))) {
+		nulls.Add(c.ns[vecDst], (uint64(dst)))
+	} else {
+		nulls.Del(c.ns[vecDst], (uint64(dst)))
+		c.xs[vecDst][dst] = c.xs[vecSrc][src]
+	}
+	return nil
+}
diff --git a/pkg/compare2/asc/datetimes/compare_test.go b/pkg/compare2/asc/datetimes/compare_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..2c14ef43d6bf286d99c2046fbac6d48530162618
--- /dev/null
+++ b/pkg/compare2/asc/datetimes/compare_test.go
@@ -0,0 +1,56 @@
+// Copyright 2021 Matrix Origin
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package datetimes
+
+import (
+	"github.com/matrixorigin/matrixone/pkg/container/nulls"
+	"github.com/matrixorigin/matrixone/pkg/container/types"
+	"github.com/matrixorigin/matrixone/pkg/container/vector"
+	"github.com/stretchr/testify/require"
+	"testing"
+)
+
+func TestNew(t *testing.T) {
+	require.Equal(t, &compare{xs: make([][]types.Datetime, 2),
+		ns: make([]*nulls.Nulls, 2),
+		vs: make([]*vector.Vector, 2)}, New())
+}
+
+func TestCompare_Vector(t *testing.T) {
+	c := New()
+	c.vs[0] = vector.New(types.Type{Oid: types.T(types.T_datetime)})
+	require.Equal(t, vector.New(types.Type{Oid: types.T(types.T_datetime)}), c.Vector())
+}
+
+func TestCompare_Set(t *testing.T) {
+	c := New()
+	vector := vector.New(types.Type{Oid: types.T(types.T_datetime)})
+	c.Set(1, vector)
+	require.Equal(t, vector, c.vs[1])
+}
+
+func TestCompare_Compare(t *testing.T) {
+	c := New()
+	c.xs[0] = []types.Datetime{5, 6}
+	c.xs[1] = []types.Datetime{7, 8}
+	result := c.Compare(0, 1, 0, 0)
+	require.Equal(t, -1, result)
+	c.xs[1] = []types.Datetime{5, 6}
+	result = c.Compare(0, 1, 0, 0)
+	require.Equal(t, 0, result)
+	c.xs[1] = []types.Datetime{3, 4}
+	result = c.Compare(0, 1, 0, 0)
+	require.Equal(t, 1, result)
+}
diff --git a/pkg/compare2/asc/datetimes/types.go b/pkg/compare2/asc/datetimes/types.go
new file mode 100644
index 0000000000000000000000000000000000000000..1e955f8f2aab72e1dbb30067d3d2a611d46bd6e9
--- /dev/null
+++ b/pkg/compare2/asc/datetimes/types.go
@@ -0,0 +1,27 @@
+// Copyright 2021 Matrix Origin
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package datetimes
+
+import (
+	"github.com/matrixorigin/matrixone/pkg/container/nulls"
+	"github.com/matrixorigin/matrixone/pkg/container/types"
+	"github.com/matrixorigin/matrixone/pkg/container/vector"
+)
+
+type compare struct {
+	xs [][]types.Datetime
+	ns []*nulls.Nulls
+	vs []*vector.Vector
+}
diff --git a/pkg/compare2/asc/float32s/compare.go b/pkg/compare2/asc/float32s/compare.go
new file mode 100644
index 0000000000000000000000000000000000000000..e922240f30958ec7ff1fc6c55853c7a579a49676
--- /dev/null
+++ b/pkg/compare2/asc/float32s/compare.go
@@ -0,0 +1,59 @@
+// Copyright 2021 Matrix Origin
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package float32s
+
+import (
+	"github.com/matrixorigin/matrixone/pkg/container/nulls"
+	"github.com/matrixorigin/matrixone/pkg/container/vector"
+	process "github.com/matrixorigin/matrixone/pkg/vm/process2"
+)
+
+func New() *compare {
+	return &compare{
+		xs: make([][]float32, 2),
+		ns: make([]*nulls.Nulls, 2),
+		vs: make([]*vector.Vector, 2),
+	}
+}
+
+func (c *compare) Vector() *vector.Vector {
+	return c.vs[0]
+}
+
+func (c *compare) Set(idx int, v *vector.Vector) {
+	c.vs[idx] = v
+	c.ns[idx] = v.Nsp
+	c.xs[idx] = v.Col.([]float32)
+}
+
+func (c *compare) Compare(veci, vecj int, vi, vj int64) int {
+	if c.xs[veci][vi] == c.xs[vecj][vj] {
+		return 0
+	}
+	if c.xs[veci][vi] < c.xs[vecj][vj] {
+		return -1
+	}
+	return +1
+}
+
+func (c *compare) Copy(vecSrc, vecDst int, src, dst int64, _ *process.Process) error {
+	if nulls.Any(c.ns[vecSrc]) && nulls.Contains(c.ns[vecSrc], (uint64(src))) {
+		nulls.Add(c.ns[vecDst], (uint64(dst)))
+	} else {
+		nulls.Del(c.ns[vecDst], (uint64(dst)))
+		c.xs[vecDst][dst] = c.xs[vecSrc][src]
+	}
+	return nil
+}
diff --git a/pkg/compare2/asc/float32s/compare_test.go b/pkg/compare2/asc/float32s/compare_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..9c19e9d4d55c458f8ccabac04d1062ae16fc0ca5
--- /dev/null
+++ b/pkg/compare2/asc/float32s/compare_test.go
@@ -0,0 +1,56 @@
+// Copyright 2021 Matrix Origin
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package float32s
+
+import (
+	"github.com/matrixorigin/matrixone/pkg/container/nulls"
+	"github.com/matrixorigin/matrixone/pkg/container/types"
+	"github.com/matrixorigin/matrixone/pkg/container/vector"
+	"github.com/stretchr/testify/require"
+	"testing"
+)
+
+func TestNew(t *testing.T) {
+	require.Equal(t, &compare{xs: make([][]float32, 2),
+		ns: make([]*nulls.Nulls, 2),
+		vs: make([]*vector.Vector, 2)}, New())
+}
+
+func TestCompare_Vector(t *testing.T) {
+	c := New()
+	c.vs[0] = vector.New(types.Type{Oid: types.T(types.T_float32)})
+	require.Equal(t, vector.New(types.Type{Oid: types.T(types.T_float32)}), c.Vector())
+}
+
+func TestCompare_Set(t *testing.T) {
+	c := New()
+	vector := vector.New(types.Type{Oid: types.T(types.T_float32)})
+	c.Set(1, vector)
+	require.Equal(t, vector, c.vs[1])
+}
+
+func TestCompare_Compare(t *testing.T) {
+	c := New()
+	c.xs[0] = []float32{5, 6}
+	c.xs[1] = []float32{7, 8}
+	result := c.Compare(0, 1, 0, 0)
+	require.Equal(t, -1, result)
+	c.xs[1] = []float32{5, 6}
+	result = c.Compare(0, 1, 0, 0)
+	require.Equal(t, 0, result)
+	c.xs[1] = []float32{3, 4}
+	result = c.Compare(0, 1, 0, 0)
+	require.Equal(t, 1, result)
+}
diff --git a/pkg/compare2/asc/float32s/types.go b/pkg/compare2/asc/float32s/types.go
new file mode 100644
index 0000000000000000000000000000000000000000..3cea8979d77cb7439ca10bd9b7cfd186bbf8243a
--- /dev/null
+++ b/pkg/compare2/asc/float32s/types.go
@@ -0,0 +1,26 @@
+// Copyright 2021 Matrix Origin
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package float32s
+
+import (
+	"github.com/matrixorigin/matrixone/pkg/container/nulls"
+	"github.com/matrixorigin/matrixone/pkg/container/vector"
+)
+
+type compare struct {
+	xs [][]float32
+	ns []*nulls.Nulls
+	vs []*vector.Vector
+}
diff --git a/pkg/compare2/asc/float64s/compare.go b/pkg/compare2/asc/float64s/compare.go
new file mode 100644
index 0000000000000000000000000000000000000000..4375971a3eba3ef4ba68ee3975d078419aa184ee
--- /dev/null
+++ b/pkg/compare2/asc/float64s/compare.go
@@ -0,0 +1,59 @@
+// Copyright 2021 Matrix Origin
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package float64s
+
+import (
+	"github.com/matrixorigin/matrixone/pkg/container/nulls"
+	"github.com/matrixorigin/matrixone/pkg/container/vector"
+	process "github.com/matrixorigin/matrixone/pkg/vm/process2"
+)
+
+func New() *compare {
+	return &compare{
+		xs: make([][]float64, 2),
+		ns: make([]*nulls.Nulls, 2),
+		vs: make([]*vector.Vector, 2),
+	}
+}
+
+func (c *compare) Vector() *vector.Vector {
+	return c.vs[0]
+}
+
+func (c *compare) Set(idx int, v *vector.Vector) {
+	c.vs[idx] = v
+	c.ns[idx] = v.Nsp
+	c.xs[idx] = v.Col.([]float64)
+}
+
+func (c *compare) Compare(veci, vecj int, vi, vj int64) int {
+	if c.xs[veci][vi] == c.xs[vecj][vj] {
+		return 0
+	}
+	if c.xs[veci][vi] < c.xs[vecj][vj] {
+		return -1
+	}
+	return +1
+}
+
+func (c *compare) Copy(vecSrc, vecDst int, src, dst int64, _ *process.Process) error {
+	if nulls.Any(c.ns[vecSrc]) && nulls.Contains(c.ns[vecSrc], (uint64(src))) {
+		nulls.Add(c.ns[vecDst], (uint64(dst)))
+	} else {
+		nulls.Del(c.ns[vecDst], (uint64(dst)))
+		c.xs[vecDst][dst] = c.xs[vecSrc][src]
+	}
+	return nil
+}
diff --git a/pkg/compare2/asc/float64s/compare_test.go b/pkg/compare2/asc/float64s/compare_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..511c02492b0260d5a5327741bb3ac9bf52255320
--- /dev/null
+++ b/pkg/compare2/asc/float64s/compare_test.go
@@ -0,0 +1,56 @@
+// Copyright 2021 Matrix Origin
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package float64s
+
+import (
+	"github.com/matrixorigin/matrixone/pkg/container/nulls"
+	"github.com/matrixorigin/matrixone/pkg/container/types"
+	"github.com/matrixorigin/matrixone/pkg/container/vector"
+	"github.com/stretchr/testify/require"
+	"testing"
+)
+
+func TestNew(t *testing.T) {
+	require.Equal(t, &compare{xs: make([][]float64, 2),
+		ns: make([]*nulls.Nulls, 2),
+		vs: make([]*vector.Vector, 2)}, New())
+}
+
+func TestCompare_Vector(t *testing.T) {
+	c := New()
+	c.vs[0] = vector.New(types.Type{Oid: types.T(types.T_float64)})
+	require.Equal(t, vector.New(types.Type{Oid: types.T(types.T_float64)}), c.Vector())
+}
+
+func TestCompare_Set(t *testing.T) {
+	c := New()
+	vector := vector.New(types.Type{Oid: types.T(types.T_float64)})
+	c.Set(1, vector)
+	require.Equal(t, vector, c.vs[1])
+}
+
+func TestCompare_Compare(t *testing.T) {
+	c := New()
+	c.xs[0] = []float64{5, 6}
+	c.xs[1] = []float64{7, 8}
+	result := c.Compare(0, 1, 0, 0)
+	require.Equal(t, -1, result)
+	c.xs[1] = []float64{5, 6}
+	result = c.Compare(0, 1, 0, 0)
+	require.Equal(t, 0, result)
+	c.xs[1] = []float64{3, 4}
+	result = c.Compare(0, 1, 0, 0)
+	require.Equal(t, 1, result)
+}
diff --git a/pkg/compare2/asc/float64s/types.go b/pkg/compare2/asc/float64s/types.go
new file mode 100644
index 0000000000000000000000000000000000000000..c0169c928662dfe6158052be38f114688098c25e
--- /dev/null
+++ b/pkg/compare2/asc/float64s/types.go
@@ -0,0 +1,26 @@
+// Copyright 2021 Matrix Origin
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package float64s
+
+import (
+	"github.com/matrixorigin/matrixone/pkg/container/nulls"
+	"github.com/matrixorigin/matrixone/pkg/container/vector"
+)
+
+type compare struct {
+	xs [][]float64
+	ns []*nulls.Nulls
+	vs []*vector.Vector
+}
diff --git a/pkg/compare2/asc/int16s/compare.go b/pkg/compare2/asc/int16s/compare.go
new file mode 100644
index 0000000000000000000000000000000000000000..d98666540ecb475e1276d57ca28301a4d76a8cf6
--- /dev/null
+++ b/pkg/compare2/asc/int16s/compare.go
@@ -0,0 +1,59 @@
+// Copyright 2021 Matrix Origin
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package int16s
+
+import (
+	"github.com/matrixorigin/matrixone/pkg/container/nulls"
+	"github.com/matrixorigin/matrixone/pkg/container/vector"
+	process "github.com/matrixorigin/matrixone/pkg/vm/process2"
+)
+
+func New() *compare {
+	return &compare{
+		xs: make([][]int16, 2),
+		ns: make([]*nulls.Nulls, 2),
+		vs: make([]*vector.Vector, 2),
+	}
+}
+
+func (c *compare) Vector() *vector.Vector {
+	return c.vs[0]
+}
+
+func (c *compare) Set(idx int, v *vector.Vector) {
+	c.vs[idx] = v
+	c.ns[idx] = v.Nsp
+	c.xs[idx] = v.Col.([]int16)
+}
+
+func (c *compare) Compare(veci, vecj int, vi, vj int64) int {
+	if c.xs[veci][vi] == c.xs[vecj][vj] {
+		return 0
+	}
+	if c.xs[veci][vi] < c.xs[vecj][vj] {
+		return -1
+	}
+	return +1
+}
+
+func (c *compare) Copy(vecSrc, vecDst int, src, dst int64, _ *process.Process) error {
+	if nulls.Any(c.ns[vecSrc]) && nulls.Contains(c.ns[vecSrc], (uint64(src))) {
+		nulls.Add(c.ns[vecDst], (uint64(dst)))
+	} else {
+		nulls.Del(c.ns[vecDst], (uint64(dst)))
+		c.xs[vecDst][dst] = c.xs[vecSrc][src]
+	}
+	return nil
+}
diff --git a/pkg/compare2/asc/int16s/compare_test.go b/pkg/compare2/asc/int16s/compare_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..7573df4efe26465a29738b7cf9e8d6c0ec843791
--- /dev/null
+++ b/pkg/compare2/asc/int16s/compare_test.go
@@ -0,0 +1,56 @@
+// Copyright 2021 Matrix Origin
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package int16s
+
+import (
+	"github.com/matrixorigin/matrixone/pkg/container/nulls"
+	"github.com/matrixorigin/matrixone/pkg/container/types"
+	"github.com/matrixorigin/matrixone/pkg/container/vector"
+	"github.com/stretchr/testify/require"
+	"testing"
+)
+
+func TestNew(t *testing.T) {
+	require.Equal(t, &compare{xs: make([][]int16, 2),
+		ns: make([]*nulls.Nulls, 2),
+		vs: make([]*vector.Vector, 2)}, New())
+}
+
+func TestCompare_Vector(t *testing.T) {
+	c := New()
+	c.vs[0] = vector.New(types.Type{Oid: types.T(types.T_int16)})
+	require.Equal(t, vector.New(types.Type{Oid: types.T(types.T_int16)}), c.Vector())
+}
+
+func TestCompare_Set(t *testing.T) {
+	c := New()
+	vector := vector.New(types.Type{Oid: types.T(types.T_int16)})
+	c.Set(1, vector)
+	require.Equal(t, vector, c.vs[1])
+}
+
+func TestCompare_Compare(t *testing.T) {
+	c := New()
+	c.xs[0] = []int16{5, 6}
+	c.xs[1] = []int16{7, 8}
+	result := c.Compare(0, 1, 0, 0)
+	require.Equal(t, -1, result)
+	c.xs[1] = []int16{5, 6}
+	result = c.Compare(0, 1, 0, 0)
+	require.Equal(t, 0, result)
+	c.xs[1] = []int16{3, 4}
+	result = c.Compare(0, 1, 0, 0)
+	require.Equal(t, 1, result)
+}
diff --git a/pkg/compare2/asc/int16s/types.go b/pkg/compare2/asc/int16s/types.go
new file mode 100644
index 0000000000000000000000000000000000000000..e176b67fc8ad7c8f0096d676011f43bacc9290f7
--- /dev/null
+++ b/pkg/compare2/asc/int16s/types.go
@@ -0,0 +1,26 @@
+// Copyright 2021 Matrix Origin
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package int16s
+
+import (
+	"github.com/matrixorigin/matrixone/pkg/container/nulls"
+	"github.com/matrixorigin/matrixone/pkg/container/vector"
+)
+
+type compare struct {
+	xs [][]int16
+	ns []*nulls.Nulls
+	vs []*vector.Vector
+}
diff --git a/pkg/compare2/asc/int32s/compare.go b/pkg/compare2/asc/int32s/compare.go
new file mode 100644
index 0000000000000000000000000000000000000000..260a52419d8517cdc35ce1c4720fbbf2c3251275
--- /dev/null
+++ b/pkg/compare2/asc/int32s/compare.go
@@ -0,0 +1,59 @@
+// Copyright 2021 Matrix Origin
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package int32s
+
+import (
+	"github.com/matrixorigin/matrixone/pkg/container/nulls"
+	"github.com/matrixorigin/matrixone/pkg/container/vector"
+	process "github.com/matrixorigin/matrixone/pkg/vm/process2"
+)
+
+func New() *compare {
+	return &compare{
+		xs: make([][]int32, 2),
+		ns: make([]*nulls.Nulls, 2),
+		vs: make([]*vector.Vector, 2),
+	}
+}
+
+func (c *compare) Vector() *vector.Vector {
+	return c.vs[0]
+}
+
+func (c *compare) Set(idx int, v *vector.Vector) {
+	c.vs[idx] = v
+	c.ns[idx] = v.Nsp
+	c.xs[idx] = v.Col.([]int32)
+}
+
+func (c *compare) Compare(veci, vecj int, vi, vj int64) int {
+	if c.xs[veci][vi] == c.xs[vecj][vj] {
+		return 0
+	}
+	if c.xs[veci][vi] < c.xs[vecj][vj] {
+		return -1
+	}
+	return +1
+}
+
+func (c *compare) Copy(vecSrc, vecDst int, src, dst int64, _ *process.Process) error {
+	if nulls.Any(c.ns[vecSrc]) && nulls.Contains(c.ns[vecSrc], (uint64(src))) {
+		nulls.Add(c.ns[vecDst], (uint64(dst)))
+	} else {
+		nulls.Del(c.ns[vecDst], (uint64(dst)))
+		c.xs[vecDst][dst] = c.xs[vecSrc][src]
+	}
+	return nil
+}
diff --git a/pkg/compare2/asc/int32s/compare_test.go b/pkg/compare2/asc/int32s/compare_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..6e80fb23296c8313f5dcc4f240a467456b0b3cf5
--- /dev/null
+++ b/pkg/compare2/asc/int32s/compare_test.go
@@ -0,0 +1,56 @@
+// Copyright 2021 Matrix Origin
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package int32s
+
+import (
+	"github.com/matrixorigin/matrixone/pkg/container/nulls"
+	"github.com/matrixorigin/matrixone/pkg/container/types"
+	"github.com/matrixorigin/matrixone/pkg/container/vector"
+	"github.com/stretchr/testify/require"
+	"testing"
+)
+
+func TestNew(t *testing.T) {
+	require.Equal(t, &compare{xs: make([][]int32, 2),
+		ns: make([]*nulls.Nulls, 2),
+		vs: make([]*vector.Vector, 2)}, New())
+}
+
+func TestCompare_Vector(t *testing.T) {
+	c := New()
+	c.vs[0] = vector.New(types.Type{Oid: types.T(types.T_int32)})
+	require.Equal(t, vector.New(types.Type{Oid: types.T(types.T_int32)}), c.Vector())
+}
+
+func TestCompare_Set(t *testing.T) {
+	c := New()
+	vector := vector.New(types.Type{Oid: types.T(types.T_int32)})
+	c.Set(1, vector)
+	require.Equal(t, vector, c.vs[1])
+}
+
+func TestCompare_Compare(t *testing.T) {
+	c := New()
+	c.xs[0] = []int32{5, 6}
+	c.xs[1] = []int32{7, 8}
+	result := c.Compare(0, 1, 0, 0)
+	require.Equal(t, -1, result)
+	c.xs[1] = []int32{5, 6}
+	result = c.Compare(0, 1, 0, 0)
+	require.Equal(t, 0, result)
+	c.xs[1] = []int32{3, 4}
+	result = c.Compare(0, 1, 0, 0)
+	require.Equal(t, 1, result)
+}
diff --git a/pkg/compare2/asc/int32s/types.go b/pkg/compare2/asc/int32s/types.go
new file mode 100644
index 0000000000000000000000000000000000000000..490907c608677d7867d149cdd4ed944be70508b8
--- /dev/null
+++ b/pkg/compare2/asc/int32s/types.go
@@ -0,0 +1,26 @@
+// Copyright 2021 Matrix Origin
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package int32s
+
+import (
+	"github.com/matrixorigin/matrixone/pkg/container/nulls"
+	"github.com/matrixorigin/matrixone/pkg/container/vector"
+)
+
+type compare struct {
+	xs [][]int32
+	ns []*nulls.Nulls
+	vs []*vector.Vector
+}
diff --git a/pkg/compare2/asc/int64s/compare.go b/pkg/compare2/asc/int64s/compare.go
new file mode 100644
index 0000000000000000000000000000000000000000..6a8be5308e68d830807facc6ba4e20a6772b014b
--- /dev/null
+++ b/pkg/compare2/asc/int64s/compare.go
@@ -0,0 +1,59 @@
+// Copyright 2021 Matrix Origin
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package int64s
+
+import (
+	"github.com/matrixorigin/matrixone/pkg/container/nulls"
+	"github.com/matrixorigin/matrixone/pkg/container/vector"
+	process "github.com/matrixorigin/matrixone/pkg/vm/process2"
+)
+
+func New() *compare {
+	return &compare{
+		xs: make([][]int64, 2),
+		ns: make([]*nulls.Nulls, 2),
+		vs: make([]*vector.Vector, 2),
+	}
+}
+
+func (c *compare) Vector() *vector.Vector {
+	return c.vs[0]
+}
+
+func (c *compare) Set(idx int, v *vector.Vector) {
+	c.vs[idx] = v
+	c.ns[idx] = v.Nsp
+	c.xs[idx] = v.Col.([]int64)
+}
+
+func (c *compare) Compare(veci, vecj int, vi, vj int64) int {
+	if c.xs[veci][vi] == c.xs[vecj][vj] {
+		return 0
+	}
+	if c.xs[veci][vi] < c.xs[vecj][vj] {
+		return -1
+	}
+	return +1
+}
+
+func (c *compare) Copy(vecSrc, vecDst int, src, dst int64, _ *process.Process) error {
+	if nulls.Any(c.ns[vecSrc]) && nulls.Contains(c.ns[vecSrc], (uint64(src))) {
+		nulls.Add(c.ns[vecDst], (uint64(dst)))
+	} else {
+		nulls.Del(c.ns[vecDst], (uint64(dst)))
+		c.xs[vecDst][dst] = c.xs[vecSrc][src]
+	}
+	return nil
+}
diff --git a/pkg/compare2/asc/int64s/compare_test.go b/pkg/compare2/asc/int64s/compare_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..2219c4c98b4700ccbf34dd5ea19af020b3bb4e69
--- /dev/null
+++ b/pkg/compare2/asc/int64s/compare_test.go
@@ -0,0 +1,56 @@
+// Copyright 2021 Matrix Origin
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package int64s
+
+import (
+	"github.com/matrixorigin/matrixone/pkg/container/nulls"
+	"github.com/matrixorigin/matrixone/pkg/container/types"
+	"github.com/matrixorigin/matrixone/pkg/container/vector"
+	"github.com/stretchr/testify/require"
+	"testing"
+)
+
+func TestNew(t *testing.T) {
+	require.Equal(t, &compare{xs: make([][]int64, 2),
+		ns: make([]*nulls.Nulls, 2),
+		vs: make([]*vector.Vector, 2)}, New())
+}
+
+func TestCompare_Vector(t *testing.T) {
+	c := New()
+	c.vs[0] = vector.New(types.Type{Oid: types.T(types.T_int64)})
+	require.Equal(t, vector.New(types.Type{Oid: types.T(types.T_int64)}), c.Vector())
+}
+
+func TestCompare_Set(t *testing.T) {
+	c := New()
+	vector := vector.New(types.Type{Oid: types.T(types.T_int64)})
+	c.Set(1, vector)
+	require.Equal(t, vector, c.vs[1])
+}
+
+func TestCompare_Compare(t *testing.T) {
+	c := New()
+	c.xs[0] = []int64{5, 6}
+	c.xs[1] = []int64{7, 8}
+	result := c.Compare(0, 1, 0, 0)
+	require.Equal(t, -1, result)
+	c.xs[1] = []int64{5, 6}
+	result = c.Compare(0, 1, 0, 0)
+	require.Equal(t, 0, result)
+	c.xs[1] = []int64{3, 4}
+	result = c.Compare(0, 1, 0, 0)
+	require.Equal(t, 1, result)
+}
diff --git a/pkg/compare2/asc/int64s/types.go b/pkg/compare2/asc/int64s/types.go
new file mode 100644
index 0000000000000000000000000000000000000000..1ced17e8fb4363eb638b04001e9e5b25abcd80cf
--- /dev/null
+++ b/pkg/compare2/asc/int64s/types.go
@@ -0,0 +1,26 @@
+// Copyright 2021 Matrix Origin
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package int64s
+
+import (
+	"github.com/matrixorigin/matrixone/pkg/container/nulls"
+	"github.com/matrixorigin/matrixone/pkg/container/vector"
+)
+
+type compare struct {
+	xs [][]int64
+	ns []*nulls.Nulls
+	vs []*vector.Vector
+}
diff --git a/pkg/compare2/asc/int8s/compare.go b/pkg/compare2/asc/int8s/compare.go
new file mode 100644
index 0000000000000000000000000000000000000000..c0ef46fc8683510da47bfda18d6fe90f074ddb18
--- /dev/null
+++ b/pkg/compare2/asc/int8s/compare.go
@@ -0,0 +1,59 @@
+// Copyright 2021 Matrix Origin
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package int8s
+
+import (
+	"github.com/matrixorigin/matrixone/pkg/container/nulls"
+	"github.com/matrixorigin/matrixone/pkg/container/vector"
+	process "github.com/matrixorigin/matrixone/pkg/vm/process2"
+)
+
+func New() *compare {
+	return &compare{
+		xs: make([][]int8, 2),
+		ns: make([]*nulls.Nulls, 2),
+		vs: make([]*vector.Vector, 2),
+	}
+}
+
+func (c *compare) Vector() *vector.Vector {
+	return c.vs[0]
+}
+
+func (c *compare) Set(idx int, v *vector.Vector) {
+	c.vs[idx] = v
+	c.ns[idx] = v.Nsp
+	c.xs[idx] = v.Col.([]int8)
+}
+
+func (c *compare) Compare(veci, vecj int, vi, vj int64) int {
+	if c.xs[veci][vi] == c.xs[vecj][vj] {
+		return 0
+	}
+	if c.xs[veci][vi] < c.xs[vecj][vj] {
+		return -1
+	}
+	return +1
+}
+
+func (c *compare) Copy(vecSrc, vecDst int, src, dst int64, _ *process.Process) error {
+	if nulls.Any(c.ns[vecSrc]) && nulls.Contains(c.ns[vecSrc], (uint64(src))) {
+		nulls.Add(c.ns[vecDst], (uint64(dst)))
+	} else {
+		nulls.Del(c.ns[vecDst], (uint64(dst)))
+		c.xs[vecDst][dst] = c.xs[vecSrc][src]
+	}
+	return nil
+}
diff --git a/pkg/compare2/asc/int8s/compare_test.go b/pkg/compare2/asc/int8s/compare_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..4266cc1e818c2ab224b46504176c1d99a746cf51
--- /dev/null
+++ b/pkg/compare2/asc/int8s/compare_test.go
@@ -0,0 +1,56 @@
+// Copyright 2021 Matrix Origin
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package int8s
+
+import (
+	"github.com/matrixorigin/matrixone/pkg/container/nulls"
+	"github.com/matrixorigin/matrixone/pkg/container/types"
+	"github.com/matrixorigin/matrixone/pkg/container/vector"
+	"github.com/stretchr/testify/require"
+	"testing"
+)
+
+func TestNew(t *testing.T) {
+	require.Equal(t, &compare{xs: make([][]int8, 2),
+		ns: make([]*nulls.Nulls, 2),
+		vs: make([]*vector.Vector, 2)}, New())
+}
+
+func TestCompare_Vector(t *testing.T) {
+	c := New()
+	c.vs[0] = vector.New(types.Type{Oid: types.T(types.T_int8)})
+	require.Equal(t, vector.New(types.Type{Oid: types.T(types.T_int8)}), c.Vector())
+}
+
+func TestCompare_Set(t *testing.T) {
+	c := New()
+	vector := vector.New(types.Type{Oid: types.T(types.T_int8)})
+	c.Set(1, vector)
+	require.Equal(t, vector, c.vs[1])
+}
+
+func TestCompare_Compare(t *testing.T) {
+	c := New()
+	c.xs[0] = []int8{5, 6}
+	c.xs[1] = []int8{7, 8}
+	result := c.Compare(0, 1, 0, 0)
+	require.Equal(t, -1, result)
+	c.xs[1] = []int8{5, 6}
+	result = c.Compare(0, 1, 0, 0)
+	require.Equal(t, 0, result)
+	c.xs[1] = []int8{3, 4}
+	result = c.Compare(0, 1, 0, 0)
+	require.Equal(t, 1, result)
+}
diff --git a/pkg/compare2/asc/int8s/types.go b/pkg/compare2/asc/int8s/types.go
new file mode 100644
index 0000000000000000000000000000000000000000..88fb01230556558875c76f8024226aaeb54a5244
--- /dev/null
+++ b/pkg/compare2/asc/int8s/types.go
@@ -0,0 +1,26 @@
+// Copyright 2021 Matrix Origin
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package int8s
+
+import (
+	"github.com/matrixorigin/matrixone/pkg/container/nulls"
+	"github.com/matrixorigin/matrixone/pkg/container/vector"
+)
+
+type compare struct {
+	xs [][]int8
+	ns []*nulls.Nulls
+	vs []*vector.Vector
+}
diff --git a/pkg/compare2/asc/uint16s/compare.go b/pkg/compare2/asc/uint16s/compare.go
new file mode 100644
index 0000000000000000000000000000000000000000..538bdb4d1c03166b3d6f3c4f69bbea8a269d2564
--- /dev/null
+++ b/pkg/compare2/asc/uint16s/compare.go
@@ -0,0 +1,59 @@
+// Copyright 2021 Matrix Origin
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package uint16s
+
+import (
+	"github.com/matrixorigin/matrixone/pkg/container/nulls"
+	"github.com/matrixorigin/matrixone/pkg/container/vector"
+	process "github.com/matrixorigin/matrixone/pkg/vm/process2"
+)
+
+func New() *compare {
+	return &compare{
+		xs: make([][]uint16, 2),
+		ns: make([]*nulls.Nulls, 2),
+		vs: make([]*vector.Vector, 2),
+	}
+}
+
+func (c *compare) Vector() *vector.Vector {
+	return c.vs[0]
+}
+
+func (c *compare) Set(idx int, v *vector.Vector) {
+	c.vs[idx] = v
+	c.ns[idx] = v.Nsp
+	c.xs[idx] = v.Col.([]uint16)
+}
+
+func (c *compare) Compare(veci, vecj int, vi, vj int64) int {
+	if c.xs[veci][vi] == c.xs[vecj][vj] {
+		return 0
+	}
+	if c.xs[veci][vi] < c.xs[vecj][vj] {
+		return -1
+	}
+	return +1
+}
+
+func (c *compare) Copy(vecSrc, vecDst int, src, dst int64, _ *process.Process) error {
+	if nulls.Any(c.ns[vecSrc]) && nulls.Contains(c.ns[vecSrc], (uint64(src))) {
+		nulls.Add(c.ns[vecDst], (uint64(dst)))
+	} else {
+		nulls.Del(c.ns[vecDst], (uint64(dst)))
+		c.xs[vecDst][dst] = c.xs[vecSrc][src]
+	}
+	return nil
+}
diff --git a/pkg/compare2/asc/uint16s/compare_test.go b/pkg/compare2/asc/uint16s/compare_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..254479ac2932ec64e87889a83371a150cdea7344
--- /dev/null
+++ b/pkg/compare2/asc/uint16s/compare_test.go
@@ -0,0 +1,56 @@
+// Copyright 2021 Matrix Origin
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package uint16s
+
+import (
+	"github.com/matrixorigin/matrixone/pkg/container/nulls"
+	"github.com/matrixorigin/matrixone/pkg/container/types"
+	"github.com/matrixorigin/matrixone/pkg/container/vector"
+	"github.com/stretchr/testify/require"
+	"testing"
+)
+
+func TestNew(t *testing.T) {
+	require.Equal(t, &compare{xs: make([][]uint16, 2),
+		ns: make([]*nulls.Nulls, 2),
+		vs: make([]*vector.Vector, 2)}, New())
+}
+
+func TestCompare_Vector(t *testing.T) {
+	c := New()
+	c.vs[0] = vector.New(types.Type{Oid: types.T(types.T_uint16)})
+	require.Equal(t, vector.New(types.Type{Oid: types.T(types.T_uint16)}), c.Vector())
+}
+
+func TestCompare_Set(t *testing.T) {
+	c := New()
+	vector := vector.New(types.Type{Oid: types.T(types.T_uint16)})
+	c.Set(1, vector)
+	require.Equal(t, vector, c.vs[1])
+}
+
+func TestCompare_Compare(t *testing.T) {
+	c := New()
+	c.xs[0] = []uint16{5, 6}
+	c.xs[1] = []uint16{7, 8}
+	result := c.Compare(0, 1, 0, 0)
+	require.Equal(t, -1, result)
+	c.xs[1] = []uint16{5, 6}
+	result = c.Compare(0, 1, 0, 0)
+	require.Equal(t, 0, result)
+	c.xs[1] = []uint16{3, 4}
+	result = c.Compare(0, 1, 0, 0)
+	require.Equal(t, 1, result)
+}
diff --git a/pkg/compare2/asc/uint16s/types.go b/pkg/compare2/asc/uint16s/types.go
new file mode 100644
index 0000000000000000000000000000000000000000..86a81895d6ece757947eae89c464c0ed570905fc
--- /dev/null
+++ b/pkg/compare2/asc/uint16s/types.go
@@ -0,0 +1,26 @@
+// Copyright 2021 Matrix Origin
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package uint16s
+
+import (
+	"github.com/matrixorigin/matrixone/pkg/container/nulls"
+	"github.com/matrixorigin/matrixone/pkg/container/vector"
+)
+
+type compare struct {
+	xs [][]uint16
+	ns []*nulls.Nulls
+	vs []*vector.Vector
+}
diff --git a/pkg/compare2/asc/uint32s/compare.go b/pkg/compare2/asc/uint32s/compare.go
new file mode 100644
index 0000000000000000000000000000000000000000..82c2db10cc9d492eaeed08631fb238cd3559bd53
--- /dev/null
+++ b/pkg/compare2/asc/uint32s/compare.go
@@ -0,0 +1,59 @@
+// Copyright 2021 Matrix Origin
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package uint32s
+
+import (
+	"github.com/matrixorigin/matrixone/pkg/container/nulls"
+	"github.com/matrixorigin/matrixone/pkg/container/vector"
+	process "github.com/matrixorigin/matrixone/pkg/vm/process2"
+)
+
+func New() *compare {
+	return &compare{
+		xs: make([][]uint32, 2),
+		ns: make([]*nulls.Nulls, 2),
+		vs: make([]*vector.Vector, 2),
+	}
+}
+
+func (c *compare) Vector() *vector.Vector {
+	return c.vs[0]
+}
+
+func (c *compare) Set(idx int, v *vector.Vector) {
+	c.vs[idx] = v
+	c.ns[idx] = v.Nsp
+	c.xs[idx] = v.Col.([]uint32)
+}
+
+func (c *compare) Compare(veci, vecj int, vi, vj int64) int {
+	if c.xs[veci][vi] == c.xs[vecj][vj] {
+		return 0
+	}
+	if c.xs[veci][vi] < c.xs[vecj][vj] {
+		return -1
+	}
+	return +1
+}
+
+func (c *compare) Copy(vecSrc, vecDst int, src, dst int64, _ *process.Process) error {
+	if nulls.Any(c.ns[vecSrc]) && nulls.Contains(c.ns[vecSrc], (uint64(src))) {
+		nulls.Add(c.ns[vecDst], (uint64(dst)))
+	} else {
+		nulls.Del(c.ns[vecDst], (uint64(dst)))
+		c.xs[vecDst][dst] = c.xs[vecSrc][src]
+	}
+	return nil
+}
diff --git a/pkg/compare2/asc/uint32s/compare_test.go b/pkg/compare2/asc/uint32s/compare_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..1d007fcdcc9d93cca36e91f34382ce0c1311d674
--- /dev/null
+++ b/pkg/compare2/asc/uint32s/compare_test.go
@@ -0,0 +1,56 @@
+// Copyright 2021 Matrix Origin
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package uint32s
+
+import (
+	"github.com/matrixorigin/matrixone/pkg/container/nulls"
+	"github.com/matrixorigin/matrixone/pkg/container/types"
+	"github.com/matrixorigin/matrixone/pkg/container/vector"
+	"github.com/stretchr/testify/require"
+	"testing"
+)
+
+func TestNew(t *testing.T) {
+	require.Equal(t, &compare{xs: make([][]uint32, 2),
+		ns: make([]*nulls.Nulls, 2),
+		vs: make([]*vector.Vector, 2)}, New())
+}
+
+func TestCompare_Vector(t *testing.T) {
+	c := New()
+	c.vs[0] = vector.New(types.Type{Oid: types.T(types.T_uint32)})
+	require.Equal(t, vector.New(types.Type{Oid: types.T(types.T_uint32)}), c.Vector())
+}
+
+func TestCompare_Set(t *testing.T) {
+	c := New()
+	vector := vector.New(types.Type{Oid: types.T(types.T_uint32)})
+	c.Set(1, vector)
+	require.Equal(t, vector, c.vs[1])
+}
+
+func TestCompare_Compare(t *testing.T) {
+	c := New()
+	c.xs[0] = []uint32{5, 6}
+	c.xs[1] = []uint32{7, 8}
+	result := c.Compare(0, 1, 0, 0)
+	require.Equal(t, -1, result)
+	c.xs[1] = []uint32{5, 6}
+	result = c.Compare(0, 1, 0, 0)
+	require.Equal(t, 0, result)
+	c.xs[1] = []uint32{3, 4}
+	result = c.Compare(0, 1, 0, 0)
+	require.Equal(t, 1, result)
+}
diff --git a/pkg/compare2/asc/uint32s/types.go b/pkg/compare2/asc/uint32s/types.go
new file mode 100644
index 0000000000000000000000000000000000000000..e925514391ba81ec1a105a11c20ee90ab1604945
--- /dev/null
+++ b/pkg/compare2/asc/uint32s/types.go
@@ -0,0 +1,26 @@
+// Copyright 2021 Matrix Origin
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package uint32s
+
+import (
+	"github.com/matrixorigin/matrixone/pkg/container/nulls"
+	"github.com/matrixorigin/matrixone/pkg/container/vector"
+)
+
+type compare struct {
+	xs [][]uint32
+	ns []*nulls.Nulls
+	vs []*vector.Vector
+}
diff --git a/pkg/compare2/asc/uint64s/compare.go b/pkg/compare2/asc/uint64s/compare.go
new file mode 100644
index 0000000000000000000000000000000000000000..db01aabbe6a3e8e0cf58db3f0f8603960732227a
--- /dev/null
+++ b/pkg/compare2/asc/uint64s/compare.go
@@ -0,0 +1,59 @@
+// Copyright 2021 Matrix Origin
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package uint64s
+
+import (
+	"github.com/matrixorigin/matrixone/pkg/container/nulls"
+	"github.com/matrixorigin/matrixone/pkg/container/vector"
+	process "github.com/matrixorigin/matrixone/pkg/vm/process2"
+)
+
+func New() *compare {
+	return &compare{
+		xs: make([][]uint64, 2),
+		ns: make([]*nulls.Nulls, 2),
+		vs: make([]*vector.Vector, 2),
+	}
+}
+
+func (c *compare) Vector() *vector.Vector {
+	return c.vs[0]
+}
+
+func (c *compare) Set(idx int, v *vector.Vector) {
+	c.vs[idx] = v
+	c.ns[idx] = v.Nsp
+	c.xs[idx] = v.Col.([]uint64)
+}
+
+func (c *compare) Compare(veci, vecj int, vi, vj int64) int {
+	if c.xs[veci][vi] == c.xs[vecj][vj] {
+		return 0
+	}
+	if c.xs[veci][vi] < c.xs[vecj][vj] {
+		return -1
+	}
+	return +1
+}
+
+func (c *compare) Copy(vecSrc, vecDst int, src, dst int64, _ *process.Process) error {
+	if nulls.Any(c.ns[vecSrc]) && nulls.Contains(c.ns[vecSrc], (uint64(src))) {
+		nulls.Add(c.ns[vecDst], (uint64(dst)))
+	} else {
+		nulls.Del(c.ns[vecDst], (uint64(dst)))
+		c.xs[vecDst][dst] = c.xs[vecSrc][src]
+	}
+	return nil
+}
diff --git a/pkg/compare2/asc/uint64s/compare_test.go b/pkg/compare2/asc/uint64s/compare_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..ceeaa0d93258f6bce28ce06accf6c5316bdf6a13
--- /dev/null
+++ b/pkg/compare2/asc/uint64s/compare_test.go
@@ -0,0 +1,56 @@
+// Copyright 2021 Matrix Origin
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package uint64s
+
+import (
+	"github.com/matrixorigin/matrixone/pkg/container/nulls"
+	"github.com/matrixorigin/matrixone/pkg/container/types"
+	"github.com/matrixorigin/matrixone/pkg/container/vector"
+	"github.com/stretchr/testify/require"
+	"testing"
+)
+
+func TestNew(t *testing.T) {
+	require.Equal(t, &compare{xs: make([][]uint64, 2),
+		ns: make([]*nulls.Nulls, 2),
+		vs: make([]*vector.Vector, 2)}, New())
+}
+
+func TestCompare_Vector(t *testing.T) {
+	c := New()
+	c.vs[0] = vector.New(types.Type{Oid: types.T(types.T_uint64)})
+	require.Equal(t, vector.New(types.Type{Oid: types.T(types.T_uint64)}), c.Vector())
+}
+
+func TestCompare_Set(t *testing.T) {
+	c := New()
+	vector := vector.New(types.Type{Oid: types.T(types.T_uint64)})
+	c.Set(1, vector)
+	require.Equal(t, vector, c.vs[1])
+}
+
+func TestCompare_Compare(t *testing.T) {
+	c := New()
+	c.xs[0] = []uint64{5, 6}
+	c.xs[1] = []uint64{7, 8}
+	result := c.Compare(0, 1, 0, 0)
+	require.Equal(t, -1, result)
+	c.xs[1] = []uint64{5, 6}
+	result = c.Compare(0, 1, 0, 0)
+	require.Equal(t, 0, result)
+	c.xs[1] = []uint64{3, 4}
+	result = c.Compare(0, 1, 0, 0)
+	require.Equal(t, 1, result)
+}
diff --git a/pkg/compare2/asc/uint64s/types.go b/pkg/compare2/asc/uint64s/types.go
new file mode 100644
index 0000000000000000000000000000000000000000..5d7b7847289e23ca29fd7a0d1e850b08cb08fb86
--- /dev/null
+++ b/pkg/compare2/asc/uint64s/types.go
@@ -0,0 +1,26 @@
+// Copyright 2021 Matrix Origin
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package uint64s
+
+import (
+	"github.com/matrixorigin/matrixone/pkg/container/nulls"
+	"github.com/matrixorigin/matrixone/pkg/container/vector"
+)
+
+type compare struct {
+	xs [][]uint64
+	ns []*nulls.Nulls
+	vs []*vector.Vector
+}
diff --git a/pkg/compare2/asc/uint8s/compare.go b/pkg/compare2/asc/uint8s/compare.go
new file mode 100644
index 0000000000000000000000000000000000000000..4c1f8e914a9efec918f3592a4da14bbe29cb0b59
--- /dev/null
+++ b/pkg/compare2/asc/uint8s/compare.go
@@ -0,0 +1,59 @@
+// Copyright 2021 Matrix Origin
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package uint8s
+
+import (
+	"github.com/matrixorigin/matrixone/pkg/container/nulls"
+	"github.com/matrixorigin/matrixone/pkg/container/vector"
+	process "github.com/matrixorigin/matrixone/pkg/vm/process2"
+)
+
+func New() *compare {
+	return &compare{
+		xs: make([][]uint8, 2),
+		ns: make([]*nulls.Nulls, 2),
+		vs: make([]*vector.Vector, 2),
+	}
+}
+
+func (c *compare) Vector() *vector.Vector {
+	return c.vs[0]
+}
+
+func (c *compare) Set(idx int, v *vector.Vector) {
+	c.vs[idx] = v
+	c.ns[idx] = v.Nsp
+	c.xs[idx] = v.Col.([]uint8)
+}
+
+func (c *compare) Compare(veci, vecj int, vi, vj int64) int {
+	if c.xs[veci][vi] == c.xs[vecj][vj] {
+		return 0
+	}
+	if c.xs[veci][vi] < c.xs[vecj][vj] {
+		return -1
+	}
+	return +1
+}
+
+func (c *compare) Copy(vecSrc, vecDst int, src, dst int64, _ *process.Process) error {
+	if nulls.Any(c.ns[vecSrc]) && nulls.Contains(c.ns[vecSrc], (uint64(src))) {
+		nulls.Add(c.ns[vecDst], (uint64(dst)))
+	} else {
+		nulls.Del(c.ns[vecDst], (uint64(dst)))
+		c.xs[vecDst][dst] = c.xs[vecSrc][src]
+	}
+	return nil
+}
diff --git a/pkg/compare2/asc/uint8s/compare_test.go b/pkg/compare2/asc/uint8s/compare_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..cb802853c2a79fef64a56ec114d2c0fcefae291c
--- /dev/null
+++ b/pkg/compare2/asc/uint8s/compare_test.go
@@ -0,0 +1,56 @@
+// Copyright 2021 Matrix Origin
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package uint8s
+
+import (
+	"github.com/matrixorigin/matrixone/pkg/container/nulls"
+	"github.com/matrixorigin/matrixone/pkg/container/types"
+	"github.com/matrixorigin/matrixone/pkg/container/vector"
+	"github.com/stretchr/testify/require"
+	"testing"
+)
+
+func TestNew(t *testing.T) {
+	require.Equal(t, &compare{xs: make([][]uint8, 2),
+		ns: make([]*nulls.Nulls, 2),
+		vs: make([]*vector.Vector, 2)}, New())
+}
+
+func TestCompare_Vector(t *testing.T) {
+	c := New()
+	c.vs[0] = vector.New(types.Type{Oid: types.T(types.T_uint8)})
+	require.Equal(t, vector.New(types.Type{Oid: types.T(types.T_uint8)}), c.Vector())
+}
+
+func TestCompare_Set(t *testing.T) {
+	c := New()
+	vector := vector.New(types.Type{Oid: types.T(types.T_uint8)})
+	c.Set(1, vector)
+	require.Equal(t, vector, c.vs[1])
+}
+
+func TestCompare_Compare(t *testing.T) {
+	c := New()
+	c.xs[0] = []uint8{5, 6}
+	c.xs[1] = []uint8{7, 8}
+	result := c.Compare(0, 1, 0, 0)
+	require.Equal(t, -1, result)
+	c.xs[1] = []uint8{5, 6}
+	result = c.Compare(0, 1, 0, 0)
+	require.Equal(t, 0, result)
+	c.xs[1] = []uint8{3, 4}
+	result = c.Compare(0, 1, 0, 0)
+	require.Equal(t, 1, result)
+}
diff --git a/pkg/compare2/asc/uint8s/types.go b/pkg/compare2/asc/uint8s/types.go
new file mode 100644
index 0000000000000000000000000000000000000000..77bf258f73b5cbdcc88c8c9d657cd9e1a33db0e0
--- /dev/null
+++ b/pkg/compare2/asc/uint8s/types.go
@@ -0,0 +1,26 @@
+// Copyright 2021 Matrix Origin
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package uint8s
+
+import (
+	"github.com/matrixorigin/matrixone/pkg/container/nulls"
+	"github.com/matrixorigin/matrixone/pkg/container/vector"
+)
+
+type compare struct {
+	xs [][]uint8
+	ns []*nulls.Nulls
+	vs []*vector.Vector
+}
diff --git a/pkg/compare2/asc/varchar/compare.go b/pkg/compare2/asc/varchar/compare.go
new file mode 100644
index 0000000000000000000000000000000000000000..3572ec5ceeaac309ec172525621a30bc9da51f90
--- /dev/null
+++ b/pkg/compare2/asc/varchar/compare.go
@@ -0,0 +1,52 @@
+// Copyright 2021 Matrix Origin
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package varchar
+
+import (
+	"bytes"
+
+	"github.com/matrixorigin/matrixone/pkg/container/nulls"
+	"github.com/matrixorigin/matrixone/pkg/container/types"
+	"github.com/matrixorigin/matrixone/pkg/container/vector"
+	process "github.com/matrixorigin/matrixone/pkg/vm/process2"
+)
+
+func New() *compare {
+	return &compare{
+		vs: make([]*vector.Vector, 2),
+	}
+}
+
+func (c *compare) Vector() *vector.Vector {
+	return c.vs[0]
+}
+
+func (c *compare) Set(idx int, v *vector.Vector) {
+	c.vs[idx] = v
+}
+
+func (c *compare) Copy(vecSrc, vecDst int, src, dst int64, proc *process.Process) error {
+	if nulls.Any(c.vs[vecSrc].Nsp) && nulls.Contains(c.vs[vecSrc].Nsp, uint64(src)) {
+		nulls.Add(c.vs[vecDst].Nsp, uint64(dst))
+		return nil
+	}
+	nulls.Del(c.vs[vecDst].Nsp, uint64(dst))
+	return vector.Copy(c.vs[vecDst], c.vs[vecSrc], dst, src, proc.Mp)
+}
+
+func (c *compare) Compare(veci, vecj int, vi, vj int64) int {
+	x, y := c.vs[veci].Col.(*types.Bytes), c.vs[vecj].Col.(*types.Bytes)
+	return bytes.Compare(x.Get(vi), y.Get(vj))
+}
diff --git a/pkg/compare2/asc/varchar/compare_test.go b/pkg/compare2/asc/varchar/compare_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..8830cc26c33d3fc4128ed5cd686591b72765733c
--- /dev/null
+++ b/pkg/compare2/asc/varchar/compare_test.go
@@ -0,0 +1,76 @@
+// Copyright 2021 Matrix Origin
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package varchar
+
+import (
+	"github.com/matrixorigin/matrixone/pkg/container/types"
+	"github.com/matrixorigin/matrixone/pkg/container/vector"
+	"github.com/stretchr/testify/require"
+	"testing"
+)
+
+func TestNew(t *testing.T) {
+	require.Equal(t, &compare{vs: make([]*vector.Vector, 2)}, New())
+}
+
+func TestCompare_Vector(t *testing.T) {
+	c := New()
+	c.vs[0] = vector.New(types.Type{Oid: types.T(types.T_char)})
+	require.Equal(t, vector.New(types.Type{Oid: types.T(types.T_char)}), c.Vector())
+}
+
+func TestCompare_Set(t *testing.T) {
+	c := New()
+	vector := vector.New(types.Type{Oid: types.T(types.T_char)})
+	c.Set(1, vector)
+	require.Equal(t, vector, c.vs[1])
+}
+
+func TestCompare_Compare(t *testing.T) {
+	c := New()
+	c.vs[0] = vector.New(types.Type{Oid: types.T(types.T_char)})
+	c.vs[1] = vector.New(types.Type{Oid: types.T(types.T_char)})
+	c.vs[0].Col = &types.Bytes{
+		Data:    []byte("helloGutkonichiwanihao"),
+		Offsets: []uint32{0, 5, 8, 17},
+		Lengths: []uint32{5, 3, 9, 5},
+	}
+	c.vs[0].Data = c.vs[0].Col.(*types.Bytes).Data
+	c.vs[1].Col = &types.Bytes{
+		Data:    []byte("helloGutkonichiwanihao"),
+		Offsets: []uint32{0, 5, 8, 17},
+		Lengths: []uint32{5, 3, 9, 5},
+	}
+	c.vs[1].Data = c.vs[1].Col.(*types.Bytes).Data
+	result := c.Compare(0, 1, 0, 0)
+	require.Equal(t, 0, result)
+	c.vs[1].Col = &types.Bytes{
+		Data:    []byte("heyheyheyhey"),
+		Offsets: []uint32{0, 3, 6, 9},
+		Lengths: []uint32{3, 3, 3, 3},
+	}
+	c.vs[1].Data = c.vs[1].Col.(*types.Bytes).Data
+	result = c.Compare(0, 1, 0, 0)
+	require.Equal(t, -1, result)
+	c.vs[1].Col = &types.Bytes{
+		Data:    []byte("aaaa"),
+		Offsets: []uint32{0, 1, 2, 3},
+		Lengths: []uint32{1, 1, 1, 1},
+	}
+	c.vs[1].Data = c.vs[1].Col.(*types.Bytes).Data
+	result = c.Compare(0, 1, 0, 0)
+	require.Equal(t, 1, result)
+
+}
diff --git a/pkg/compare2/asc/varchar/types.go b/pkg/compare2/asc/varchar/types.go
new file mode 100644
index 0000000000000000000000000000000000000000..79202a5606f2da9e6272c5c58238a4fdffcc8cad
--- /dev/null
+++ b/pkg/compare2/asc/varchar/types.go
@@ -0,0 +1,23 @@
+// Copyright 2021 Matrix Origin
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package varchar
+
+import (
+	"github.com/matrixorigin/matrixone/pkg/container/vector"
+)
+
+type compare struct {
+	vs []*vector.Vector
+}
diff --git a/pkg/compare2/compare.go b/pkg/compare2/compare.go
new file mode 100644
index 0000000000000000000000000000000000000000..1ac7dc67c5d5ea6f90c4d03e7a7e6deb98e31e8f
--- /dev/null
+++ b/pkg/compare2/compare.go
@@ -0,0 +1,116 @@
+// Copyright 2021 Matrix Origin
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package compare
+
+import (
+	adates "github.com/matrixorigin/matrixone/pkg/compare2/asc/dates"
+	adatetimes "github.com/matrixorigin/matrixone/pkg/compare2/asc/datetimes"
+	afloat32s "github.com/matrixorigin/matrixone/pkg/compare2/asc/float32s"
+	afloat64s "github.com/matrixorigin/matrixone/pkg/compare2/asc/float64s"
+	aint16s "github.com/matrixorigin/matrixone/pkg/compare2/asc/int16s"
+	aint32s "github.com/matrixorigin/matrixone/pkg/compare2/asc/int32s"
+	aint64s "github.com/matrixorigin/matrixone/pkg/compare2/asc/int64s"
+	aint8s "github.com/matrixorigin/matrixone/pkg/compare2/asc/int8s"
+	auint16s "github.com/matrixorigin/matrixone/pkg/compare2/asc/uint16s"
+	auint32s "github.com/matrixorigin/matrixone/pkg/compare2/asc/uint32s"
+	auint64s "github.com/matrixorigin/matrixone/pkg/compare2/asc/uint64s"
+	auint8s "github.com/matrixorigin/matrixone/pkg/compare2/asc/uint8s"
+	avarchar "github.com/matrixorigin/matrixone/pkg/compare2/asc/varchar"
+	ddates "github.com/matrixorigin/matrixone/pkg/compare2/desc/dates"
+	ddatetimes "github.com/matrixorigin/matrixone/pkg/compare2/desc/datetimes"
+	dfloat32s "github.com/matrixorigin/matrixone/pkg/compare2/desc/float32s"
+	dfloat64s "github.com/matrixorigin/matrixone/pkg/compare2/desc/float64s"
+	dint16s "github.com/matrixorigin/matrixone/pkg/compare2/desc/int16s"
+	dint32s "github.com/matrixorigin/matrixone/pkg/compare2/desc/int32s"
+	dint64s "github.com/matrixorigin/matrixone/pkg/compare2/desc/int64s"
+	dint8s "github.com/matrixorigin/matrixone/pkg/compare2/desc/int8s"
+	duint16s "github.com/matrixorigin/matrixone/pkg/compare2/desc/uint16s"
+	duint32s "github.com/matrixorigin/matrixone/pkg/compare2/desc/uint32s"
+	duint64s "github.com/matrixorigin/matrixone/pkg/compare2/desc/uint64s"
+	duint8s "github.com/matrixorigin/matrixone/pkg/compare2/desc/uint8s"
+	dvarchar "github.com/matrixorigin/matrixone/pkg/compare2/desc/varchar"
+	"github.com/matrixorigin/matrixone/pkg/container/types"
+)
+
+func New(typ types.T, desc bool) Compare {
+	switch typ {
+	case types.T_int8:
+		if desc {
+			return dint8s.New()
+		}
+		return aint8s.New()
+	case types.T_int16:
+		if desc {
+			return dint16s.New()
+		}
+		return aint16s.New()
+	case types.T_int32:
+		if desc {
+			return dint32s.New()
+		}
+		return aint32s.New()
+	case types.T_int64:
+		if desc {
+			return dint64s.New()
+		}
+		return aint64s.New()
+	case types.T_uint8:
+		if desc {
+			return duint8s.New()
+		}
+		return auint8s.New()
+	case types.T_uint16:
+		if desc {
+			return duint16s.New()
+		}
+		return auint16s.New()
+	case types.T_uint32:
+		if desc {
+			return duint32s.New()
+		}
+		return auint32s.New()
+	case types.T_uint64:
+		if desc {
+			return duint64s.New()
+		}
+		return auint64s.New()
+	case types.T_float32:
+		if desc {
+			return dfloat32s.New()
+		}
+		return afloat32s.New()
+	case types.T_float64:
+		if desc {
+			return dfloat64s.New()
+		}
+		return afloat64s.New()
+	case types.T_char, types.T_json, types.T_varchar:
+		if desc {
+			return dvarchar.New()
+		}
+		return avarchar.New()
+	case types.T_date:
+		if desc {
+			return ddates.New()
+		}
+		return adates.New()
+	case types.T_datetime:
+		if desc {
+			return ddatetimes.New()
+		}
+		return adatetimes.New()
+	}
+	return nil
+}
diff --git a/pkg/compare2/desc/dates/compare.go b/pkg/compare2/desc/dates/compare.go
new file mode 100644
index 0000000000000000000000000000000000000000..360e0d542171abc199690139bfc61c36593ec213
--- /dev/null
+++ b/pkg/compare2/desc/dates/compare.go
@@ -0,0 +1,60 @@
+// Copyright 2021 Matrix Origin
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package dates
+
+import (
+	"github.com/matrixorigin/matrixone/pkg/container/nulls"
+	"github.com/matrixorigin/matrixone/pkg/container/types"
+	"github.com/matrixorigin/matrixone/pkg/container/vector"
+	process "github.com/matrixorigin/matrixone/pkg/vm/process2"
+)
+
+func New() *compare {
+	return &compare{
+		xs: make([][]types.Date, 2),
+		ns: make([]*nulls.Nulls, 2),
+		vs: make([]*vector.Vector, 2),
+	}
+}
+
+func (c *compare) Vector() *vector.Vector {
+	return c.vs[0]
+}
+
+func (c *compare) Set(idx int, v *vector.Vector) {
+	c.vs[idx] = v
+	c.ns[idx] = v.Nsp
+	c.xs[idx] = v.Col.([]types.Date)
+}
+
+func (c *compare) Compare(veci, vecj int, vi, vj int64) int {
+	if c.xs[veci][vi] == c.xs[vecj][vj] {
+		return 0
+	}
+	if c.xs[veci][vi] < c.xs[vecj][vj] {
+		return +1
+	}
+	return -1
+}
+
+func (c *compare) Copy(vecSrc, vecDst int, src, dst int64, _ *process.Process) error {
+	if nulls.Any(c.ns[vecSrc]) && nulls.Contains(c.ns[vecSrc], (uint64(src))) {
+		nulls.Add(c.ns[vecDst], (uint64(dst)))
+	} else {
+		nulls.Del(c.ns[vecDst], (uint64(dst)))
+		c.xs[vecDst][dst] = c.xs[vecSrc][src]
+	}
+	return nil
+}
diff --git a/pkg/compare2/desc/dates/compare_test.go b/pkg/compare2/desc/dates/compare_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..8b2b7dae0e6b6b26783b701ce502e8673c513aaf
--- /dev/null
+++ b/pkg/compare2/desc/dates/compare_test.go
@@ -0,0 +1,56 @@
+// Copyright 2021 Matrix Origin
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package dates
+
+import (
+	"github.com/matrixorigin/matrixone/pkg/container/nulls"
+	"github.com/matrixorigin/matrixone/pkg/container/types"
+	"github.com/matrixorigin/matrixone/pkg/container/vector"
+	"github.com/stretchr/testify/require"
+	"testing"
+)
+
+func TestNew(t *testing.T) {
+	require.Equal(t, &compare{xs: make([][]types.Date, 2),
+		ns: make([]*nulls.Nulls, 2),
+		vs: make([]*vector.Vector, 2)}, New())
+}
+
+func TestCompare_Vector(t *testing.T) {
+	c := New()
+	c.vs[0] = vector.New(types.Type{Oid: types.T(types.T_date)})
+	require.Equal(t, vector.New(types.Type{Oid: types.T(types.T_date)}), c.Vector())
+}
+
+func TestCompare_Set(t *testing.T) {
+	c := New()
+	vector := vector.New(types.Type{Oid: types.T(types.T_date)})
+	c.Set(1, vector)
+	require.Equal(t, vector, c.vs[1])
+}
+
+func TestCompare_Compare(t *testing.T) {
+	c := New()
+	c.xs[0] = []types.Date{5, 6}
+	c.xs[1] = []types.Date{7, 8}
+	result := c.Compare(0, 1, 0, 0)
+	require.Equal(t, 1, result)
+	c.xs[1] = []types.Date{5, 6}
+	result = c.Compare(0, 1, 0, 0)
+	require.Equal(t, 0, result)
+	c.xs[1] = []types.Date{3, 4}
+	result = c.Compare(0, 1, 0, 0)
+	require.Equal(t, -1, result)
+}
diff --git a/pkg/compare2/desc/dates/types.go b/pkg/compare2/desc/dates/types.go
new file mode 100644
index 0000000000000000000000000000000000000000..9a330e7b8430769d6fa787e2cdf3066257647360
--- /dev/null
+++ b/pkg/compare2/desc/dates/types.go
@@ -0,0 +1,27 @@
+// Copyright 2021 Matrix Origin
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package dates
+
+import (
+	"github.com/matrixorigin/matrixone/pkg/container/nulls"
+	"github.com/matrixorigin/matrixone/pkg/container/types"
+	"github.com/matrixorigin/matrixone/pkg/container/vector"
+)
+
+type compare struct {
+	xs [][]types.Date
+	ns []*nulls.Nulls
+	vs []*vector.Vector
+}
diff --git a/pkg/compare2/desc/datetimes/compare.go b/pkg/compare2/desc/datetimes/compare.go
new file mode 100644
index 0000000000000000000000000000000000000000..5de3a0bba6dbb48713644ee24fa985e062c99989
--- /dev/null
+++ b/pkg/compare2/desc/datetimes/compare.go
@@ -0,0 +1,60 @@
+// Copyright 2021 Matrix Origin
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package datetimes
+
+import (
+	"github.com/matrixorigin/matrixone/pkg/container/nulls"
+	"github.com/matrixorigin/matrixone/pkg/container/types"
+	"github.com/matrixorigin/matrixone/pkg/container/vector"
+	process "github.com/matrixorigin/matrixone/pkg/vm/process2"
+)
+
+func New() *compare {
+	return &compare{
+		xs: make([][]types.Datetime, 2),
+		ns: make([]*nulls.Nulls, 2),
+		vs: make([]*vector.Vector, 2),
+	}
+}
+
+func (c *compare) Vector() *vector.Vector {
+	return c.vs[0]
+}
+
+func (c *compare) Set(idx int, v *vector.Vector) {
+	c.vs[idx] = v
+	c.ns[idx] = v.Nsp
+	c.xs[idx] = v.Col.([]types.Datetime)
+}
+
+func (c *compare) Compare(veci, vecj int, vi, vj int64) int {
+	if c.xs[veci][vi] == c.xs[vecj][vj] {
+		return 0
+	}
+	if c.xs[veci][vi] < c.xs[vecj][vj] {
+		return +1
+	}
+	return -1
+}
+
+func (c *compare) Copy(vecSrc, vecDst int, src, dst int64, _ *process.Process) error {
+	if nulls.Any(c.ns[vecSrc]) && nulls.Contains(c.ns[vecSrc], (uint64(src))) {
+		nulls.Add(c.ns[vecDst], (uint64(dst)))
+	} else {
+		nulls.Del(c.ns[vecDst], (uint64(dst)))
+		c.xs[vecDst][dst] = c.xs[vecSrc][src]
+	}
+	return nil
+}
diff --git a/pkg/compare2/desc/datetimes/compare_test.go b/pkg/compare2/desc/datetimes/compare_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..2c6cf2c085a8564d996ad9b19c3b1554692a6395
--- /dev/null
+++ b/pkg/compare2/desc/datetimes/compare_test.go
@@ -0,0 +1,56 @@
+// Copyright 2021 Matrix Origin
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package datetimes
+
+import (
+	"github.com/matrixorigin/matrixone/pkg/container/nulls"
+	"github.com/matrixorigin/matrixone/pkg/container/types"
+	"github.com/matrixorigin/matrixone/pkg/container/vector"
+	"github.com/stretchr/testify/require"
+	"testing"
+)
+
+func TestNew(t *testing.T) {
+	require.Equal(t, &compare{xs: make([][]types.Datetime, 2),
+		ns: make([]*nulls.Nulls, 2),
+		vs: make([]*vector.Vector, 2)}, New())
+}
+
+func TestCompare_Vector(t *testing.T) {
+	c := New()
+	c.vs[0] = vector.New(types.Type{Oid: types.T(types.T_datetime)})
+	require.Equal(t, vector.New(types.Type{Oid: types.T(types.T_datetime)}), c.Vector())
+}
+
+func TestCompare_Set(t *testing.T) {
+	c := New()
+	vector := vector.New(types.Type{Oid: types.T(types.T_datetime)})
+	c.Set(1, vector)
+	require.Equal(t, vector, c.vs[1])
+}
+
+func TestCompare_Compare(t *testing.T) {
+	c := New()
+	c.xs[0] = []types.Datetime{5, 6}
+	c.xs[1] = []types.Datetime{7, 8}
+	result := c.Compare(0, 1, 0, 0)
+	require.Equal(t, 1, result)
+	c.xs[1] = []types.Datetime{5, 6}
+	result = c.Compare(0, 1, 0, 0)
+	require.Equal(t, 0, result)
+	c.xs[1] = []types.Datetime{3, 4}
+	result = c.Compare(0, 1, 0, 0)
+	require.Equal(t, -1, result)
+}
diff --git a/pkg/compare2/desc/datetimes/types.go b/pkg/compare2/desc/datetimes/types.go
new file mode 100644
index 0000000000000000000000000000000000000000..1e955f8f2aab72e1dbb30067d3d2a611d46bd6e9
--- /dev/null
+++ b/pkg/compare2/desc/datetimes/types.go
@@ -0,0 +1,27 @@
+// Copyright 2021 Matrix Origin
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package datetimes
+
+import (
+	"github.com/matrixorigin/matrixone/pkg/container/nulls"
+	"github.com/matrixorigin/matrixone/pkg/container/types"
+	"github.com/matrixorigin/matrixone/pkg/container/vector"
+)
+
+type compare struct {
+	xs [][]types.Datetime
+	ns []*nulls.Nulls
+	vs []*vector.Vector
+}
diff --git a/pkg/compare2/desc/float32s/compare.go b/pkg/compare2/desc/float32s/compare.go
new file mode 100644
index 0000000000000000000000000000000000000000..61e7931e1ae8db186aad296d263159359a8511c2
--- /dev/null
+++ b/pkg/compare2/desc/float32s/compare.go
@@ -0,0 +1,59 @@
+// Copyright 2021 Matrix Origin
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package float32s
+
+import (
+	"github.com/matrixorigin/matrixone/pkg/container/nulls"
+	"github.com/matrixorigin/matrixone/pkg/container/vector"
+	process "github.com/matrixorigin/matrixone/pkg/vm/process2"
+)
+
+func New() *compare {
+	return &compare{
+		xs: make([][]float32, 2),
+		ns: make([]*nulls.Nulls, 2),
+		vs: make([]*vector.Vector, 2),
+	}
+}
+
+func (c *compare) Vector() *vector.Vector {
+	return c.vs[0]
+}
+
+func (c *compare) Set(idx int, v *vector.Vector) {
+	c.vs[idx] = v
+	c.ns[idx] = v.Nsp
+	c.xs[idx] = v.Col.([]float32)
+}
+
+func (c *compare) Compare(veci, vecj int, vi, vj int64) int {
+	if c.xs[veci][vi] == c.xs[vecj][vj] {
+		return 0
+	}
+	if c.xs[veci][vi] < c.xs[vecj][vj] {
+		return +1
+	}
+	return -1
+}
+
+func (c *compare) Copy(vecSrc, vecDst int, src, dst int64, _ *process.Process) error {
+	if nulls.Any(c.ns[vecSrc]) && nulls.Contains(c.ns[vecSrc], (uint64(src))) {
+		nulls.Add(c.ns[vecDst], (uint64(dst)))
+	} else {
+		nulls.Del(c.ns[vecDst], (uint64(dst)))
+		c.xs[vecDst][dst] = c.xs[vecSrc][src]
+	}
+	return nil
+}
diff --git a/pkg/compare2/desc/float32s/compare_test.go b/pkg/compare2/desc/float32s/compare_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..68364f0e4cac4b8ec143ed2371d73559b046003a
--- /dev/null
+++ b/pkg/compare2/desc/float32s/compare_test.go
@@ -0,0 +1,56 @@
+// Copyright 2021 Matrix Origin
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package float32s
+
+import (
+	"github.com/matrixorigin/matrixone/pkg/container/nulls"
+	"github.com/matrixorigin/matrixone/pkg/container/types"
+	"github.com/matrixorigin/matrixone/pkg/container/vector"
+	"github.com/stretchr/testify/require"
+	"testing"
+)
+
+func TestNew(t *testing.T) {
+	require.Equal(t, &compare{xs: make([][]float32, 2),
+		ns: make([]*nulls.Nulls, 2),
+		vs: make([]*vector.Vector, 2)}, New())
+}
+
+func TestCompare_Vector(t *testing.T) {
+	c := New()
+	c.vs[0] = vector.New(types.Type{Oid: types.T(types.T_float32)})
+	require.Equal(t, vector.New(types.Type{Oid: types.T(types.T_float32)}), c.Vector())
+}
+
+func TestCompare_Set(t *testing.T) {
+	c := New()
+	vector := vector.New(types.Type{Oid: types.T(types.T_float32)})
+	c.Set(1, vector)
+	require.Equal(t, vector, c.vs[1])
+}
+
+func TestCompare_Compare(t *testing.T) {
+	c := New()
+	c.xs[0] = []float32{5, 6}
+	c.xs[1] = []float32{7, 8}
+	result := c.Compare(0, 1, 0, 0)
+	require.Equal(t, 1, result)
+	c.xs[1] = []float32{5, 6}
+	result = c.Compare(0, 1, 0, 0)
+	require.Equal(t, 0, result)
+	c.xs[1] = []float32{3, 4}
+	result = c.Compare(0, 1, 0, 0)
+	require.Equal(t, -1, result)
+}
diff --git a/pkg/compare2/desc/float32s/types.go b/pkg/compare2/desc/float32s/types.go
new file mode 100644
index 0000000000000000000000000000000000000000..3cea8979d77cb7439ca10bd9b7cfd186bbf8243a
--- /dev/null
+++ b/pkg/compare2/desc/float32s/types.go
@@ -0,0 +1,26 @@
+// Copyright 2021 Matrix Origin
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package float32s
+
+import (
+	"github.com/matrixorigin/matrixone/pkg/container/nulls"
+	"github.com/matrixorigin/matrixone/pkg/container/vector"
+)
+
+type compare struct {
+	xs [][]float32
+	ns []*nulls.Nulls
+	vs []*vector.Vector
+}
diff --git a/pkg/compare2/desc/float64s/compare.go b/pkg/compare2/desc/float64s/compare.go
new file mode 100644
index 0000000000000000000000000000000000000000..e9b38bb4fddae2abede5162f8a9bc81422e7da84
--- /dev/null
+++ b/pkg/compare2/desc/float64s/compare.go
@@ -0,0 +1,59 @@
+// Copyright 2021 Matrix Origin
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package float64s
+
+import (
+	"github.com/matrixorigin/matrixone/pkg/container/nulls"
+	"github.com/matrixorigin/matrixone/pkg/container/vector"
+	process "github.com/matrixorigin/matrixone/pkg/vm/process2"
+)
+
+func New() *compare {
+	return &compare{
+		xs: make([][]float64, 2),
+		ns: make([]*nulls.Nulls, 2),
+		vs: make([]*vector.Vector, 2),
+	}
+}
+
+func (c *compare) Vector() *vector.Vector {
+	return c.vs[0]
+}
+
+func (c *compare) Set(idx int, v *vector.Vector) {
+	c.vs[idx] = v
+	c.ns[idx] = v.Nsp
+	c.xs[idx] = v.Col.([]float64)
+}
+
+func (c *compare) Compare(veci, vecj int, vi, vj int64) int {
+	if c.xs[veci][vi] == c.xs[vecj][vj] {
+		return 0
+	}
+	if c.xs[veci][vi] < c.xs[vecj][vj] {
+		return +1
+	}
+	return -1
+}
+
+func (c *compare) Copy(vecSrc, vecDst int, src, dst int64, _ *process.Process) error {
+	if nulls.Any(c.ns[vecSrc]) && nulls.Contains(c.ns[vecSrc], (uint64(src))) {
+		nulls.Add(c.ns[vecDst], (uint64(dst)))
+	} else {
+		nulls.Del(c.ns[vecDst], (uint64(dst)))
+		c.xs[vecDst][dst] = c.xs[vecSrc][src]
+	}
+	return nil
+}
diff --git a/pkg/compare2/desc/float64s/compare_test.go b/pkg/compare2/desc/float64s/compare_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..8c856c738cb17c4c9f4bc1b8e0d880a87b72b8ca
--- /dev/null
+++ b/pkg/compare2/desc/float64s/compare_test.go
@@ -0,0 +1,56 @@
+// Copyright 2021 Matrix Origin
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package float64s
+
+import (
+	"github.com/matrixorigin/matrixone/pkg/container/nulls"
+	"github.com/matrixorigin/matrixone/pkg/container/types"
+	"github.com/matrixorigin/matrixone/pkg/container/vector"
+	"github.com/stretchr/testify/require"
+	"testing"
+)
+
+func TestNew(t *testing.T) {
+	require.Equal(t, &compare{xs: make([][]float64, 2),
+		ns: make([]*nulls.Nulls, 2),
+		vs: make([]*vector.Vector, 2)}, New())
+}
+
+func TestCompare_Vector(t *testing.T) {
+	c := New()
+	c.vs[0] = vector.New(types.Type{Oid: types.T(types.T_float64)})
+	require.Equal(t, vector.New(types.Type{Oid: types.T(types.T_float64)}), c.Vector())
+}
+
+func TestCompare_Set(t *testing.T) {
+	c := New()
+	vector := vector.New(types.Type{Oid: types.T(types.T_float64)})
+	c.Set(1, vector)
+	require.Equal(t, vector, c.vs[1])
+}
+
+func TestCompare_Compare(t *testing.T) {
+	c := New()
+	c.xs[0] = []float64{5, 6}
+	c.xs[1] = []float64{7, 8}
+	result := c.Compare(0, 1, 0, 0)
+	require.Equal(t, 1, result)
+	c.xs[1] = []float64{5, 6}
+	result = c.Compare(0, 1, 0, 0)
+	require.Equal(t, 0, result)
+	c.xs[1] = []float64{3, 4}
+	result = c.Compare(0, 1, 0, 0)
+	require.Equal(t, -1, result)
+}
diff --git a/pkg/compare2/desc/float64s/types.go b/pkg/compare2/desc/float64s/types.go
new file mode 100644
index 0000000000000000000000000000000000000000..c0169c928662dfe6158052be38f114688098c25e
--- /dev/null
+++ b/pkg/compare2/desc/float64s/types.go
@@ -0,0 +1,26 @@
+// Copyright 2021 Matrix Origin
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package float64s
+
+import (
+	"github.com/matrixorigin/matrixone/pkg/container/nulls"
+	"github.com/matrixorigin/matrixone/pkg/container/vector"
+)
+
+type compare struct {
+	xs [][]float64
+	ns []*nulls.Nulls
+	vs []*vector.Vector
+}
diff --git a/pkg/compare2/desc/int16s/compare.go b/pkg/compare2/desc/int16s/compare.go
new file mode 100644
index 0000000000000000000000000000000000000000..c2eedf5d1a7ebc2978109250f8d7c042ba77dbc2
--- /dev/null
+++ b/pkg/compare2/desc/int16s/compare.go
@@ -0,0 +1,59 @@
+// Copyright 2021 Matrix Origin
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package int16s
+
+import (
+	"github.com/matrixorigin/matrixone/pkg/container/nulls"
+	"github.com/matrixorigin/matrixone/pkg/container/vector"
+	process "github.com/matrixorigin/matrixone/pkg/vm/process2"
+)
+
+func New() *compare {
+	return &compare{
+		xs: make([][]int16, 2),
+		ns: make([]*nulls.Nulls, 2),
+		vs: make([]*vector.Vector, 2),
+	}
+}
+
+func (c *compare) Vector() *vector.Vector {
+	return c.vs[0]
+}
+
+func (c *compare) Set(idx int, v *vector.Vector) {
+	c.vs[idx] = v
+	c.ns[idx] = v.Nsp
+	c.xs[idx] = v.Col.([]int16)
+}
+
+func (c *compare) Compare(veci, vecj int, vi, vj int64) int {
+	if c.xs[veci][vi] == c.xs[vecj][vj] {
+		return 0
+	}
+	if c.xs[veci][vi] < c.xs[vecj][vj] {
+		return +1
+	}
+	return -1
+}
+
+func (c *compare) Copy(vecSrc, vecDst int, src, dst int64, _ *process.Process) error {
+	if nulls.Any(c.ns[vecSrc]) && nulls.Contains(c.ns[vecSrc], (uint64(src))) {
+		nulls.Add(c.ns[vecDst], (uint64(dst)))
+	} else {
+		nulls.Del(c.ns[vecDst], (uint64(dst)))
+		c.xs[vecDst][dst] = c.xs[vecSrc][src]
+	}
+	return nil
+}
diff --git a/pkg/compare2/desc/int16s/compare_test.go b/pkg/compare2/desc/int16s/compare_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..4aa79843ffdb98e69ad060f754ab779154cc0bbb
--- /dev/null
+++ b/pkg/compare2/desc/int16s/compare_test.go
@@ -0,0 +1,56 @@
+// Copyright 2021 Matrix Origin
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package int16s
+
+import (
+	"github.com/matrixorigin/matrixone/pkg/container/nulls"
+	"github.com/matrixorigin/matrixone/pkg/container/types"
+	"github.com/matrixorigin/matrixone/pkg/container/vector"
+	"github.com/stretchr/testify/require"
+	"testing"
+)
+
+func TestNew(t *testing.T) {
+	require.Equal(t, &compare{xs: make([][]int16, 2),
+		ns: make([]*nulls.Nulls, 2),
+		vs: make([]*vector.Vector, 2)}, New())
+}
+
+func TestCompare_Vector(t *testing.T) {
+	c := New()
+	c.vs[0] = vector.New(types.Type{Oid: types.T(types.T_int16)})
+	require.Equal(t, vector.New(types.Type{Oid: types.T(types.T_int16)}), c.Vector())
+}
+
+func TestCompare_Set(t *testing.T) {
+	c := New()
+	vector := vector.New(types.Type{Oid: types.T(types.T_int16)})
+	c.Set(1, vector)
+	require.Equal(t, vector, c.vs[1])
+}
+
+func TestCompare_Compare(t *testing.T) {
+	c := New()
+	c.xs[0] = []int16{5, 6}
+	c.xs[1] = []int16{7, 8}
+	result := c.Compare(0, 1, 0, 0)
+	require.Equal(t, 1, result)
+	c.xs[1] = []int16{5, 6}
+	result = c.Compare(0, 1, 0, 0)
+	require.Equal(t, 0, result)
+	c.xs[1] = []int16{3, 4}
+	result = c.Compare(0, 1, 0, 0)
+	require.Equal(t, -1, result)
+}
diff --git a/pkg/compare2/desc/int16s/types.go b/pkg/compare2/desc/int16s/types.go
new file mode 100644
index 0000000000000000000000000000000000000000..e176b67fc8ad7c8f0096d676011f43bacc9290f7
--- /dev/null
+++ b/pkg/compare2/desc/int16s/types.go
@@ -0,0 +1,26 @@
+// Copyright 2021 Matrix Origin
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package int16s
+
+import (
+	"github.com/matrixorigin/matrixone/pkg/container/nulls"
+	"github.com/matrixorigin/matrixone/pkg/container/vector"
+)
+
+type compare struct {
+	xs [][]int16
+	ns []*nulls.Nulls
+	vs []*vector.Vector
+}
diff --git a/pkg/compare2/desc/int32s/compare.go b/pkg/compare2/desc/int32s/compare.go
new file mode 100644
index 0000000000000000000000000000000000000000..4abc5ae4c3a755c87cf1841aab45d8c4af5ac331
--- /dev/null
+++ b/pkg/compare2/desc/int32s/compare.go
@@ -0,0 +1,59 @@
+// Copyright 2021 Matrix Origin
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package int32s
+
+import (
+	"github.com/matrixorigin/matrixone/pkg/container/nulls"
+	"github.com/matrixorigin/matrixone/pkg/container/vector"
+	process "github.com/matrixorigin/matrixone/pkg/vm/process2"
+)
+
+func New() *compare {
+	return &compare{
+		xs: make([][]int32, 2),
+		ns: make([]*nulls.Nulls, 2),
+		vs: make([]*vector.Vector, 2),
+	}
+}
+
+func (c *compare) Vector() *vector.Vector {
+	return c.vs[0]
+}
+
+func (c *compare) Set(idx int, v *vector.Vector) {
+	c.vs[idx] = v
+	c.ns[idx] = v.Nsp
+	c.xs[idx] = v.Col.([]int32)
+}
+
+func (c *compare) Compare(veci, vecj int, vi, vj int64) int {
+	if c.xs[veci][vi] == c.xs[vecj][vj] {
+		return 0
+	}
+	if c.xs[veci][vi] < c.xs[vecj][vj] {
+		return +1
+	}
+	return -1
+}
+
+func (c *compare) Copy(vecSrc, vecDst int, src, dst int64, _ *process.Process) error {
+	if nulls.Any(c.ns[vecSrc]) && nulls.Contains(c.ns[vecSrc], (uint64(src))) {
+		nulls.Add(c.ns[vecDst], (uint64(dst)))
+	} else {
+		nulls.Del(c.ns[vecDst], (uint64(dst)))
+		c.xs[vecDst][dst] = c.xs[vecSrc][src]
+	}
+	return nil
+}
diff --git a/pkg/compare2/desc/int32s/compare_test.go b/pkg/compare2/desc/int32s/compare_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..4b4f497f90c8301cac14e07f49d72211ef5e6e38
--- /dev/null
+++ b/pkg/compare2/desc/int32s/compare_test.go
@@ -0,0 +1,56 @@
+// Copyright 2021 Matrix Origin
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package int32s
+
+import (
+	"github.com/matrixorigin/matrixone/pkg/container/nulls"
+	"github.com/matrixorigin/matrixone/pkg/container/types"
+	"github.com/matrixorigin/matrixone/pkg/container/vector"
+	"github.com/stretchr/testify/require"
+	"testing"
+)
+
+func TestNew(t *testing.T) {
+	require.Equal(t, &compare{xs: make([][]int32, 2),
+		ns: make([]*nulls.Nulls, 2),
+		vs: make([]*vector.Vector, 2)}, New())
+}
+
+func TestCompare_Vector(t *testing.T) {
+	c := New()
+	c.vs[0] = vector.New(types.Type{Oid: types.T(types.T_int32)})
+	require.Equal(t, vector.New(types.Type{Oid: types.T(types.T_int32)}), c.Vector())
+}
+
+func TestCompare_Set(t *testing.T) {
+	c := New()
+	vector := vector.New(types.Type{Oid: types.T(types.T_int32)})
+	c.Set(1, vector)
+	require.Equal(t, vector, c.vs[1])
+}
+
+func TestCompare_Compare(t *testing.T) {
+	c := New()
+	c.xs[0] = []int32{5, 6}
+	c.xs[1] = []int32{7, 8}
+	result := c.Compare(0, 1, 0, 0)
+	require.Equal(t, 1, result)
+	c.xs[1] = []int32{5, 6}
+	result = c.Compare(0, 1, 0, 0)
+	require.Equal(t, 0, result)
+	c.xs[1] = []int32{3, 4}
+	result = c.Compare(0, 1, 0, 0)
+	require.Equal(t, -1, result)
+}
diff --git a/pkg/compare2/desc/int32s/types.go b/pkg/compare2/desc/int32s/types.go
new file mode 100644
index 0000000000000000000000000000000000000000..490907c608677d7867d149cdd4ed944be70508b8
--- /dev/null
+++ b/pkg/compare2/desc/int32s/types.go
@@ -0,0 +1,26 @@
+// Copyright 2021 Matrix Origin
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package int32s
+
+import (
+	"github.com/matrixorigin/matrixone/pkg/container/nulls"
+	"github.com/matrixorigin/matrixone/pkg/container/vector"
+)
+
+type compare struct {
+	xs [][]int32
+	ns []*nulls.Nulls
+	vs []*vector.Vector
+}
diff --git a/pkg/compare2/desc/int64s/compare.go b/pkg/compare2/desc/int64s/compare.go
new file mode 100644
index 0000000000000000000000000000000000000000..1ba6070a1c7cc5b4a4ff42151dd12b3c52fe282e
--- /dev/null
+++ b/pkg/compare2/desc/int64s/compare.go
@@ -0,0 +1,59 @@
+// Copyright 2021 Matrix Origin
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package int64s
+
+import (
+	"github.com/matrixorigin/matrixone/pkg/container/nulls"
+	"github.com/matrixorigin/matrixone/pkg/container/vector"
+	process "github.com/matrixorigin/matrixone/pkg/vm/process2"
+)
+
+func New() *compare {
+	return &compare{
+		xs: make([][]int64, 2),
+		ns: make([]*nulls.Nulls, 2),
+		vs: make([]*vector.Vector, 2),
+	}
+}
+
+func (c *compare) Vector() *vector.Vector {
+	return c.vs[0]
+}
+
+func (c *compare) Set(idx int, v *vector.Vector) {
+	c.vs[idx] = v
+	c.ns[idx] = v.Nsp
+	c.xs[idx] = v.Col.([]int64)
+}
+
+func (c *compare) Compare(veci, vecj int, vi, vj int64) int {
+	if c.xs[veci][vi] == c.xs[vecj][vj] {
+		return 0
+	}
+	if c.xs[veci][vi] < c.xs[vecj][vj] {
+		return +1
+	}
+	return -1
+}
+
+func (c *compare) Copy(vecSrc, vecDst int, src, dst int64, _ *process.Process) error {
+	if nulls.Any(c.ns[vecSrc]) && nulls.Contains(c.ns[vecSrc], (uint64(src))) {
+		nulls.Add(c.ns[vecDst], (uint64(dst)))
+	} else {
+		nulls.Del(c.ns[vecDst], (uint64(dst)))
+		c.xs[vecDst][dst] = c.xs[vecSrc][src]
+	}
+	return nil
+}
diff --git a/pkg/compare2/desc/int64s/compare_test.go b/pkg/compare2/desc/int64s/compare_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..a1029ebf19e4640ae2a25999ab153b8cda483227
--- /dev/null
+++ b/pkg/compare2/desc/int64s/compare_test.go
@@ -0,0 +1,56 @@
+// Copyright 2021 Matrix Origin
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package int64s
+
+import (
+	"github.com/matrixorigin/matrixone/pkg/container/nulls"
+	"github.com/matrixorigin/matrixone/pkg/container/types"
+	"github.com/matrixorigin/matrixone/pkg/container/vector"
+	"github.com/stretchr/testify/require"
+	"testing"
+)
+
+func TestNew(t *testing.T) {
+	require.Equal(t, &compare{xs: make([][]int64, 2),
+		ns: make([]*nulls.Nulls, 2),
+		vs: make([]*vector.Vector, 2)}, New())
+}
+
+func TestCompare_Vector(t *testing.T) {
+	c := New()
+	c.vs[0] = vector.New(types.Type{Oid: types.T(types.T_int64)})
+	require.Equal(t, vector.New(types.Type{Oid: types.T(types.T_int64)}), c.Vector())
+}
+
+func TestCompare_Set(t *testing.T) {
+	c := New()
+	vector := vector.New(types.Type{Oid: types.T(types.T_int64)})
+	c.Set(1, vector)
+	require.Equal(t, vector, c.vs[1])
+}
+
+func TestCompare_Compare(t *testing.T) {
+	c := New()
+	c.xs[0] = []int64{5, 6}
+	c.xs[1] = []int64{7, 8}
+	result := c.Compare(0, 1, 0, 0)
+	require.Equal(t, 1, result)
+	c.xs[1] = []int64{5, 6}
+	result = c.Compare(0, 1, 0, 0)
+	require.Equal(t, 0, result)
+	c.xs[1] = []int64{3, 4}
+	result = c.Compare(0, 1, 0, 0)
+	require.Equal(t, -1, result)
+}
diff --git a/pkg/compare2/desc/int64s/types.go b/pkg/compare2/desc/int64s/types.go
new file mode 100644
index 0000000000000000000000000000000000000000..1ced17e8fb4363eb638b04001e9e5b25abcd80cf
--- /dev/null
+++ b/pkg/compare2/desc/int64s/types.go
@@ -0,0 +1,26 @@
+// Copyright 2021 Matrix Origin
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package int64s
+
+import (
+	"github.com/matrixorigin/matrixone/pkg/container/nulls"
+	"github.com/matrixorigin/matrixone/pkg/container/vector"
+)
+
+type compare struct {
+	xs [][]int64
+	ns []*nulls.Nulls
+	vs []*vector.Vector
+}
diff --git a/pkg/compare2/desc/int8s/compare.go b/pkg/compare2/desc/int8s/compare.go
new file mode 100644
index 0000000000000000000000000000000000000000..b9bfe6e31d701a77fd4d2bac82fd5c5ad81b912e
--- /dev/null
+++ b/pkg/compare2/desc/int8s/compare.go
@@ -0,0 +1,59 @@
+// Copyright 2021 Matrix Origin
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package int8s
+
+import (
+	"github.com/matrixorigin/matrixone/pkg/container/nulls"
+	"github.com/matrixorigin/matrixone/pkg/container/vector"
+	process "github.com/matrixorigin/matrixone/pkg/vm/process2"
+)
+
+func New() *compare {
+	return &compare{
+		xs: make([][]int8, 2),
+		ns: make([]*nulls.Nulls, 2),
+		vs: make([]*vector.Vector, 2),
+	}
+}
+
+func (c *compare) Vector() *vector.Vector {
+	return c.vs[0]
+}
+
+func (c *compare) Set(idx int, v *vector.Vector) {
+	c.vs[idx] = v
+	c.ns[idx] = v.Nsp
+	c.xs[idx] = v.Col.([]int8)
+}
+
+func (c *compare) Compare(veci, vecj int, vi, vj int64) int {
+	if c.xs[veci][vi] == c.xs[vecj][vj] {
+		return 0
+	}
+	if c.xs[veci][vi] < c.xs[vecj][vj] {
+		return +1
+	}
+	return -1
+}
+
+func (c *compare) Copy(vecSrc, vecDst int, src, dst int64, _ *process.Process) error {
+	if nulls.Any(c.ns[vecSrc]) && nulls.Contains(c.ns[vecSrc], (uint64(src))) {
+		nulls.Add(c.ns[vecDst], (uint64(dst)))
+	} else {
+		nulls.Del(c.ns[vecDst], (uint64(dst)))
+		c.xs[vecDst][dst] = c.xs[vecSrc][src]
+	}
+	return nil
+}
diff --git a/pkg/compare2/desc/int8s/compare_test.go b/pkg/compare2/desc/int8s/compare_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..2f534f5b1792aa259c4b5b828c25829fe9e46461
--- /dev/null
+++ b/pkg/compare2/desc/int8s/compare_test.go
@@ -0,0 +1,56 @@
+// Copyright 2021 Matrix Origin
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package int8s
+
+import (
+	"github.com/matrixorigin/matrixone/pkg/container/nulls"
+	"github.com/matrixorigin/matrixone/pkg/container/types"
+	"github.com/matrixorigin/matrixone/pkg/container/vector"
+	"github.com/stretchr/testify/require"
+	"testing"
+)
+
+func TestNew(t *testing.T) {
+	require.Equal(t, &compare{xs: make([][]int8, 2),
+		ns: make([]*nulls.Nulls, 2),
+		vs: make([]*vector.Vector, 2)}, New())
+}
+
+func TestCompare_Vector(t *testing.T) {
+	c := New()
+	c.vs[0] = vector.New(types.Type{Oid: types.T(types.T_int8)})
+	require.Equal(t, vector.New(types.Type{Oid: types.T(types.T_int8)}), c.Vector())
+}
+
+func TestCompare_Set(t *testing.T) {
+	c := New()
+	vector := vector.New(types.Type{Oid: types.T(types.T_int8)})
+	c.Set(1, vector)
+	require.Equal(t, vector, c.vs[1])
+}
+
+func TestCompare_Compare(t *testing.T) {
+	c := New()
+	c.xs[0] = []int8{5, 6}
+	c.xs[1] = []int8{7, 8}
+	result := c.Compare(0, 1, 0, 0)
+	require.Equal(t, 1, result)
+	c.xs[1] = []int8{5, 6}
+	result = c.Compare(0, 1, 0, 0)
+	require.Equal(t, 0, result)
+	c.xs[1] = []int8{3, 4}
+	result = c.Compare(0, 1, 0, 0)
+	require.Equal(t, -1, result)
+}
diff --git a/pkg/compare2/desc/int8s/types.go b/pkg/compare2/desc/int8s/types.go
new file mode 100644
index 0000000000000000000000000000000000000000..88fb01230556558875c76f8024226aaeb54a5244
--- /dev/null
+++ b/pkg/compare2/desc/int8s/types.go
@@ -0,0 +1,26 @@
+// Copyright 2021 Matrix Origin
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package int8s
+
+import (
+	"github.com/matrixorigin/matrixone/pkg/container/nulls"
+	"github.com/matrixorigin/matrixone/pkg/container/vector"
+)
+
+type compare struct {
+	xs [][]int8
+	ns []*nulls.Nulls
+	vs []*vector.Vector
+}
diff --git a/pkg/compare2/desc/uint16s/compare.go b/pkg/compare2/desc/uint16s/compare.go
new file mode 100644
index 0000000000000000000000000000000000000000..a211acf8d677dcebea6faa1b47a29688c3fa7fc2
--- /dev/null
+++ b/pkg/compare2/desc/uint16s/compare.go
@@ -0,0 +1,59 @@
+// Copyright 2021 Matrix Origin
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package uint16s
+
+import (
+	"github.com/matrixorigin/matrixone/pkg/container/nulls"
+	"github.com/matrixorigin/matrixone/pkg/container/vector"
+	process "github.com/matrixorigin/matrixone/pkg/vm/process2"
+)
+
+func New() *compare {
+	return &compare{
+		xs: make([][]uint16, 2),
+		ns: make([]*nulls.Nulls, 2),
+		vs: make([]*vector.Vector, 2),
+	}
+}
+
+func (c *compare) Vector() *vector.Vector {
+	return c.vs[0]
+}
+
+func (c *compare) Set(idx int, v *vector.Vector) {
+	c.vs[idx] = v
+	c.ns[idx] = v.Nsp
+	c.xs[idx] = v.Col.([]uint16)
+}
+
+func (c *compare) Compare(veci, vecj int, vi, vj int64) int {
+	if c.xs[veci][vi] == c.xs[vecj][vj] {
+		return 0
+	}
+	if c.xs[veci][vi] < c.xs[vecj][vj] {
+		return +1
+	}
+	return -1
+}
+
+func (c *compare) Copy(vecSrc, vecDst int, src, dst int64, _ *process.Process) error {
+	if nulls.Any(c.ns[vecSrc]) && nulls.Contains(c.ns[vecSrc], (uint64(src))) {
+		nulls.Add(c.ns[vecDst], (uint64(dst)))
+	} else {
+		nulls.Del(c.ns[vecDst], (uint64(dst)))
+		c.xs[vecDst][dst] = c.xs[vecSrc][src]
+	}
+	return nil
+}
diff --git a/pkg/compare2/desc/uint16s/compare_test.go b/pkg/compare2/desc/uint16s/compare_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..93b9e58c830d677196e22d59e16e77efffafcba9
--- /dev/null
+++ b/pkg/compare2/desc/uint16s/compare_test.go
@@ -0,0 +1,56 @@
+// Copyright 2021 Matrix Origin
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package uint16s
+
+import (
+	"github.com/matrixorigin/matrixone/pkg/container/nulls"
+	"github.com/matrixorigin/matrixone/pkg/container/types"
+	"github.com/matrixorigin/matrixone/pkg/container/vector"
+	"github.com/stretchr/testify/require"
+	"testing"
+)
+
+func TestNew(t *testing.T) {
+	require.Equal(t, &compare{xs: make([][]uint16, 2),
+		ns: make([]*nulls.Nulls, 2),
+		vs: make([]*vector.Vector, 2)}, New())
+}
+
+func TestCompare_Vector(t *testing.T) {
+	c := New()
+	c.vs[0] = vector.New(types.Type{Oid: types.T(types.T_uint16)})
+	require.Equal(t, vector.New(types.Type{Oid: types.T(types.T_uint16)}), c.Vector())
+}
+
+func TestCompare_Set(t *testing.T) {
+	c := New()
+	vector := vector.New(types.Type{Oid: types.T(types.T_uint16)})
+	c.Set(1, vector)
+	require.Equal(t, vector, c.vs[1])
+}
+
+func TestCompare_Compare(t *testing.T) {
+	c := New()
+	c.xs[0] = []uint16{5, 6}
+	c.xs[1] = []uint16{7, 8}
+	result := c.Compare(0, 1, 0, 0)
+	require.Equal(t, 1, result)
+	c.xs[1] = []uint16{5, 6}
+	result = c.Compare(0, 1, 0, 0)
+	require.Equal(t, 0, result)
+	c.xs[1] = []uint16{3, 4}
+	result = c.Compare(0, 1, 0, 0)
+	require.Equal(t, -1, result)
+}
diff --git a/pkg/compare2/desc/uint16s/types.go b/pkg/compare2/desc/uint16s/types.go
new file mode 100644
index 0000000000000000000000000000000000000000..86a81895d6ece757947eae89c464c0ed570905fc
--- /dev/null
+++ b/pkg/compare2/desc/uint16s/types.go
@@ -0,0 +1,26 @@
+// Copyright 2021 Matrix Origin
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package uint16s
+
+import (
+	"github.com/matrixorigin/matrixone/pkg/container/nulls"
+	"github.com/matrixorigin/matrixone/pkg/container/vector"
+)
+
+type compare struct {
+	xs [][]uint16
+	ns []*nulls.Nulls
+	vs []*vector.Vector
+}
diff --git a/pkg/compare2/desc/uint32s/compare.go b/pkg/compare2/desc/uint32s/compare.go
new file mode 100644
index 0000000000000000000000000000000000000000..1b24c5c3381a196dc227f9e9c2fd58e26968ba4f
--- /dev/null
+++ b/pkg/compare2/desc/uint32s/compare.go
@@ -0,0 +1,59 @@
+// Copyright 2021 Matrix Origin
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package uint32s
+
+import (
+	"github.com/matrixorigin/matrixone/pkg/container/nulls"
+	"github.com/matrixorigin/matrixone/pkg/container/vector"
+	process "github.com/matrixorigin/matrixone/pkg/vm/process2"
+)
+
+func New() *compare {
+	return &compare{
+		xs: make([][]uint32, 2),
+		ns: make([]*nulls.Nulls, 2),
+		vs: make([]*vector.Vector, 2),
+	}
+}
+
+func (c *compare) Vector() *vector.Vector {
+	return c.vs[0]
+}
+
+func (c *compare) Set(idx int, v *vector.Vector) {
+	c.vs[idx] = v
+	c.ns[idx] = v.Nsp
+	c.xs[idx] = v.Col.([]uint32)
+}
+
+func (c *compare) Compare(veci, vecj int, vi, vj int64) int {
+	if c.xs[veci][vi] == c.xs[vecj][vj] {
+		return 0
+	}
+	if c.xs[veci][vi] < c.xs[vecj][vj] {
+		return +1
+	}
+	return -1
+}
+
+func (c *compare) Copy(vecSrc, vecDst int, src, dst int64, _ *process.Process) error {
+	if nulls.Any(c.ns[vecSrc]) && nulls.Contains(c.ns[vecSrc], (uint64(src))) {
+		nulls.Add(c.ns[vecDst], (uint64(dst)))
+	} else {
+		nulls.Del(c.ns[vecDst], (uint64(dst)))
+		c.xs[vecDst][dst] = c.xs[vecSrc][src]
+	}
+	return nil
+}
diff --git a/pkg/compare2/desc/uint32s/compare_test.go b/pkg/compare2/desc/uint32s/compare_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..aa484abf9b4ebc3b2db99f74188a14dbea3943cf
--- /dev/null
+++ b/pkg/compare2/desc/uint32s/compare_test.go
@@ -0,0 +1,56 @@
+// Copyright 2021 Matrix Origin
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package uint32s
+
+import (
+	"github.com/matrixorigin/matrixone/pkg/container/nulls"
+	"github.com/matrixorigin/matrixone/pkg/container/types"
+	"github.com/matrixorigin/matrixone/pkg/container/vector"
+	"github.com/stretchr/testify/require"
+	"testing"
+)
+
+func TestNew(t *testing.T) {
+	require.Equal(t, &compare{xs: make([][]uint32, 2),
+		ns: make([]*nulls.Nulls, 2),
+		vs: make([]*vector.Vector, 2)}, New())
+}
+
+func TestCompare_Vector(t *testing.T) {
+	c := New()
+	c.vs[0] = vector.New(types.Type{Oid: types.T(types.T_uint32)})
+	require.Equal(t, vector.New(types.Type{Oid: types.T(types.T_uint32)}), c.Vector())
+}
+
+func TestCompare_Set(t *testing.T) {
+	c := New()
+	vector := vector.New(types.Type{Oid: types.T(types.T_uint32)})
+	c.Set(1, vector)
+	require.Equal(t, vector, c.vs[1])
+}
+
+func TestCompare_Compare(t *testing.T) {
+	c := New()
+	c.xs[0] = []uint32{5, 6}
+	c.xs[1] = []uint32{7, 8}
+	result := c.Compare(0, 1, 0, 0)
+	require.Equal(t, 1, result)
+	c.xs[1] = []uint32{5, 6}
+	result = c.Compare(0, 1, 0, 0)
+	require.Equal(t, 0, result)
+	c.xs[1] = []uint32{3, 4}
+	result = c.Compare(0, 1, 0, 0)
+	require.Equal(t, -1, result)
+}
diff --git a/pkg/compare2/desc/uint32s/types.go b/pkg/compare2/desc/uint32s/types.go
new file mode 100644
index 0000000000000000000000000000000000000000..e925514391ba81ec1a105a11c20ee90ab1604945
--- /dev/null
+++ b/pkg/compare2/desc/uint32s/types.go
@@ -0,0 +1,26 @@
+// Copyright 2021 Matrix Origin
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package uint32s
+
+import (
+	"github.com/matrixorigin/matrixone/pkg/container/nulls"
+	"github.com/matrixorigin/matrixone/pkg/container/vector"
+)
+
+type compare struct {
+	xs [][]uint32
+	ns []*nulls.Nulls
+	vs []*vector.Vector
+}
diff --git a/pkg/compare2/desc/uint64s/compare.go b/pkg/compare2/desc/uint64s/compare.go
new file mode 100644
index 0000000000000000000000000000000000000000..590544e0d150f3fb55fa2693f2f695d5b0f5572a
--- /dev/null
+++ b/pkg/compare2/desc/uint64s/compare.go
@@ -0,0 +1,59 @@
+// Copyright 2021 Matrix Origin
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package uint64s
+
+import (
+	"github.com/matrixorigin/matrixone/pkg/container/nulls"
+	"github.com/matrixorigin/matrixone/pkg/container/vector"
+	process "github.com/matrixorigin/matrixone/pkg/vm/process2"
+)
+
+func New() *compare {
+	return &compare{
+		xs: make([][]uint64, 2),
+		ns: make([]*nulls.Nulls, 2),
+		vs: make([]*vector.Vector, 2),
+	}
+}
+
+func (c *compare) Vector() *vector.Vector {
+	return c.vs[0]
+}
+
+func (c *compare) Set(idx int, v *vector.Vector) {
+	c.vs[idx] = v
+	c.ns[idx] = v.Nsp
+	c.xs[idx] = v.Col.([]uint64)
+}
+
+func (c *compare) Compare(veci, vecj int, vi, vj int64) int {
+	if c.xs[veci][vi] == c.xs[vecj][vj] {
+		return 0
+	}
+	if c.xs[veci][vi] < c.xs[vecj][vj] {
+		return +1
+	}
+	return -1
+}
+
+func (c *compare) Copy(vecSrc, vecDst int, src, dst int64, _ *process.Process) error {
+	if nulls.Any(c.ns[vecSrc]) && nulls.Contains(c.ns[vecSrc], (uint64(src))) {
+		nulls.Add(c.ns[vecDst], (uint64(dst)))
+	} else {
+		nulls.Del(c.ns[vecDst], (uint64(dst)))
+		c.xs[vecDst][dst] = c.xs[vecSrc][src]
+	}
+	return nil
+}
diff --git a/pkg/compare2/desc/uint64s/compare_test.go b/pkg/compare2/desc/uint64s/compare_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..8cfbe441af4d972f1097bf31aea1e2c13fcab6b4
--- /dev/null
+++ b/pkg/compare2/desc/uint64s/compare_test.go
@@ -0,0 +1,56 @@
+// Copyright 2021 Matrix Origin
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package uint64s
+
+import (
+	"github.com/matrixorigin/matrixone/pkg/container/nulls"
+	"github.com/matrixorigin/matrixone/pkg/container/types"
+	"github.com/matrixorigin/matrixone/pkg/container/vector"
+	"github.com/stretchr/testify/require"
+	"testing"
+)
+
+func TestNew(t *testing.T) {
+	require.Equal(t, &compare{xs: make([][]uint64, 2),
+		ns: make([]*nulls.Nulls, 2),
+		vs: make([]*vector.Vector, 2)}, New())
+}
+
+func TestCompare_Vector(t *testing.T) {
+	c := New()
+	c.vs[0] = vector.New(types.Type{Oid: types.T(types.T_uint64)})
+	require.Equal(t, vector.New(types.Type{Oid: types.T(types.T_uint64)}), c.Vector())
+}
+
+func TestCompare_Set(t *testing.T) {
+	c := New()
+	vector := vector.New(types.Type{Oid: types.T(types.T_uint64)})
+	c.Set(1, vector)
+	require.Equal(t, vector, c.vs[1])
+}
+
+func TestCompare_Compare(t *testing.T) {
+	c := New()
+	c.xs[0] = []uint64{5, 6}
+	c.xs[1] = []uint64{7, 8}
+	result := c.Compare(0, 1, 0, 0)
+	require.Equal(t, 1, result)
+	c.xs[1] = []uint64{5, 6}
+	result = c.Compare(0, 1, 0, 0)
+	require.Equal(t, 0, result)
+	c.xs[1] = []uint64{3, 4}
+	result = c.Compare(0, 1, 0, 0)
+	require.Equal(t, -1, result)
+}
diff --git a/pkg/compare2/desc/uint64s/types.go b/pkg/compare2/desc/uint64s/types.go
new file mode 100644
index 0000000000000000000000000000000000000000..5d7b7847289e23ca29fd7a0d1e850b08cb08fb86
--- /dev/null
+++ b/pkg/compare2/desc/uint64s/types.go
@@ -0,0 +1,26 @@
+// Copyright 2021 Matrix Origin
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package uint64s
+
+import (
+	"github.com/matrixorigin/matrixone/pkg/container/nulls"
+	"github.com/matrixorigin/matrixone/pkg/container/vector"
+)
+
+type compare struct {
+	xs [][]uint64
+	ns []*nulls.Nulls
+	vs []*vector.Vector
+}
diff --git a/pkg/compare2/desc/uint8s/compare.go b/pkg/compare2/desc/uint8s/compare.go
new file mode 100644
index 0000000000000000000000000000000000000000..03ad9a98800b8c3275ed32af5955562015238c48
--- /dev/null
+++ b/pkg/compare2/desc/uint8s/compare.go
@@ -0,0 +1,59 @@
+// Copyright 2021 Matrix Origin
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package uint8s
+
+import (
+	"github.com/matrixorigin/matrixone/pkg/container/nulls"
+	"github.com/matrixorigin/matrixone/pkg/container/vector"
+	process "github.com/matrixorigin/matrixone/pkg/vm/process2"
+)
+
+func New() *compare {
+	return &compare{
+		xs: make([][]uint8, 2),
+		ns: make([]*nulls.Nulls, 2),
+		vs: make([]*vector.Vector, 2),
+	}
+}
+
+func (c *compare) Vector() *vector.Vector {
+	return c.vs[0]
+}
+
+func (c *compare) Set(idx int, v *vector.Vector) {
+	c.vs[idx] = v
+	c.ns[idx] = v.Nsp
+	c.xs[idx] = v.Col.([]uint8)
+}
+
+func (c *compare) Compare(veci, vecj int, vi, vj int64) int {
+	if c.xs[veci][vi] == c.xs[vecj][vj] {
+		return 0
+	}
+	if c.xs[veci][vi] < c.xs[vecj][vj] {
+		return +1
+	}
+	return -1
+}
+
+func (c *compare) Copy(vecSrc, vecDst int, src, dst int64, _ *process.Process) error {
+	if nulls.Any(c.ns[vecSrc]) && nulls.Contains(c.ns[vecSrc], (uint64(src))) {
+		nulls.Add(c.ns[vecDst], (uint64(dst)))
+	} else {
+		nulls.Del(c.ns[vecDst], (uint64(dst)))
+		c.xs[vecDst][dst] = c.xs[vecSrc][src]
+	}
+	return nil
+}
diff --git a/pkg/compare2/desc/uint8s/compare_test.go b/pkg/compare2/desc/uint8s/compare_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..268ab7e295de9b579fb87038663c4d54bc17685f
--- /dev/null
+++ b/pkg/compare2/desc/uint8s/compare_test.go
@@ -0,0 +1,56 @@
+// Copyright 2021 Matrix Origin
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package uint8s
+
+import (
+	"github.com/matrixorigin/matrixone/pkg/container/nulls"
+	"github.com/matrixorigin/matrixone/pkg/container/types"
+	"github.com/matrixorigin/matrixone/pkg/container/vector"
+	"github.com/stretchr/testify/require"
+	"testing"
+)
+
+func TestNew(t *testing.T) {
+	require.Equal(t, &compare{xs: make([][]uint8, 2),
+		ns: make([]*nulls.Nulls, 2),
+		vs: make([]*vector.Vector, 2)}, New())
+}
+
+func TestCompare_Vector(t *testing.T) {
+	c := New()
+	c.vs[0] = vector.New(types.Type{Oid: types.T(types.T_uint8)})
+	require.Equal(t, vector.New(types.Type{Oid: types.T(types.T_uint8)}), c.Vector())
+}
+
+func TestCompare_Set(t *testing.T) {
+	c := New()
+	vector := vector.New(types.Type{Oid: types.T(types.T_uint8)})
+	c.Set(1, vector)
+	require.Equal(t, vector, c.vs[1])
+}
+
+func TestCompare_Compare(t *testing.T) {
+	c := New()
+	c.xs[0] = []uint8{5, 6}
+	c.xs[1] = []uint8{7, 8}
+	result := c.Compare(0, 1, 0, 0)
+	require.Equal(t, 1, result)
+	c.xs[1] = []uint8{5, 6}
+	result = c.Compare(0, 1, 0, 0)
+	require.Equal(t, 0, result)
+	c.xs[1] = []uint8{3, 4}
+	result = c.Compare(0, 1, 0, 0)
+	require.Equal(t, -1, result)
+}
diff --git a/pkg/compare2/desc/uint8s/types.go b/pkg/compare2/desc/uint8s/types.go
new file mode 100644
index 0000000000000000000000000000000000000000..77bf258f73b5cbdcc88c8c9d657cd9e1a33db0e0
--- /dev/null
+++ b/pkg/compare2/desc/uint8s/types.go
@@ -0,0 +1,26 @@
+// Copyright 2021 Matrix Origin
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package uint8s
+
+import (
+	"github.com/matrixorigin/matrixone/pkg/container/nulls"
+	"github.com/matrixorigin/matrixone/pkg/container/vector"
+)
+
+type compare struct {
+	xs [][]uint8
+	ns []*nulls.Nulls
+	vs []*vector.Vector
+}
diff --git a/pkg/compare2/desc/varchar/compare.go b/pkg/compare2/desc/varchar/compare.go
new file mode 100644
index 0000000000000000000000000000000000000000..48b56c25d809cabfd90d2a2951f4be5cf737db31
--- /dev/null
+++ b/pkg/compare2/desc/varchar/compare.go
@@ -0,0 +1,59 @@
+// Copyright 2021 Matrix Origin
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package varchar
+
+import (
+	"bytes"
+
+	"github.com/matrixorigin/matrixone/pkg/container/nulls"
+	"github.com/matrixorigin/matrixone/pkg/container/types"
+	"github.com/matrixorigin/matrixone/pkg/container/vector"
+	process "github.com/matrixorigin/matrixone/pkg/vm/process2"
+)
+
+func New() *compare {
+	return &compare{
+		vs: make([]*vector.Vector, 2),
+	}
+}
+
+func (c *compare) Vector() *vector.Vector {
+	return c.vs[0]
+}
+
+func (c *compare) Set(idx int, v *vector.Vector) {
+	c.vs[idx] = v
+}
+
+func (c *compare) Copy(vecSrc, vecDst int, src, dst int64, proc *process.Process) error {
+	if nulls.Any(c.vs[vecSrc].Nsp) && nulls.Contains(c.vs[vecSrc].Nsp, uint64(src)) {
+		nulls.Add(c.vs[vecDst].Nsp, uint64(dst))
+		return nil
+	}
+	nulls.Del(c.vs[vecDst].Nsp, uint64(dst))
+	return vector.Copy(c.vs[vecDst], c.vs[vecSrc], dst, src, proc.Mp)
+}
+
+func (c *compare) Compare(veci, vecj int, vi, vj int64) int {
+	x, y := c.vs[veci].Col.(*types.Bytes), c.vs[vecj].Col.(*types.Bytes)
+	r := bytes.Compare(x.Get(vi), y.Get(vj))
+	switch r {
+	case +1:
+		r = -1
+	case -1:
+		r = +1
+	}
+	return r
+}
diff --git a/pkg/compare2/desc/varchar/compare_test.go b/pkg/compare2/desc/varchar/compare_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..3e40ea7230a4efd5854f60e55e289bda8e01595a
--- /dev/null
+++ b/pkg/compare2/desc/varchar/compare_test.go
@@ -0,0 +1,75 @@
+// Copyright 2021 Matrix Origin
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package varchar
+
+import (
+	"github.com/matrixorigin/matrixone/pkg/container/types"
+	"github.com/matrixorigin/matrixone/pkg/container/vector"
+	"github.com/stretchr/testify/require"
+	"testing"
+)
+
+func TestNew(t *testing.T) {
+	require.Equal(t, &compare{vs: make([]*vector.Vector, 2)}, New())
+}
+
+func TestCompare_Vector(t *testing.T) {
+	c := New()
+	c.vs[0] = vector.New(types.Type{Oid: types.T(types.T_char)})
+	require.Equal(t, vector.New(types.Type{Oid: types.T(types.T_char)}), c.Vector())
+}
+
+func TestCompare_Set(t *testing.T) {
+	c := New()
+	vector := vector.New(types.Type{Oid: types.T(types.T_char)})
+	c.Set(1, vector)
+	require.Equal(t, vector, c.vs[1])
+}
+
+func TestCompare_Compare(t *testing.T) {
+	c := New()
+	c.vs[0] = vector.New(types.Type{Oid: types.T(types.T_char)})
+	c.vs[1] = vector.New(types.Type{Oid: types.T(types.T_char)})
+	c.vs[0].Col = &types.Bytes{
+		Data:    []byte("helloGutkonichiwanihao"),
+		Offsets: []uint32{0, 5, 8, 17},
+		Lengths: []uint32{5, 3, 9, 5},
+	}
+	c.vs[0].Data = c.vs[0].Col.(*types.Bytes).Data
+	c.vs[1].Col = &types.Bytes{
+		Data:    []byte("helloGutkonichiwanihao"),
+		Offsets: []uint32{0, 5, 8, 17},
+		Lengths: []uint32{5, 3, 9, 5},
+	}
+	c.vs[1].Data = c.vs[1].Col.(*types.Bytes).Data
+	result := c.Compare(0, 1, 0, 0)
+	require.Equal(t, 0, result)
+	c.vs[1].Col = &types.Bytes{
+		Data:    []byte("heyheyheyhey"),
+		Offsets: []uint32{0, 3, 6, 9},
+		Lengths: []uint32{3, 3, 3, 3},
+	}
+	c.vs[1].Data = c.vs[1].Col.(*types.Bytes).Data
+	result = c.Compare(0, 1, 0, 0)
+	require.Equal(t, 1, result)
+	c.vs[1].Col = &types.Bytes{
+		Data:    []byte("aaaa"),
+		Offsets: []uint32{0, 1, 2, 3},
+		Lengths: []uint32{1, 1, 1, 1},
+	}
+	c.vs[1].Data = c.vs[1].Col.(*types.Bytes).Data
+	result = c.Compare(0, 1, 0, 0)
+	require.Equal(t, -1, result)
+}
diff --git a/pkg/compare2/desc/varchar/types.go b/pkg/compare2/desc/varchar/types.go
new file mode 100644
index 0000000000000000000000000000000000000000..79202a5606f2da9e6272c5c58238a4fdffcc8cad
--- /dev/null
+++ b/pkg/compare2/desc/varchar/types.go
@@ -0,0 +1,23 @@
+// Copyright 2021 Matrix Origin
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package varchar
+
+import (
+	"github.com/matrixorigin/matrixone/pkg/container/vector"
+)
+
+type compare struct {
+	vs []*vector.Vector
+}
diff --git a/pkg/compare2/types.go b/pkg/compare2/types.go
new file mode 100644
index 0000000000000000000000000000000000000000..abb8b2e040e966f4ed833eb70a98514a1201a537
--- /dev/null
+++ b/pkg/compare2/types.go
@@ -0,0 +1,27 @@
+// Copyright 2021 Matrix Origin
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package compare
+
+import (
+	"github.com/matrixorigin/matrixone/pkg/container/vector"
+	process "github.com/matrixorigin/matrixone/pkg/vm/process2"
+)
+
+type Compare interface {
+	Vector() *vector.Vector
+	Set(int, *vector.Vector)
+	Compare(int, int, int64, int64) int
+	Copy(int, int, int64, int64, *process.Process) error
+}
diff --git a/pkg/container/batch2/batch.go b/pkg/container/batch2/batch.go
new file mode 100644
index 0000000000000000000000000000000000000000..bb7834d2512684a3fb201927fe54267785da33d9
--- /dev/null
+++ b/pkg/container/batch2/batch.go
@@ -0,0 +1,142 @@
+// Copyright 2021 Matrix Origin
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package batch
+
+import (
+	"bytes"
+	"fmt"
+
+	"github.com/matrixorigin/matrixone/pkg/container/vector"
+	"github.com/matrixorigin/matrixone/pkg/encoding"
+	"github.com/matrixorigin/matrixone/pkg/errno"
+	"github.com/matrixorigin/matrixone/pkg/sql/errors"
+	"github.com/matrixorigin/matrixone/pkg/vectorize/shuffle"
+	"github.com/matrixorigin/matrixone/pkg/vm/mheap"
+)
+
+func New(n int) *Batch {
+	return &Batch{
+		Vecs: make([]*vector.Vector, n),
+	}
+}
+
+func Reorder(bat *Batch, poses []int32) {
+	for i, pos := range poses {
+		bat.Vecs[i], bat.Vecs[pos] = bat.Vecs[pos], bat.Vecs[i]
+	}
+}
+
+func SetLength(bat *Batch, n int) {
+	for _, vec := range bat.Vecs {
+		vector.SetLength(vec, n)
+	}
+	bat.Zs = bat.Zs[:n]
+}
+
+func Shrink(bat *Batch, sels []int64) {
+	for _, vec := range bat.Vecs {
+		vector.Shrink(vec, sels)
+	}
+	vs := bat.Zs
+	for i, sel := range sels {
+		vs[i] = vs[sel]
+	}
+	bat.Zs = bat.Zs[:len(sels)]
+}
+
+func Shuffle(bat *Batch, sels []int64, m *mheap.Mheap) error {
+	if len(sels) > 0 {
+		for _, vec := range bat.Vecs {
+			if err := vector.Shuffle(vec, sels, m); err != nil {
+				return err
+			}
+		}
+		data, err := mheap.Alloc(m, int64(len(bat.Zs))*8)
+		if err != nil {
+			return err
+		}
+		ws := encoding.DecodeInt64Slice(data)
+		bat.Zs = shuffle.Int64Shuffle(bat.Zs, ws, sels)
+		mheap.Free(m, data)
+	}
+	return nil
+}
+
+func Length(bat *Batch) int {
+	return len(bat.Zs)
+}
+
+func Prefetch(bat *Batch, poses []int32, vecs []*vector.Vector) {
+	for i, pos := range poses {
+		vecs[i] = GetVector(bat, pos)
+	}
+}
+
+func GetVector(bat *Batch, pos int32) *vector.Vector {
+	return bat.Vecs[pos]
+}
+
+func Clean(bat *Batch, m *mheap.Mheap) {
+	for _, vec := range bat.Vecs {
+		if vec != nil {
+			vector.Clean(vec, m)
+		}
+	}
+	bat.Vecs = nil
+	bat.Zs = nil
+}
+
+func (bat *Batch) String() string {
+	var buf bytes.Buffer
+
+	for i, vec := range bat.Vecs {
+		buf.WriteString(fmt.Sprintf("%v:\n", i))
+		if len(bat.Zs) > 0 {
+			buf.WriteString(fmt.Sprintf("\t%s\n", vec))
+		}
+	}
+	return buf.String()
+}
+
+func (bat *Batch) Append(mp *mheap.Mheap, b *Batch) (*Batch, error) {
+	if bat == nil {
+		return b, nil
+	}
+	if len(bat.Vecs) != len(b.Vecs) {
+		return nil, errors.New(errno.InternalError, "unexpected error happens in batch append")
+	}
+	if len(bat.Vecs) == 0 {
+		return bat, nil
+	}
+	flags := make([]uint8, vector.Length(b.Vecs[0]))
+	for i := range flags {
+		flags[i]++
+	}
+	for i := range bat.Vecs {
+		if err := vector.UnionBatch(bat.Vecs[i], b.Vecs[i], 0, vector.Length(b.Vecs[i]), flags[:vector.Length(b.Vecs[i])], mp); err != nil {
+			return nil, err
+		}
+	}
+	bat.Zs = append(bat.Zs, b.Zs...)
+	return bat, nil
+}
+
+// InitZsOne init Batch.Zs and values are all 1
+func (bat *Batch) InitZsOne(len int) {
+	bat.Zs = make([]int64, len)
+	for i := range bat.Zs {
+		bat.Zs[i]++
+	}
+}
diff --git a/pkg/container/batch2/batch_test.go b/pkg/container/batch2/batch_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..bb97483969c13e41fbb0d4eb7b5d9565330fcbcb
--- /dev/null
+++ b/pkg/container/batch2/batch_test.go
@@ -0,0 +1,127 @@
+// Copyright 2021 Matrix Origin
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package batch
+
+import (
+	"fmt"
+	"strconv"
+	"testing"
+
+	"github.com/matrixorigin/matrixone/pkg/container/types"
+	"github.com/matrixorigin/matrixone/pkg/container/vector"
+	"github.com/matrixorigin/matrixone/pkg/encoding"
+	"github.com/matrixorigin/matrixone/pkg/vm/mheap"
+	"github.com/matrixorigin/matrixone/pkg/vm/mmu/guest"
+	"github.com/matrixorigin/matrixone/pkg/vm/mmu/host"
+	"github.com/stretchr/testify/require"
+)
+
+const (
+	Rows = 10
+)
+
+func TestBatch(t *testing.T) {
+	mp := mheap.New(guest.New(1<<30, host.New(1<<30)))
+	bat0 := newBatch(t, []types.Type{{Oid: types.T_int8}}, mp)
+	bat1 := newBatch(t, []types.Type{{Oid: types.T_int8}}, mp)
+	Reorder(bat0, []int32{0})
+	SetLength(bat0, 10)
+	sels := []int64{1, 2, 3}
+	Shrink(bat0, sels)
+	Shuffle(bat1, sels, mp)
+	{
+		vecs := make([]*vector.Vector, 1)
+		Prefetch(bat0, []int32{0}, vecs)
+	}
+	fmt.Printf("%v\n", bat0.String())
+	_, err := bat0.Append(mp, bat1)
+	require.NoError(t, err)
+	bat0.InitZsOne(Length(bat0))
+	Clean(bat0, mp)
+	Clean(bat1, mp)
+}
+
+// create a new block based on the attribute information, flg indicates if the data is all duplicated
+func newBatch(t *testing.T, ts []types.Type, mp *mheap.Mheap) *Batch {
+	bat := New(len(ts))
+	bat.Zs = make([]int64, Rows)
+	for i := range bat.Zs {
+		bat.Zs[i] = 1
+	}
+	for i := range bat.Vecs {
+		vec := vector.New(ts[i])
+		switch vec.Typ.Oid {
+		case types.T_int8:
+			data, err := mheap.Alloc(mp, Rows*1)
+			require.NoError(t, err)
+			vec.Data = data
+			vs := encoding.DecodeInt8Slice(vec.Data)[:Rows]
+			for i := range vs {
+				vs[i] = int8(i)
+			}
+			vec.Col = vs
+		case types.T_int64:
+			data, err := mheap.Alloc(mp, Rows*8)
+			require.NoError(t, err)
+			vec.Data = data
+			vs := encoding.DecodeInt64Slice(vec.Data)[:Rows]
+			for i := range vs {
+				vs[i] = int64(i)
+			}
+			vec.Col = vs
+		case types.T_float64:
+			data, err := mheap.Alloc(mp, Rows*8)
+			require.NoError(t, err)
+			vec.Data = data
+			vs := encoding.DecodeFloat64Slice(vec.Data)[:Rows]
+			for i := range vs {
+				vs[i] = float64(i)
+			}
+			vec.Col = vs
+		case types.T_date:
+			data, err := mheap.Alloc(mp, Rows*4)
+			require.NoError(t, err)
+			vec.Data = data
+			vs := encoding.DecodeDateSlice(vec.Data)[:Rows]
+			for i := range vs {
+				vs[i] = types.Date(i)
+			}
+			vec.Col = vs
+		case types.T_char, types.T_varchar:
+			size := 0
+			vs := make([][]byte, Rows)
+			for i := range vs {
+				vs[i] = []byte(strconv.Itoa(i))
+				size += len(vs[i])
+			}
+			data, err := mheap.Alloc(mp, int64(size))
+			require.NoError(t, err)
+			data = data[:0]
+			col := new(types.Bytes)
+			o := uint32(0)
+			for _, v := range vs {
+				data = append(data, v...)
+				col.Offsets = append(col.Offsets, o)
+				o += uint32(len(v))
+				col.Lengths = append(col.Lengths, uint32(len(v)))
+			}
+			col.Data = data
+			vec.Col = col
+			vec.Data = data
+		}
+		bat.Vecs[i] = vec
+	}
+	return bat
+}
diff --git a/pkg/container/batch2/types.go b/pkg/container/batch2/types.go
new file mode 100644
index 0000000000000000000000000000000000000000..18181d9f5d6804b208b7bdbf7757194262aa8dcc
--- /dev/null
+++ b/pkg/container/batch2/types.go
@@ -0,0 +1,29 @@
+// Copyright 2021 Matrix Origin
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package batch
+
+import (
+	"github.com/matrixorigin/matrixone/pkg/container/vector"
+)
+
+// Batch represents a part of a relationship
+type Batch struct {
+	// ring
+	Zs []int64
+	// columns
+	Vecs []*vector.Vector
+	// anything
+	Ht interface{}
+}
diff --git a/pkg/sql/colexec2/limit/limit.go b/pkg/sql/colexec2/limit/limit.go
index 4e896dca3f7e557377f87bbc7381cc9fb04d33f7..203003e6468b59dc1ee46d93ba8d9829e22b2171 100644
--- a/pkg/sql/colexec2/limit/limit.go
+++ b/pkg/sql/colexec2/limit/limit.go
@@ -17,8 +17,9 @@ package limit
 import (
 	"bytes"
 	"fmt"
-	"github.com/matrixorigin/matrixone/pkg/container/batch"
-	"github.com/matrixorigin/matrixone/pkg/vm/process"
+
+	batch "github.com/matrixorigin/matrixone/pkg/container/batch2"
+	process "github.com/matrixorigin/matrixone/pkg/vm/process2"
 )
 
 func String(arg interface{}, buf *bytes.Buffer) {
diff --git a/pkg/sql/colexec2/limit/limit_test.go b/pkg/sql/colexec2/limit/limit_test.go
index ac6460181b89fd8642777575883e4db7cb51ba1a..79979cfd3a6fd4c4ce37895d9c172eca0bcbef1f 100644
--- a/pkg/sql/colexec2/limit/limit_test.go
+++ b/pkg/sql/colexec2/limit/limit_test.go
@@ -19,14 +19,14 @@ import (
 	"strconv"
 	"testing"
 
-	"github.com/matrixorigin/matrixone/pkg/container/batch"
+	batch "github.com/matrixorigin/matrixone/pkg/container/batch2"
 	"github.com/matrixorigin/matrixone/pkg/container/types"
 	"github.com/matrixorigin/matrixone/pkg/container/vector"
 	"github.com/matrixorigin/matrixone/pkg/encoding"
 	"github.com/matrixorigin/matrixone/pkg/vm/mheap"
 	"github.com/matrixorigin/matrixone/pkg/vm/mmu/guest"
 	"github.com/matrixorigin/matrixone/pkg/vm/mmu/host"
-	"github.com/matrixorigin/matrixone/pkg/vm/process"
+	process "github.com/matrixorigin/matrixone/pkg/vm/process2"
 	"github.com/stretchr/testify/require"
 )
 
@@ -38,7 +38,6 @@ const (
 // add unit tests for cases
 type limitTestCase struct {
 	arg   *Argument
-	attrs []string
 	types []types.Type
 	proc  *process.Process
 }
@@ -52,8 +51,7 @@ func init() {
 	gm := guest.New(1<<30, hm)
 	tcs = []limitTestCase{
 		{
-			proc:  process.New(mheap.New(gm)),
-			attrs: []string{"1"},
+			proc: process.New(mheap.New(gm)),
 			types: []types.Type{
 				{Oid: types.T_int8},
 			},
@@ -63,8 +61,7 @@ func init() {
 			},
 		},
 		{
-			proc:  process.New(mheap.New(gm)),
-			attrs: []string{"1"},
+			proc: process.New(mheap.New(gm)),
 			types: []types.Type{
 				{Oid: types.T_int8},
 			},
@@ -74,8 +71,7 @@ func init() {
 			},
 		},
 		{
-			proc:  process.New(mheap.New(gm)),
-			attrs: []string{"1"},
+			proc: process.New(mheap.New(gm)),
 			types: []types.Type{
 				{Oid: types.T_int8},
 			},
@@ -103,9 +99,9 @@ func TestPrepare(t *testing.T) {
 func TestLimit(t *testing.T) {
 	for _, tc := range tcs {
 		Prepare(tc.proc, tc.arg)
-		tc.proc.Reg.InputBatch = newBatch(t, tc.types, tc.attrs, tc.proc)
+		tc.proc.Reg.InputBatch = newBatch(t, tc.types, tc.proc, Rows)
 		Call(tc.proc, tc.arg)
-		tc.proc.Reg.InputBatch = newBatch(t, tc.types, tc.attrs, tc.proc)
+		tc.proc.Reg.InputBatch = newBatch(t, tc.types, tc.proc, Rows)
 		Call(tc.proc, tc.arg)
 		tc.proc.Reg.InputBatch = &batch.Batch{}
 		Call(tc.proc, tc.arg)
@@ -115,84 +111,81 @@ func TestLimit(t *testing.T) {
 }
 
 func BenchmarkLimit(b *testing.B) {
-	hm := host.New(1 << 30)
-	gm := guest.New(1<<30, hm)
-	tcs = []limitTestCase{
-		{
-			proc:  process.New(mheap.New(gm)),
-			attrs: []string{"1"},
-			types: []types.Type{
-				{Oid: types.T_int8},
+	for i := 0; i < b.N; i++ {
+		hm := host.New(1 << 30)
+		gm := guest.New(1<<30, hm)
+		tcs = []limitTestCase{
+			{
+				proc: process.New(mheap.New(gm)),
+				types: []types.Type{
+					{Oid: types.T_int8},
+				},
+				arg: &Argument{
+					Seen:  0,
+					Limit: 8,
+				},
 			},
-			arg: &Argument{
-				Seen:  0,
-				Limit: 8,
-			},
-		},
-	}
+		}
 
-	t := new(testing.T)
-	for _, tc := range tcs {
-		Prepare(tc.proc, tc.arg)
-		tc.proc.Reg.InputBatch = newBatch(t, tc.types, tc.attrs, tc.proc)
-		Call(tc.proc, tc.arg)
-		tc.proc.Reg.InputBatch = &batch.Batch{}
-		Call(tc.proc, tc.arg)
-		tc.proc.Reg.InputBatch = nil
-		Call(tc.proc, tc.arg)
+		t := new(testing.T)
+		for _, tc := range tcs {
+			Prepare(tc.proc, tc.arg)
+			tc.proc.Reg.InputBatch = newBatch(t, tc.types, tc.proc, BenchmarkRows)
+			Call(tc.proc, tc.arg)
+			tc.proc.Reg.InputBatch = &batch.Batch{}
+			Call(tc.proc, tc.arg)
+			tc.proc.Reg.InputBatch = nil
+			Call(tc.proc, tc.arg)
+		}
 	}
 }
 
-// create a new block based on the attribute information, flg indicates if the data is all duplicated
-func newBatch(t *testing.T, ts []types.Type, attrs []string, proc *process.Process) *batch.Batch {
-	bat := batch.New(true, attrs)
-	bat.Zs = make([]int64, Rows)
-	bat.Ht = []*vector.Vector{}
-	for i := range bat.Zs {
-		bat.Zs[i] = 1
-	}
+// create a new block based on the type information
+func newBatch(t *testing.T, ts []types.Type, proc *process.Process, rows int64) *batch.Batch {
+	bat := batch.New(len(ts))
+	bat.InitZsOne(int(rows))
 	for i := range bat.Vecs {
 		vec := vector.New(ts[i])
 		switch vec.Typ.Oid {
 		case types.T_int8:
-			data, err := mheap.Alloc(proc.Mp, Rows*1)
+			data, err := mheap.Alloc(proc.Mp, rows*1)
 			require.NoError(t, err)
 			vec.Data = data
-			vs := encoding.DecodeInt8Slice(vec.Data)[:Rows]
+			vs := encoding.DecodeInt8Slice(vec.Data)[:rows]
 			for i := range vs {
 				vs[i] = int8(i)
 			}
 			vec.Col = vs
 		case types.T_int64:
-			data, err := mheap.Alloc(proc.Mp, Rows*8)
+			data, err := mheap.Alloc(proc.Mp, rows*8)
 			require.NoError(t, err)
 			vec.Data = data
-			vs := encoding.DecodeInt64Slice(vec.Data)[:Rows]
+			vs := encoding.DecodeInt64Slice(vec.Data)[:rows]
 			for i := range vs {
 				vs[i] = int64(i)
 			}
 			vec.Col = vs
 		case types.T_float64:
-			data, err := mheap.Alloc(proc.Mp, Rows*8)
+			data, err := mheap.Alloc(proc.Mp, rows*8)
 			require.NoError(t, err)
 			vec.Data = data
-			vs := encoding.DecodeFloat64Slice(vec.Data)[:Rows]
+			vs := encoding.DecodeFloat64Slice(vec.Data)[:rows]
 			for i := range vs {
 				vs[i] = float64(i)
 			}
 			vec.Col = vs
 		case types.T_date:
-			data, err := mheap.Alloc(proc.Mp, Rows*4)
+			data, err := mheap.Alloc(proc.Mp, rows*4)
 			require.NoError(t, err)
 			vec.Data = data
-			vs := encoding.DecodeDateSlice(vec.Data)[:Rows]
+			vs := encoding.DecodeDateSlice(vec.Data)[:rows]
 			for i := range vs {
 				vs[i] = types.Date(i)
 			}
 			vec.Col = vs
 		case types.T_char, types.T_varchar:
 			size := 0
-			vs := make([][]byte, Rows)
+			vs := make([][]byte, rows)
 			for i := range vs {
 				vs[i] = []byte(strconv.Itoa(i))
 				size += len(vs[i])
diff --git a/pkg/sql/colexec2/mergelimit/limit.go b/pkg/sql/colexec2/mergelimit/limit.go
index 435d5ba428dd263af8a6a127bb4ba1bad6bdebe0..916e2b2a1c299138edfd48d9c7de08e7896866db 100644
--- a/pkg/sql/colexec2/mergelimit/limit.go
+++ b/pkg/sql/colexec2/mergelimit/limit.go
@@ -18,8 +18,8 @@ import (
 	"bytes"
 	"fmt"
 
-	"github.com/matrixorigin/matrixone/pkg/container/batch"
-	"github.com/matrixorigin/matrixone/pkg/vm/process"
+	batch "github.com/matrixorigin/matrixone/pkg/container/batch2"
+	process "github.com/matrixorigin/matrixone/pkg/vm/process2"
 )
 
 func String(arg interface{}, buf *bytes.Buffer) {
diff --git a/pkg/sql/colexec2/mergelimit/limit_test.go b/pkg/sql/colexec2/mergelimit/limit_test.go
index 5bc758a03b15da3dd5b29f691e5f9937170176a6..a1ef603eaafd1f0665a1681cb4e5d499bbf8c233 100644
--- a/pkg/sql/colexec2/mergelimit/limit_test.go
+++ b/pkg/sql/colexec2/mergelimit/limit_test.go
@@ -20,14 +20,14 @@ import (
 	"strconv"
 	"testing"
 
-	"github.com/matrixorigin/matrixone/pkg/container/batch"
+	batch "github.com/matrixorigin/matrixone/pkg/container/batch2"
 	"github.com/matrixorigin/matrixone/pkg/container/types"
 	"github.com/matrixorigin/matrixone/pkg/container/vector"
 	"github.com/matrixorigin/matrixone/pkg/encoding"
 	"github.com/matrixorigin/matrixone/pkg/vm/mheap"
 	"github.com/matrixorigin/matrixone/pkg/vm/mmu/guest"
 	"github.com/matrixorigin/matrixone/pkg/vm/mmu/host"
-	"github.com/matrixorigin/matrixone/pkg/vm/process"
+	process "github.com/matrixorigin/matrixone/pkg/vm/process2"
 	"github.com/stretchr/testify/require"
 )
 
@@ -39,7 +39,6 @@ const (
 // add unit tests for cases
 type limitTestCase struct {
 	arg    *Argument
-	attrs  []string
 	types  []types.Type
 	proc   *process.Process
 	cancel context.CancelFunc
@@ -73,19 +72,12 @@ func TestPrepare(t *testing.T) {
 }
 
 func TestLimit(t *testing.T) {
-	hm := host.New(1 << 30)
-	gm := guest.New(1<<30, hm)
-	tcs = []limitTestCase{
-		newTestCase(mheap.New(gm), 8),
-		newTestCase(mheap.New(gm), 10),
-		newTestCase(mheap.New(gm), 12),
-	}
 	for _, tc := range tcs {
 		Prepare(tc.proc, tc.arg)
-		tc.proc.Reg.MergeReceivers[0].Ch <- newBatch(t, tc.types, tc.attrs, tc.proc)
+		tc.proc.Reg.MergeReceivers[0].Ch <- newBatch(t, tc.types, tc.proc, Rows)
 		tc.proc.Reg.MergeReceivers[0].Ch <- &batch.Batch{}
 		tc.proc.Reg.MergeReceivers[0].Ch <- nil
-		tc.proc.Reg.MergeReceivers[1].Ch <- newBatch(t, tc.types, tc.attrs, tc.proc)
+		tc.proc.Reg.MergeReceivers[1].Ch <- newBatch(t, tc.types, tc.proc, Rows)
 		tc.proc.Reg.MergeReceivers[1].Ch <- &batch.Batch{}
 		tc.proc.Reg.MergeReceivers[1].Ch <- nil
 		for {
@@ -97,29 +89,30 @@ func TestLimit(t *testing.T) {
 }
 
 func BenchmarkLimit(b *testing.B) {
-	hm := host.New(1 << 30)
-	gm := guest.New(1<<30, hm)
-	tcs = []limitTestCase{
-		newTestCase(mheap.New(gm), 8),
-		newTestCase(mheap.New(gm), 10),
-		newTestCase(mheap.New(gm), 12),
-	}
+	for i := 0; i < b.N; i++ {
+		hm := host.New(1 << 30)
+		gm := guest.New(1<<30, hm)
+		tcs = []limitTestCase{
+			newTestCase(mheap.New(gm), 8),
+			newTestCase(mheap.New(gm), 10),
+			newTestCase(mheap.New(gm), 12),
+		}
 
-	t := new(testing.T)
-	for _, tc := range tcs {
-		Prepare(tc.proc, tc.arg)
-		tc.proc.Reg.MergeReceivers[0].Ch <- newBatch(t, tc.types, tc.attrs, tc.proc)
-		tc.proc.Reg.MergeReceivers[0].Ch <- &batch.Batch{}
-		tc.proc.Reg.MergeReceivers[0].Ch <- nil
-		tc.proc.Reg.MergeReceivers[1].Ch <- newBatch(t, tc.types, tc.attrs, tc.proc)
-		tc.proc.Reg.MergeReceivers[1].Ch <- &batch.Batch{}
-		tc.proc.Reg.MergeReceivers[1].Ch <- nil
-		for {
-			if ok, err := Call(tc.proc, tc.arg); ok || err != nil {
-				break
+		t := new(testing.T)
+		for _, tc := range tcs {
+			Prepare(tc.proc, tc.arg)
+			tc.proc.Reg.MergeReceivers[0].Ch <- newBatch(t, tc.types, tc.proc, BenchmarkRows)
+			tc.proc.Reg.MergeReceivers[0].Ch <- &batch.Batch{}
+			tc.proc.Reg.MergeReceivers[0].Ch <- nil
+			tc.proc.Reg.MergeReceivers[1].Ch <- newBatch(t, tc.types, tc.proc, BenchmarkRows)
+			tc.proc.Reg.MergeReceivers[1].Ch <- &batch.Batch{}
+			tc.proc.Reg.MergeReceivers[1].Ch <- nil
+			for {
+				if ok, err := Call(tc.proc, tc.arg); ok || err != nil {
+					break
+				}
 			}
 		}
-
 	}
 }
 
@@ -136,8 +129,7 @@ func newTestCase(m *mheap.Mheap, limit uint64) limitTestCase {
 		Ch:  make(chan *batch.Batch, 3),
 	}
 	return limitTestCase{
-		proc:  proc,
-		attrs: []string{"1"},
+		proc: proc,
 		types: []types.Type{
 			{Oid: types.T_int8},
 		},
@@ -148,56 +140,52 @@ func newTestCase(m *mheap.Mheap, limit uint64) limitTestCase {
 	}
 }
 
-// create a new block based on the attribute information, flg indicates if the data is all duplicated
-func newBatch(t *testing.T, ts []types.Type, attrs []string, proc *process.Process) *batch.Batch {
-	bat := batch.New(true, attrs)
-	bat.Zs = make([]int64, Rows)
-	bat.Ht = []*vector.Vector{}
-	for i := range bat.Zs {
-		bat.Zs[i] = 1
-	}
+// create a new block based on the type information
+func newBatch(t *testing.T, ts []types.Type, proc *process.Process, rows int64) *batch.Batch {
+	bat := batch.New(len(ts))
+	bat.InitZsOne(int(rows))
 	for i := range bat.Vecs {
 		vec := vector.New(ts[i])
 		switch vec.Typ.Oid {
 		case types.T_int8:
-			data, err := mheap.Alloc(proc.Mp, Rows*1)
+			data, err := mheap.Alloc(proc.Mp, rows*1)
 			require.NoError(t, err)
 			vec.Data = data
-			vs := encoding.DecodeInt8Slice(vec.Data)[:Rows]
+			vs := encoding.DecodeInt8Slice(vec.Data)[:rows]
 			for i := range vs {
 				vs[i] = int8(i)
 			}
 			vec.Col = vs
 		case types.T_int64:
-			data, err := mheap.Alloc(proc.Mp, Rows*8)
+			data, err := mheap.Alloc(proc.Mp, rows*8)
 			require.NoError(t, err)
 			vec.Data = data
-			vs := encoding.DecodeInt64Slice(vec.Data)[:Rows]
+			vs := encoding.DecodeInt64Slice(vec.Data)[:rows]
 			for i := range vs {
 				vs[i] = int64(i)
 			}
 			vec.Col = vs
 		case types.T_float64:
-			data, err := mheap.Alloc(proc.Mp, Rows*8)
+			data, err := mheap.Alloc(proc.Mp, rows*8)
 			require.NoError(t, err)
 			vec.Data = data
-			vs := encoding.DecodeFloat64Slice(vec.Data)[:Rows]
+			vs := encoding.DecodeFloat64Slice(vec.Data)[:rows]
 			for i := range vs {
 				vs[i] = float64(i)
 			}
 			vec.Col = vs
 		case types.T_date:
-			data, err := mheap.Alloc(proc.Mp, Rows*4)
+			data, err := mheap.Alloc(proc.Mp, rows*4)
 			require.NoError(t, err)
 			vec.Data = data
-			vs := encoding.DecodeDateSlice(vec.Data)[:Rows]
+			vs := encoding.DecodeDateSlice(vec.Data)[:rows]
 			for i := range vs {
 				vs[i] = types.Date(i)
 			}
 			vec.Col = vs
 		case types.T_char, types.T_varchar:
 			size := 0
-			vs := make([][]byte, Rows)
+			vs := make([][]byte, rows)
 			for i := range vs {
 				vs[i] = []byte(strconv.Itoa(i))
 				size += len(vs[i])
diff --git a/pkg/sql/colexec2/mergeoffset/offset.go b/pkg/sql/colexec2/mergeoffset/offset.go
index 2a1c93f6a079a31fda2db853c90ca0176022ba15..9947ce08f03359d9f4fdd55a235d42b35e9fb7be 100644
--- a/pkg/sql/colexec2/mergeoffset/offset.go
+++ b/pkg/sql/colexec2/mergeoffset/offset.go
@@ -17,26 +17,24 @@ package mergeoffset
 import (
 	"bytes"
 	"fmt"
-	"github.com/matrixorigin/matrixone/pkg/container/batch"
-	"github.com/matrixorigin/matrixone/pkg/encoding"
-	"github.com/matrixorigin/matrixone/pkg/vm/mheap"
-	"github.com/matrixorigin/matrixone/pkg/vm/process"
+
+	batch "github.com/matrixorigin/matrixone/pkg/container/batch2"
+	process "github.com/matrixorigin/matrixone/pkg/vm/process2"
 )
 
 func String(arg interface{}, buf *bytes.Buffer) {
-	argument := arg.(*Argument)
-	buf.WriteString(fmt.Sprintf("mergeOffset(%d)", argument.Offset))
+	n := arg.(*Argument)
+	buf.WriteString(fmt.Sprintf("mergeOffset(%d)", n.Offset))
 }
 
 func Prepare(_ *process.Process, arg interface{}) error {
-	argument := arg.(*Argument)
-	argument.ctr.seen = 0
+	n := arg.(*Argument)
+	n.ctr.seen = 0
 	return nil
 }
 
 func Call(proc *process.Process, arg interface{}) (bool, error) {
-	argument := arg.(*Argument)
-
+	n := arg.(*Argument)
 	for i := 0; i < len(proc.Reg.MergeReceivers); i++ {
 		rec := proc.Reg.MergeReceivers[i]
 		bat := <-rec.Ch
@@ -55,41 +53,30 @@ func Call(proc *process.Process, arg interface{}) (bool, error) {
 			}
 		}
 
-		if argument.ctr.seen > argument.Offset {
+		if n.ctr.seen > n.Offset {
 			return false, nil
 		}
 		length := len(bat.Zs)
 		// bat = PartOne + PartTwo, and PartTwo is required.
-		if argument.ctr.seen+uint64(length) > argument.Offset {
-			data, sels, err := newSels(int64(argument.Offset-argument.ctr.seen), int64(length)-int64(argument.Offset-argument.ctr.seen), proc.Mp)
-			if err != nil {
-				batch.Clean(bat, proc.Mp)
-				return false, err
-			}
-			argument.ctr.seen += uint64(length)
+		if n.ctr.seen+uint64(length) > n.Offset {
+			sels := newSels(int64(n.Offset-n.ctr.seen), int64(length)-int64(n.Offset-n.ctr.seen))
+			n.ctr.seen += uint64(length)
 			batch.Shrink(bat, sels)
-			mheap.Free(proc.Mp, data)
 			proc.Reg.InputBatch = bat
 			return false, nil
 		}
-
-		argument.ctr.seen += uint64(length)
+		n.ctr.seen += uint64(length)
 		batch.Clean(bat, proc.Mp)
 		proc.Reg.InputBatch = nil
 		i--
 	}
-
 	return true, nil
 }
 
-func newSels(start, count int64, mp *mheap.Mheap) ([]byte, []int64, error) {
-	data, err := mheap.Alloc(mp, count*8)
-	if err != nil {
-		return nil, nil, err
-	}
-	sels := encoding.DecodeInt64Slice(data)
+func newSels(start, count int64) []int64 {
+	sels := make([]int64, count)
 	for i := int64(0); i < count; i++ {
 		sels[i] = start + i
 	}
-	return data, sels[:count], nil
+	return sels[:count]
 }
diff --git a/pkg/sql/colexec2/mergeoffset/offset_test.go b/pkg/sql/colexec2/mergeoffset/offset_test.go
index 0c1b2b504becc22b6ce8cfd5f3b4c7c2372c6438..bb538491af8c66f296c0aef7387b224e359f7836 100644
--- a/pkg/sql/colexec2/mergeoffset/offset_test.go
+++ b/pkg/sql/colexec2/mergeoffset/offset_test.go
@@ -20,14 +20,14 @@ import (
 	"strconv"
 	"testing"
 
-	"github.com/matrixorigin/matrixone/pkg/container/batch"
+	batch "github.com/matrixorigin/matrixone/pkg/container/batch2"
 	"github.com/matrixorigin/matrixone/pkg/container/types"
 	"github.com/matrixorigin/matrixone/pkg/container/vector"
 	"github.com/matrixorigin/matrixone/pkg/encoding"
 	"github.com/matrixorigin/matrixone/pkg/vm/mheap"
 	"github.com/matrixorigin/matrixone/pkg/vm/mmu/guest"
 	"github.com/matrixorigin/matrixone/pkg/vm/mmu/host"
-	"github.com/matrixorigin/matrixone/pkg/vm/process"
+	process "github.com/matrixorigin/matrixone/pkg/vm/process2"
 	"github.com/stretchr/testify/require"
 )
 
@@ -39,7 +39,6 @@ const (
 // add unit tests for cases
 type offsetTestCase struct {
 	arg    *Argument
-	attrs  []string
 	types  []types.Type
 	proc   *process.Process
 	cancel context.CancelFunc
@@ -73,19 +72,12 @@ func TestPrepare(t *testing.T) {
 }
 
 func TestOffset(t *testing.T) {
-	hm := host.New(1 << 30)
-	gm := guest.New(1<<30, hm)
-	tcs = []offsetTestCase{
-		newTestCase(mheap.New(gm), 8),
-		newTestCase(mheap.New(gm), 10),
-		newTestCase(mheap.New(gm), 12),
-	}
 	for _, tc := range tcs {
 		Prepare(tc.proc, tc.arg)
-		tc.proc.Reg.MergeReceivers[0].Ch <- newBatch(t, tc.types, tc.attrs, tc.proc)
+		tc.proc.Reg.MergeReceivers[0].Ch <- newBatch(t, tc.types, tc.proc, Rows)
 		tc.proc.Reg.MergeReceivers[0].Ch <- &batch.Batch{}
 		tc.proc.Reg.MergeReceivers[0].Ch <- nil
-		tc.proc.Reg.MergeReceivers[1].Ch <- newBatch(t, tc.types, tc.attrs, tc.proc)
+		tc.proc.Reg.MergeReceivers[1].Ch <- newBatch(t, tc.types, tc.proc, Rows)
 		tc.proc.Reg.MergeReceivers[1].Ch <- &batch.Batch{}
 		tc.proc.Reg.MergeReceivers[1].Ch <- nil
 		for {
@@ -97,29 +89,30 @@ func TestOffset(t *testing.T) {
 }
 
 func BenchmarkOffset(b *testing.B) {
-	hm := host.New(1 << 30)
-	gm := guest.New(1<<30, hm)
-	tcs = []offsetTestCase{
-		newTestCase(mheap.New(gm), 8),
-		newTestCase(mheap.New(gm), 10),
-		newTestCase(mheap.New(gm), 12),
-	}
+	for i := 0; i < b.N; i++ {
+		hm := host.New(1 << 30)
+		gm := guest.New(1<<30, hm)
+		tcs = []offsetTestCase{
+			newTestCase(mheap.New(gm), 8),
+			newTestCase(mheap.New(gm), 10),
+			newTestCase(mheap.New(gm), 12),
+		}
 
-	t := new(testing.T)
-	for _, tc := range tcs {
-		Prepare(tc.proc, tc.arg)
-		tc.proc.Reg.MergeReceivers[0].Ch <- newBatch(t, tc.types, tc.attrs, tc.proc)
-		tc.proc.Reg.MergeReceivers[0].Ch <- &batch.Batch{}
-		tc.proc.Reg.MergeReceivers[0].Ch <- nil
-		tc.proc.Reg.MergeReceivers[1].Ch <- newBatch(t, tc.types, tc.attrs, tc.proc)
-		tc.proc.Reg.MergeReceivers[1].Ch <- &batch.Batch{}
-		tc.proc.Reg.MergeReceivers[1].Ch <- nil
-		for {
-			if ok, err := Call(tc.proc, tc.arg); ok || err != nil {
-				break
+		t := new(testing.T)
+		for _, tc := range tcs {
+			Prepare(tc.proc, tc.arg)
+			tc.proc.Reg.MergeReceivers[0].Ch <- newBatch(t, tc.types, tc.proc, BenchmarkRows)
+			tc.proc.Reg.MergeReceivers[0].Ch <- &batch.Batch{}
+			tc.proc.Reg.MergeReceivers[0].Ch <- nil
+			tc.proc.Reg.MergeReceivers[1].Ch <- newBatch(t, tc.types, tc.proc, BenchmarkRows)
+			tc.proc.Reg.MergeReceivers[1].Ch <- &batch.Batch{}
+			tc.proc.Reg.MergeReceivers[1].Ch <- nil
+			for {
+				if ok, err := Call(tc.proc, tc.arg); ok || err != nil {
+					break
+				}
 			}
 		}
-
 	}
 }
 
@@ -136,8 +129,7 @@ func newTestCase(m *mheap.Mheap, offset uint64) offsetTestCase {
 		Ch:  make(chan *batch.Batch, 3),
 	}
 	return offsetTestCase{
-		proc:  proc,
-		attrs: []string{"1"},
+		proc: proc,
 		types: []types.Type{
 			{Oid: types.T_int8},
 		},
@@ -148,56 +140,52 @@ func newTestCase(m *mheap.Mheap, offset uint64) offsetTestCase {
 	}
 }
 
-// create a new block based on the attribute information, flg indicates if the data is all duplicated
-func newBatch(t *testing.T, ts []types.Type, attrs []string, proc *process.Process) *batch.Batch {
-	bat := batch.New(true, attrs)
-	bat.Zs = make([]int64, Rows)
-	bat.Ht = []*vector.Vector{}
-	for i := range bat.Zs {
-		bat.Zs[i] = 1
-	}
+// create a new block based on the type information
+func newBatch(t *testing.T, ts []types.Type, proc *process.Process, rows int64) *batch.Batch {
+	bat := batch.New(len(ts))
+	bat.InitZsOne(int(rows))
 	for i := range bat.Vecs {
 		vec := vector.New(ts[i])
 		switch vec.Typ.Oid {
 		case types.T_int8:
-			data, err := mheap.Alloc(proc.Mp, Rows*1)
+			data, err := mheap.Alloc(proc.Mp, rows*1)
 			require.NoError(t, err)
 			vec.Data = data
-			vs := encoding.DecodeInt8Slice(vec.Data)[:Rows]
+			vs := encoding.DecodeInt8Slice(vec.Data)[:rows]
 			for i := range vs {
 				vs[i] = int8(i)
 			}
 			vec.Col = vs
 		case types.T_int64:
-			data, err := mheap.Alloc(proc.Mp, Rows*8)
+			data, err := mheap.Alloc(proc.Mp, rows*8)
 			require.NoError(t, err)
 			vec.Data = data
-			vs := encoding.DecodeInt64Slice(vec.Data)[:Rows]
+			vs := encoding.DecodeInt64Slice(vec.Data)[:rows]
 			for i := range vs {
 				vs[i] = int64(i)
 			}
 			vec.Col = vs
 		case types.T_float64:
-			data, err := mheap.Alloc(proc.Mp, Rows*8)
+			data, err := mheap.Alloc(proc.Mp, rows*8)
 			require.NoError(t, err)
 			vec.Data = data
-			vs := encoding.DecodeFloat64Slice(vec.Data)[:Rows]
+			vs := encoding.DecodeFloat64Slice(vec.Data)[:rows]
 			for i := range vs {
 				vs[i] = float64(i)
 			}
 			vec.Col = vs
 		case types.T_date:
-			data, err := mheap.Alloc(proc.Mp, Rows*4)
+			data, err := mheap.Alloc(proc.Mp, rows*4)
 			require.NoError(t, err)
 			vec.Data = data
-			vs := encoding.DecodeDateSlice(vec.Data)[:Rows]
+			vs := encoding.DecodeDateSlice(vec.Data)[:rows]
 			for i := range vs {
 				vs[i] = types.Date(i)
 			}
 			vec.Col = vs
 		case types.T_char, types.T_varchar:
 			size := 0
-			vs := make([][]byte, Rows)
+			vs := make([][]byte, rows)
 			for i := range vs {
 				vs[i] = []byte(strconv.Itoa(i))
 				size += len(vs[i])
diff --git a/pkg/sql/colexec2/mergeorder/order.go b/pkg/sql/colexec2/mergeorder/order.go
new file mode 100644
index 0000000000000000000000000000000000000000..ea19e90cdf7ff7c86b393d645432dba845533abb
--- /dev/null
+++ b/pkg/sql/colexec2/mergeorder/order.go
@@ -0,0 +1,197 @@
+// Copyright 2021 Matrix Origin
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package mergeorder
+
+import (
+	"bytes"
+	"fmt"
+
+	compare "github.com/matrixorigin/matrixone/pkg/compare2"
+	batch "github.com/matrixorigin/matrixone/pkg/container/batch2"
+	"github.com/matrixorigin/matrixone/pkg/container/vector"
+	order "github.com/matrixorigin/matrixone/pkg/sql/colexec2/order"
+	process "github.com/matrixorigin/matrixone/pkg/vm/process2"
+)
+
+func String(arg interface{}, buf *bytes.Buffer) {
+	n := arg.(*Argument)
+	buf.WriteString("Ï„([")
+	for i, f := range n.Fs {
+		if i > 0 {
+			buf.WriteString(", ")
+		}
+		buf.WriteString(f.String())
+	}
+	buf.WriteString(fmt.Sprintf("])"))
+}
+
+func Prepare(_ *process.Process, arg interface{}) error {
+	n := arg.(*Argument)
+	n.ctr = new(Container)
+	{
+		n.ctr.poses = make([]int32, len(n.Fs))
+		for i, f := range n.Fs {
+			n.ctr.poses[i] = f.Pos
+		}
+	}
+	n.ctr.cmps = make([]compare.Compare, len(n.Fs))
+	return nil
+}
+
+func Call(proc *process.Process, arg interface{}) (bool, error) {
+	n := arg.(*Argument)
+	ctr := n.ctr
+	for {
+		switch ctr.state {
+		case Build:
+			if err := ctr.build(n, proc); err != nil {
+				ctr.state = End
+				return true, err
+			}
+			ctr.state = Eval
+		case Eval:
+			proc.Reg.InputBatch = ctr.bat
+			ctr.bat = nil
+			ctr.state = End
+			return true, nil
+		default:
+			proc.Reg.InputBatch = nil
+			return true, nil
+		}
+	}
+
+}
+
+func (ctr *Container) build(n *Argument, proc *process.Process) error {
+	for {
+		if len(proc.Reg.MergeReceivers) == 0 {
+			break
+		}
+		for i := 0; i < len(proc.Reg.MergeReceivers); i++ {
+			reg := proc.Reg.MergeReceivers[i]
+			bat := <-reg.Ch
+			if bat == nil {
+				proc.Reg.MergeReceivers = append(proc.Reg.MergeReceivers[:i], proc.Reg.MergeReceivers[i+1:]...)
+				i--
+				continue
+			}
+			if len(bat.Zs) == 0 {
+				i--
+				continue
+			}
+			if ctr.bat == nil {
+				batch.Reorder(bat, ctr.poses)
+				ctr.bat = bat
+				for i, f := range n.Fs {
+					ctr.cmps[i] = compare.New(bat.Vecs[i].Typ.Oid, f.Type == order.Descending)
+				}
+				for i := len(n.Fs); i < len(bat.Vecs); i++ {
+					ctr.cmps = append(ctr.cmps, compare.New(bat.Vecs[i].Typ.Oid, true))
+				}
+			} else {
+				batch.Reorder(bat, ctr.poses)
+				if err := ctr.processBatch(bat, proc); err != nil {
+					batch.Clean(bat, proc.Mp)
+					batch.Clean(ctr.bat, proc.Mp)
+					return err
+				}
+				batch.Clean(bat, proc.Mp)
+			}
+		}
+	}
+	return nil
+}
+
+func (ctr *Container) processBatch(bat2 *batch.Batch, proc *process.Process) error {
+	bat1 := ctr.bat
+	rbat := batch.New(len(bat1.Vecs))
+	for i, vec := range bat1.Vecs {
+		rbat.Vecs[i] = vector.New(vec.Typ)
+	}
+	for i, cmp := range ctr.cmps {
+		cmp.Set(0, batch.GetVector(bat1, int32(i)))
+		cmp.Set(1, batch.GetVector(bat2, int32(i)))
+	}
+	// init index-number for merge-sort
+	i, j := int64(0), int64(0)
+	l1, l2 := int64(vector.Length(bat1.Vecs[0])), int64(vector.Length(bat2.Vecs[0]))
+
+	// do merge-sort work
+	for i < l1 && j < l2 {
+		compareResult := 0
+		for k := range ctr.cmps {
+			compareResult = ctr.cmps[k].Compare(0, 1, i, j)
+			if compareResult != 0 {
+				break
+			}
+		}
+		if compareResult <= 0 { // Weight of item1 is less than or equal to item2
+			for k := 0; k < len(rbat.Vecs); k++ {
+				err := vector.UnionOne(rbat.Vecs[k], bat1.Vecs[k], i, proc.Mp)
+				if err != nil {
+					batch.Clean(rbat, proc.Mp)
+					return err
+				}
+			}
+			rbat.Zs = append(rbat.Zs, bat1.Zs[i])
+			i++
+		} else {
+			for k := 0; k < len(rbat.Vecs); k++ {
+				err := vector.UnionOne(rbat.Vecs[k], bat2.Vecs[k], j, proc.Mp)
+				if err != nil {
+					batch.Clean(rbat, proc.Mp)
+					return err
+				}
+			}
+			rbat.Zs = append(rbat.Zs, bat2.Zs[j])
+			j++
+		}
+	}
+	if i < l1 {
+		count := int(l1 - i)
+		// union all bat1 from i to l1
+		for k := 0; k < len(rbat.Vecs); k++ {
+			err := vector.UnionBatch(rbat.Vecs[k], bat1.Vecs[k], i, count, makeFlagsOne(count), proc.Mp)
+			if err != nil {
+				batch.Clean(rbat, proc.Mp)
+				return err
+			}
+		}
+		rbat.Zs = append(rbat.Zs, bat1.Zs[i:]...)
+	}
+	if j < l2 {
+		count := int(l2 - j)
+		// union all bat2 from j to l2
+		for k := 0; k < len(rbat.Vecs); k++ {
+			err := vector.UnionBatch(rbat.Vecs[k], bat2.Vecs[k], j, count, makeFlagsOne(count), proc.Mp)
+			if err != nil {
+				batch.Clean(rbat, proc.Mp)
+				return err
+			}
+		}
+		rbat.Zs = append(rbat.Zs, bat2.Zs[j:]...)
+	}
+	batch.Clean(ctr.bat, proc.Mp)
+	ctr.bat = rbat
+	return nil
+}
+
+func makeFlagsOne(n int) []uint8 {
+	t := make([]uint8, n)
+	for i := range t {
+		t[i]++
+	}
+	return t
+}
diff --git a/pkg/sql/colexec2/mergeorder/order_test.go b/pkg/sql/colexec2/mergeorder/order_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..d15b8731bad9ea032cd942efc3f43b83115b5d29
--- /dev/null
+++ b/pkg/sql/colexec2/mergeorder/order_test.go
@@ -0,0 +1,185 @@
+// Copyright 2021 Matrix Origin
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package mergeorder
+
+import (
+	"bytes"
+	"context"
+	"testing"
+
+	batch "github.com/matrixorigin/matrixone/pkg/container/batch2"
+	"github.com/matrixorigin/matrixone/pkg/container/types"
+	"github.com/matrixorigin/matrixone/pkg/container/vector"
+	"github.com/matrixorigin/matrixone/pkg/encoding"
+	order "github.com/matrixorigin/matrixone/pkg/sql/colexec2/order"
+	"github.com/matrixorigin/matrixone/pkg/vm/mheap"
+	"github.com/matrixorigin/matrixone/pkg/vm/mmu/guest"
+	"github.com/matrixorigin/matrixone/pkg/vm/mmu/host"
+	process "github.com/matrixorigin/matrixone/pkg/vm/process2"
+	"github.com/stretchr/testify/require"
+)
+
+const (
+	Rows          = 10     // default rows
+	BenchmarkRows = 100000 // default rows for benchmark
+)
+
+// add unit tests for cases
+type orderTestCase struct {
+	ds     []bool // Directions, ds[i] == true: the attrs[i] are in descending order
+	arg    *Argument
+	types  []types.Type
+	proc   *process.Process
+	cancel context.CancelFunc
+}
+
+var (
+	tcs []orderTestCase
+)
+
+func init() {
+	hm := host.New(1 << 30)
+	gm := guest.New(1<<30, hm)
+	tcs = []orderTestCase{
+		newTestCase(mheap.New(gm), []bool{false}, []types.Type{{Oid: types.T_int8}}, []order.Field{{Pos: 0, Type: 0}}),
+		newTestCase(mheap.New(gm), []bool{true}, []types.Type{{Oid: types.T_int8}}, []order.Field{{Pos: 0, Type: 2}}),
+		newTestCase(mheap.New(gm), []bool{false, false}, []types.Type{{Oid: types.T_int8}, {Oid: types.T_int64}}, []order.Field{{Pos: 1, Type: 0}}),
+		newTestCase(mheap.New(gm), []bool{true, false}, []types.Type{{Oid: types.T_int8}, {Oid: types.T_int64}}, []order.Field{{Pos: 0, Type: 2}}),
+		newTestCase(mheap.New(gm), []bool{true, false}, []types.Type{{Oid: types.T_int8}, {Oid: types.T_int64}}, []order.Field{{Pos: 0, Type: 2}, {Pos: 1, Type: 0}}),
+	}
+}
+
+func TestString(t *testing.T) {
+	buf := new(bytes.Buffer)
+	for _, tc := range tcs {
+		String(tc.arg, buf)
+	}
+}
+
+func TestPrepare(t *testing.T) {
+	for _, tc := range tcs {
+		Prepare(tc.proc, tc.arg)
+	}
+}
+
+func TestOrder(t *testing.T) {
+	for _, tc := range tcs {
+		Prepare(tc.proc, tc.arg)
+		tc.proc.Reg.MergeReceivers[0].Ch <- newBatch(t, tc.ds, tc.types, tc.proc, Rows)
+		tc.proc.Reg.MergeReceivers[0].Ch <- &batch.Batch{}
+		tc.proc.Reg.MergeReceivers[0].Ch <- nil
+		tc.proc.Reg.MergeReceivers[1].Ch <- newBatch(t, tc.ds, tc.types, tc.proc, Rows)
+		tc.proc.Reg.MergeReceivers[1].Ch <- &batch.Batch{}
+		tc.proc.Reg.MergeReceivers[1].Ch <- nil
+		for {
+			if ok, err := Call(tc.proc, tc.arg); ok || err != nil {
+				break
+			}
+		}
+	}
+}
+
+func BenchmarkOrder(b *testing.B) {
+	for i := 0; i < b.N; i++ {
+		hm := host.New(1 << 30)
+		gm := guest.New(1<<30, hm)
+		tcs = []orderTestCase{
+			newTestCase(mheap.New(gm), []bool{false}, []types.Type{{Oid: types.T_int8}}, []order.Field{{Pos: 0, Type: 0}}),
+			newTestCase(mheap.New(gm), []bool{true}, []types.Type{{Oid: types.T_int8}}, []order.Field{{Pos: 0, Type: 2}}),
+		}
+		t := new(testing.T)
+		for _, tc := range tcs {
+			Prepare(tc.proc, tc.arg)
+			tc.proc.Reg.MergeReceivers[0].Ch <- newBatch(t, tc.ds, tc.types, tc.proc, BenchmarkRows)
+			tc.proc.Reg.MergeReceivers[0].Ch <- &batch.Batch{}
+			tc.proc.Reg.MergeReceivers[0].Ch <- nil
+			tc.proc.Reg.MergeReceivers[1].Ch <- newBatch(t, tc.ds, tc.types, tc.proc, BenchmarkRows)
+			tc.proc.Reg.MergeReceivers[1].Ch <- &batch.Batch{}
+			tc.proc.Reg.MergeReceivers[1].Ch <- nil
+			for {
+				if ok, err := Call(tc.proc, tc.arg); ok || err != nil {
+					break
+				}
+			}
+		}
+	}
+}
+
+func newTestCase(m *mheap.Mheap, ds []bool, ts []types.Type, fs []order.Field) orderTestCase {
+	proc := process.New(m)
+	proc.Reg.MergeReceivers = make([]*process.WaitRegister, 2)
+	ctx, cancel := context.WithCancel(context.Background())
+	proc.Reg.MergeReceivers[0] = &process.WaitRegister{
+		Ctx: ctx,
+		Ch:  make(chan *batch.Batch, 3),
+	}
+	proc.Reg.MergeReceivers[1] = &process.WaitRegister{
+		Ctx: ctx,
+		Ch:  make(chan *batch.Batch, 3),
+	}
+	return orderTestCase{
+		ds:    ds,
+		types: ts,
+		proc:  proc,
+		arg: &Argument{
+			Fs: fs,
+		},
+		cancel: cancel,
+	}
+}
+
+// create a new block based on the type information, ds[i] == true: in descending order
+func newBatch(t *testing.T, ds []bool, ts []types.Type, proc *process.Process, rows int64) *batch.Batch {
+	bat := batch.New(len(ts))
+	bat.InitZsOne(int(rows))
+	for i := range bat.Vecs {
+		flg := ds[i]
+		vec := vector.New(ts[i])
+		switch vec.Typ.Oid {
+		case types.T_int8:
+			data, err := mheap.Alloc(proc.Mp, rows*1)
+			require.NoError(t, err)
+			vec.Data = data
+			vs := encoding.DecodeInt8Slice(vec.Data)[:rows]
+			if flg {
+				for i := range vs {
+					vs[i] = int8(rows) - int8(i) - 1
+				}
+			} else {
+				for i := range vs {
+					vs[i] = int8(i)
+				}
+			}
+			vec.Col = vs
+		case types.T_int64:
+			data, err := mheap.Alloc(proc.Mp, rows*8)
+			require.NoError(t, err)
+			vec.Data = data
+			vs := encoding.DecodeInt64Slice(vec.Data)[:rows]
+			if flg {
+				for i := range vs {
+					vs[i] = int64(rows) - int64(i) - 1
+				}
+			} else {
+				for i := range vs {
+					vs[i] = int64(i)
+				}
+			}
+			vec.Col = vs
+		}
+		bat.Vecs[i] = vec
+	}
+	return bat
+}
diff --git a/pkg/sql/colexec2/mergeorder/types.go b/pkg/sql/colexec2/mergeorder/types.go
new file mode 100644
index 0000000000000000000000000000000000000000..89ae4304662636560e35ed03ddb499c06f558e48
--- /dev/null
+++ b/pkg/sql/colexec2/mergeorder/types.go
@@ -0,0 +1,40 @@
+// Copyright 2021 Matrix Origin
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package mergeorder
+
+import (
+	compare "github.com/matrixorigin/matrixone/pkg/compare2"
+	batch "github.com/matrixorigin/matrixone/pkg/container/batch2"
+	order "github.com/matrixorigin/matrixone/pkg/sql/colexec2/order"
+)
+
+const (
+	Build = iota
+	Eval
+	End
+)
+
+type Container struct {
+	state int
+	poses []int32           // sorted list of attributes
+	cmps  []compare.Compare // compare structures used to do sort work for attrs
+
+	bat *batch.Batch // bat store the result of merge-order
+}
+
+type Argument struct {
+	Fs  []order.Field // Fields store the order information
+	ctr *Container    // ctr stores the attributes needn't do Serialization work
+}
diff --git a/pkg/sql/colexec2/mergetop/top.go b/pkg/sql/colexec2/mergetop/top.go
new file mode 100644
index 0000000000000000000000000000000000000000..7805c59a44513dc6cc9ac872a0b019a3514ee384
--- /dev/null
+++ b/pkg/sql/colexec2/mergetop/top.go
@@ -0,0 +1,190 @@
+// Copyright 2021 Matrix Origin
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package mergetop
+
+import (
+	"bytes"
+	"container/heap"
+	"fmt"
+
+	compare "github.com/matrixorigin/matrixone/pkg/compare2"
+	batch "github.com/matrixorigin/matrixone/pkg/container/batch2"
+	"github.com/matrixorigin/matrixone/pkg/container/vector"
+	top "github.com/matrixorigin/matrixone/pkg/sql/colexec2/top"
+	process "github.com/matrixorigin/matrixone/pkg/vm/process2"
+)
+
+func String(arg interface{}, buf *bytes.Buffer) {
+	n := arg.(*Argument)
+	buf.WriteString("Ï„([")
+	for i, f := range n.Fs {
+		if i > 0 {
+			buf.WriteString(", ")
+		}
+		buf.WriteString(f.String())
+	}
+	buf.WriteString(fmt.Sprintf("], %v)", n.Limit))
+}
+
+func Prepare(_ *process.Process, arg interface{}) error {
+	n := arg.(*Argument)
+	n.ctr = new(Container)
+	{
+		n.ctr.poses = make([]int32, len(n.Fs))
+		for i, f := range n.Fs {
+			n.ctr.poses[i] = f.Pos
+		}
+	}
+	n.ctr.n = len(n.Fs)
+	n.ctr.sels = make([]int64, 0, n.Limit)
+	n.ctr.cmps = make([]compare.Compare, len(n.Fs))
+	return nil
+}
+
+func Call(proc *process.Process, arg interface{}) (bool, error) {
+	n := arg.(*Argument)
+	ctr := n.ctr
+	for {
+		switch ctr.state {
+		case Build:
+			if err := ctr.build(n, proc); err != nil {
+				ctr.state = End
+				return true, err
+			}
+			ctr.state = Eval
+		case Eval:
+			ctr.state = End
+			return true, ctr.eval(n.Limit, proc)
+		default:
+			proc.Reg.InputBatch = nil
+			return true, nil
+		}
+	}
+}
+
+func (ctr *Container) build(n *Argument, proc *process.Process) error {
+	for {
+		if len(proc.Reg.MergeReceivers) == 0 {
+			break
+		}
+		for i := 0; i < len(proc.Reg.MergeReceivers); i++ {
+			reg := proc.Reg.MergeReceivers[i]
+			bat := <-reg.Ch
+			if bat == nil {
+				proc.Reg.MergeReceivers = append(proc.Reg.MergeReceivers[:i], proc.Reg.MergeReceivers[i+1:]...)
+				i--
+				continue
+			}
+			if len(bat.Zs) == 0 {
+				i--
+				continue
+			}
+			if ctr.bat == nil {
+				batch.Reorder(bat, ctr.poses)
+				ctr.bat = batch.New(len(bat.Vecs))
+				for i, vec := range bat.Vecs {
+					ctr.bat.Vecs[i] = vector.New(vec.Typ)
+				}
+				for i, f := range n.Fs {
+					ctr.cmps[i] = compare.New(bat.Vecs[i].Typ.Oid, f.Type == top.Descending)
+				}
+				for i := len(n.Fs); i < len(bat.Vecs); i++ {
+					ctr.cmps = append(ctr.cmps, compare.New(bat.Vecs[i].Typ.Oid, true))
+				}
+			} else {
+				batch.Reorder(bat, ctr.poses)
+			}
+			if err := ctr.processBatch(n.Limit, bat, proc); err != nil {
+				batch.Clean(bat, proc.Mp)
+				return err
+			}
+			batch.Clean(bat, proc.Mp)
+		}
+	}
+	return nil
+}
+
+func (ctr *Container) processBatch(limit int64, bat *batch.Batch, proc *process.Process) error {
+	var start int64
+
+	length := int64(len(bat.Zs))
+	if n := int64(len(ctr.sels)); n < limit {
+		start = limit - n
+		if start > length {
+			start = length
+		}
+		for i := int64(0); i < start; i++ {
+			for j, vec := range ctr.bat.Vecs {
+				if err := vector.UnionOne(vec, bat.Vecs[j], i, proc.Mp); err != nil {
+					return err
+				}
+			}
+			ctr.sels = append(ctr.sels, n)
+			ctr.bat.Zs = append(ctr.bat.Zs, bat.Zs[i])
+			n++
+		}
+		if n == limit {
+			ctr.sort()
+		}
+	}
+	if start == length {
+		return nil
+	}
+
+	// bat is still have items
+	for i, cmp := range ctr.cmps {
+		cmp.Set(1, bat.Vecs[i])
+	}
+	for i, j := start, length; i < j; i++ {
+		if ctr.compare(1, 0, i, ctr.sels[0]) < 0 {
+			for _, cmp := range ctr.cmps {
+				if err := cmp.Copy(1, 0, i, ctr.sels[0], proc); err != nil {
+					return err
+				}
+				ctr.bat.Zs[0] = bat.Zs[i]
+			}
+			heap.Fix(ctr, 0)
+		}
+	}
+	return nil
+}
+
+func (ctr *Container) eval(limit int64, proc *process.Process) error {
+	if int64(len(ctr.sels)) < limit {
+		ctr.sort()
+	}
+	for i, cmp := range ctr.cmps {
+		ctr.bat.Vecs[i] = cmp.Vector()
+	}
+	sels := make([]int64, len(ctr.sels))
+	for i, j := 0, len(ctr.sels); i < j; i++ {
+		sels[len(sels)-1-i] = heap.Pop(ctr).(int64)
+	}
+	if err := batch.Shuffle(ctr.bat, sels, proc.Mp); err != nil {
+		batch.Clean(ctr.bat, proc.Mp)
+		ctr.bat = nil
+	}
+	proc.Reg.InputBatch = ctr.bat
+	ctr.bat = nil
+	return nil
+}
+
+// do sort work for heap, and result order will be set in container.sels
+func (ctr *Container) sort() {
+	for i, cmp := range ctr.cmps {
+		cmp.Set(0, ctr.bat.Vecs[i])
+	}
+	heap.Init(ctr)
+}
diff --git a/pkg/sql/colexec2/mergetop/top_test.go b/pkg/sql/colexec2/mergetop/top_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..8f3f6bcde2fe94ebc7563090ed16a58ff829e611
--- /dev/null
+++ b/pkg/sql/colexec2/mergetop/top_test.go
@@ -0,0 +1,187 @@
+// Copyright 2021 Matrix Origin
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package mergetop
+
+import (
+	"bytes"
+	"context"
+	"testing"
+
+	batch "github.com/matrixorigin/matrixone/pkg/container/batch2"
+	"github.com/matrixorigin/matrixone/pkg/container/types"
+	"github.com/matrixorigin/matrixone/pkg/container/vector"
+	"github.com/matrixorigin/matrixone/pkg/encoding"
+	top "github.com/matrixorigin/matrixone/pkg/sql/colexec2/top"
+	"github.com/matrixorigin/matrixone/pkg/vm/mheap"
+	"github.com/matrixorigin/matrixone/pkg/vm/mmu/guest"
+	"github.com/matrixorigin/matrixone/pkg/vm/mmu/host"
+	process "github.com/matrixorigin/matrixone/pkg/vm/process2"
+	"github.com/stretchr/testify/require"
+)
+
+const (
+	Rows          = 10     // default rows
+	BenchmarkRows = 100000 // default rows for benchmark
+)
+
+// add unit tests for cases
+type topTestCase struct {
+	ds     []bool // Directions, ds[i] == true: the attrs[i] are in descending order
+	arg    *Argument
+	types  []types.Type
+	proc   *process.Process
+	cancel context.CancelFunc
+}
+
+var (
+	tcs []topTestCase
+)
+
+func init() {
+	hm := host.New(1 << 30)
+	gm := guest.New(1<<30, hm)
+	tcs = []topTestCase{
+		newTestCase(mheap.New(gm), []bool{false}, []types.Type{{Oid: types.T_int8}}, 3, []top.Field{{Pos: 0, Type: 0}}),
+		newTestCase(mheap.New(gm), []bool{true}, []types.Type{{Oid: types.T_int8}}, 3, []top.Field{{Pos: 0, Type: 2}}),
+		newTestCase(mheap.New(gm), []bool{false, false}, []types.Type{{Oid: types.T_int8}, {Oid: types.T_int64}}, 3, []top.Field{{Pos: 1, Type: 0}}),
+		newTestCase(mheap.New(gm), []bool{true, false}, []types.Type{{Oid: types.T_int8}, {Oid: types.T_int64}}, 3, []top.Field{{Pos: 0, Type: 2}}),
+		newTestCase(mheap.New(gm), []bool{true, false}, []types.Type{{Oid: types.T_int8}, {Oid: types.T_int64}}, 3, []top.Field{{Pos: 0, Type: 2}, {Pos: 1, Type: 0}}),
+	}
+
+}
+
+func TestString(t *testing.T) {
+	buf := new(bytes.Buffer)
+	for _, tc := range tcs {
+		String(tc.arg, buf)
+	}
+}
+
+func TestPrepare(t *testing.T) {
+	for _, tc := range tcs {
+		Prepare(tc.proc, tc.arg)
+	}
+}
+
+func TestTop(t *testing.T) {
+	for _, tc := range tcs {
+		Prepare(tc.proc, tc.arg)
+		tc.proc.Reg.MergeReceivers[0].Ch <- newBatch(t, tc.ds, tc.types, tc.proc, Rows)
+		tc.proc.Reg.MergeReceivers[0].Ch <- &batch.Batch{}
+		tc.proc.Reg.MergeReceivers[0].Ch <- nil
+		tc.proc.Reg.MergeReceivers[1].Ch <- newBatch(t, tc.ds, tc.types, tc.proc, Rows)
+		tc.proc.Reg.MergeReceivers[1].Ch <- &batch.Batch{}
+		tc.proc.Reg.MergeReceivers[1].Ch <- nil
+		for {
+			if ok, err := Call(tc.proc, tc.arg); ok || err != nil {
+				break
+			}
+		}
+	}
+}
+
+func BenchmarkTop(b *testing.B) {
+	for i := 0; i < b.N; i++ {
+		hm := host.New(1 << 30)
+		gm := guest.New(1<<30, hm)
+		tcs = []topTestCase{
+			newTestCase(mheap.New(gm), []bool{false}, []types.Type{{Oid: types.T_int8}}, 3, []top.Field{{Pos: 0, Type: 0}}),
+			newTestCase(mheap.New(gm), []bool{true}, []types.Type{{Oid: types.T_int8}}, 3, []top.Field{{Pos: 0, Type: 2}}),
+		}
+		t := new(testing.T)
+		for _, tc := range tcs {
+			Prepare(tc.proc, tc.arg)
+			tc.proc.Reg.MergeReceivers[0].Ch <- newBatch(t, tc.ds, tc.types, tc.proc, BenchmarkRows)
+			tc.proc.Reg.MergeReceivers[0].Ch <- &batch.Batch{}
+			tc.proc.Reg.MergeReceivers[0].Ch <- nil
+			tc.proc.Reg.MergeReceivers[1].Ch <- newBatch(t, tc.ds, tc.types, tc.proc, BenchmarkRows)
+			tc.proc.Reg.MergeReceivers[1].Ch <- &batch.Batch{}
+			tc.proc.Reg.MergeReceivers[1].Ch <- nil
+			for {
+				if ok, err := Call(tc.proc, tc.arg); ok || err != nil {
+					break
+				}
+			}
+		}
+	}
+}
+
+func newTestCase(m *mheap.Mheap, ds []bool, ts []types.Type, limit int64, fs []top.Field) topTestCase {
+	proc := process.New(m)
+	proc.Reg.MergeReceivers = make([]*process.WaitRegister, 2)
+	ctx, cancel := context.WithCancel(context.Background())
+	proc.Reg.MergeReceivers[0] = &process.WaitRegister{
+		Ctx: ctx,
+		Ch:  make(chan *batch.Batch, 3),
+	}
+	proc.Reg.MergeReceivers[1] = &process.WaitRegister{
+		Ctx: ctx,
+		Ch:  make(chan *batch.Batch, 3),
+	}
+	return topTestCase{
+		ds:    ds,
+		types: ts,
+		proc:  proc,
+		arg: &Argument{
+			Fs:    fs,
+			Limit: limit,
+		},
+		cancel: cancel,
+	}
+}
+
+// create a new block based on the type information, ds[i] == true: in descending order
+func newBatch(t *testing.T, ds []bool, ts []types.Type, proc *process.Process, rows int64) *batch.Batch {
+	bat := batch.New(len(ts))
+	bat.InitZsOne(int(rows))
+	for i := range bat.Vecs {
+		flg := ds[i]
+		vec := vector.New(ts[i])
+		switch vec.Typ.Oid {
+		case types.T_int8:
+			data, err := mheap.Alloc(proc.Mp, rows*1)
+			require.NoError(t, err)
+			vec.Data = data
+			vs := encoding.DecodeInt8Slice(vec.Data)[:rows]
+			if flg {
+				for i := range vs {
+					vs[i] = int8(rows) - int8(i) - 1
+				}
+			} else {
+				for i := range vs {
+					vs[i] = int8(i)
+				}
+			}
+			vec.Col = vs
+		case types.T_int64:
+			data, err := mheap.Alloc(proc.Mp, rows*8)
+			require.NoError(t, err)
+			vec.Data = data
+			vs := encoding.DecodeInt64Slice(vec.Data)[:rows]
+			if flg {
+				for i := range vs {
+					vs[i] = int64(rows) - int64(i) - 1
+				}
+			} else {
+				for i := range vs {
+					vs[i] = int64(i)
+				}
+			}
+			vec.Col = vs
+		}
+		bat.Vecs[i] = vec
+	}
+	return bat
+}
diff --git a/pkg/sql/colexec2/mergetop/types.go b/pkg/sql/colexec2/mergetop/types.go
new file mode 100644
index 0000000000000000000000000000000000000000..cca00c538033b9904b3368fbf3020511d5a8f9a7
--- /dev/null
+++ b/pkg/sql/colexec2/mergetop/types.go
@@ -0,0 +1,75 @@
+// Copyright 2021 Matrix Origin
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package mergetop
+
+import (
+	compare "github.com/matrixorigin/matrixone/pkg/compare2"
+	batch "github.com/matrixorigin/matrixone/pkg/container/batch2"
+	top "github.com/matrixorigin/matrixone/pkg/sql/colexec2/top"
+)
+
+const (
+	Build = iota
+	Eval
+	End
+)
+
+type Container struct {
+	state int
+	n     int // number of attributes involved in sorting
+	sels  []int64
+	poses []int32           // sorted list of attributes
+	cmps  []compare.Compare // compare structure used to do sort work
+
+	bat *batch.Batch // bat stores the final result of merge-top
+}
+
+type Argument struct {
+	Fs    []top.Field // Fs store the order information
+	Limit int64       // Limit store the number of mergeTop-operator
+	ctr   *Container  // ctr stores the attributes needn't do Serialization work
+}
+
+func (ctr *Container) compare(vi, vj int, i, j int64) int {
+	for k := 0; k < ctr.n; k++ {
+		if r := ctr.cmps[k].Compare(vi, vj, i, j); r != 0 {
+			return r
+		}
+	}
+	return 0
+}
+
+func (ctr *Container) Len() int {
+	return len(ctr.sels)
+}
+
+func (ctr *Container) Less(i, j int) bool {
+	return ctr.compare(0, 0, ctr.sels[i], ctr.sels[j]) > 0
+}
+
+func (ctr *Container) Swap(i, j int) {
+	ctr.sels[i], ctr.sels[j] = ctr.sels[j], ctr.sels[i]
+}
+
+func (ctr *Container) Push(x interface{}) {
+	ctr.sels = append(ctr.sels, x.(int64))
+}
+
+func (ctr *Container) Pop() interface{} {
+	n := len(ctr.sels) - 1
+	x := ctr.sels[n]
+	ctr.sels = ctr.sels[:n]
+	return x
+}
diff --git a/pkg/sql/colexec2/offset/offset.go b/pkg/sql/colexec2/offset/offset.go
index 431f1f1eab36964ef0fb19e1c5de7a1e600f5348..2b40033e4a286622ac0b12ae0ce288818b4b0b51 100644
--- a/pkg/sql/colexec2/offset/offset.go
+++ b/pkg/sql/colexec2/offset/offset.go
@@ -17,10 +17,9 @@ package offset
 import (
 	"bytes"
 	"fmt"
-	"github.com/matrixorigin/matrixone/pkg/container/batch"
-	"github.com/matrixorigin/matrixone/pkg/encoding"
-	"github.com/matrixorigin/matrixone/pkg/vm/mheap"
-	"github.com/matrixorigin/matrixone/pkg/vm/process"
+
+	batch "github.com/matrixorigin/matrixone/pkg/container/batch2"
+	process "github.com/matrixorigin/matrixone/pkg/vm/process2"
 )
 
 func String(arg interface{}, buf *bytes.Buffer) {
@@ -43,14 +42,9 @@ func Call(proc *process.Process, arg interface{}) (bool, error) {
 	}
 	length := len(bat.Zs)
 	if n.Seen+uint64(length) > n.Offset {
-		data, sels, err := newSels(int64(n.Offset-n.Seen), int64(length)-int64(n.Offset-n.Seen), proc.Mp)
-		if err != nil {
-			batch.Clean(bat, proc.Mp)
-			return false, err
-		}
+		sels := newSels(int64(n.Offset-n.Seen), int64(length)-int64(n.Offset-n.Seen))
 		n.Seen += uint64(length)
 		batch.Shrink(bat, sels)
-		mheap.Free(proc.Mp, data)
 		proc.Reg.InputBatch = bat
 		return false, nil
 	}
@@ -60,14 +54,10 @@ func Call(proc *process.Process, arg interface{}) (bool, error) {
 	return false, nil
 }
 
-func newSels(start, count int64, mp *mheap.Mheap) ([]byte, []int64, error) {
-	data, err := mheap.Alloc(mp, count*8)
-	if err != nil {
-		return nil, nil, err
-	}
-	sels := encoding.DecodeInt64Slice(data)
+func newSels(start, count int64) []int64 {
+	sels := make([]int64, count)
 	for i := int64(0); i < count; i++ {
 		sels[i] = start + i
 	}
-	return data, sels[:count], nil
+	return sels[:count]
 }
diff --git a/pkg/sql/colexec2/offset/offset_test.go b/pkg/sql/colexec2/offset/offset_test.go
index e2796578cd29224f1491dc262f65162e7df80b00..88a0469071d402bae45bff46122103854e8b51af 100644
--- a/pkg/sql/colexec2/offset/offset_test.go
+++ b/pkg/sql/colexec2/offset/offset_test.go
@@ -19,14 +19,14 @@ import (
 	"strconv"
 	"testing"
 
-	"github.com/matrixorigin/matrixone/pkg/container/batch"
+	batch "github.com/matrixorigin/matrixone/pkg/container/batch2"
 	"github.com/matrixorigin/matrixone/pkg/container/types"
 	"github.com/matrixorigin/matrixone/pkg/container/vector"
 	"github.com/matrixorigin/matrixone/pkg/encoding"
 	"github.com/matrixorigin/matrixone/pkg/vm/mheap"
 	"github.com/matrixorigin/matrixone/pkg/vm/mmu/guest"
 	"github.com/matrixorigin/matrixone/pkg/vm/mmu/host"
-	"github.com/matrixorigin/matrixone/pkg/vm/process"
+	process "github.com/matrixorigin/matrixone/pkg/vm/process2"
 	"github.com/stretchr/testify/require"
 )
 
@@ -38,7 +38,6 @@ const (
 // add unit tests for cases
 type offsetTestCase struct {
 	arg   *Argument
-	attrs []string
 	types []types.Type
 	proc  *process.Process
 }
@@ -52,8 +51,7 @@ func init() {
 	gm := guest.New(1<<30, hm)
 	tcs = []offsetTestCase{
 		{
-			proc:  process.New(mheap.New(gm)),
-			attrs: []string{"1"},
+			proc: process.New(mheap.New(gm)),
 			types: []types.Type{
 				{Oid: types.T_int8},
 			},
@@ -63,8 +61,7 @@ func init() {
 			},
 		},
 		{
-			proc:  process.New(mheap.New(gm)),
-			attrs: []string{"1"},
+			proc: process.New(mheap.New(gm)),
 			types: []types.Type{
 				{Oid: types.T_int8},
 			},
@@ -74,8 +71,7 @@ func init() {
 			},
 		},
 		{
-			proc:  process.New(mheap.New(gm)),
-			attrs: []string{"1"},
+			proc: process.New(mheap.New(gm)),
 			types: []types.Type{
 				{Oid: types.T_int8},
 			},
@@ -103,9 +99,9 @@ func TestPrepare(t *testing.T) {
 func TestOffset(t *testing.T) {
 	for _, tc := range tcs {
 		Prepare(tc.proc, tc.arg)
-		tc.proc.Reg.InputBatch = newBatch(t, tc.types, tc.attrs, tc.proc)
+		tc.proc.Reg.InputBatch = newBatch(t, tc.types, tc.proc, Rows)
 		Call(tc.proc, tc.arg)
-		tc.proc.Reg.InputBatch = newBatch(t, tc.types, tc.attrs, tc.proc)
+		tc.proc.Reg.InputBatch = newBatch(t, tc.types, tc.proc, Rows)
 		Call(tc.proc, tc.arg)
 		tc.proc.Reg.InputBatch = &batch.Batch{}
 		Call(tc.proc, tc.arg)
@@ -115,84 +111,81 @@ func TestOffset(t *testing.T) {
 }
 
 func BenchmarkLimit(b *testing.B) {
-	hm := host.New(1 << 30)
-	gm := guest.New(1<<30, hm)
-	tcs = []offsetTestCase{
-		{
-			proc:  process.New(mheap.New(gm)),
-			attrs: []string{"1"},
-			types: []types.Type{
-				{Oid: types.T_int8},
+	for i := 0; i < b.N; i++ {
+		hm := host.New(1 << 30)
+		gm := guest.New(1<<30, hm)
+		tcs = []offsetTestCase{
+			{
+				proc: process.New(mheap.New(gm)),
+				types: []types.Type{
+					{Oid: types.T_int8},
+				},
+				arg: &Argument{
+					Seen:   0,
+					Offset: 8,
+				},
 			},
-			arg: &Argument{
-				Seen:   0,
-				Offset: 8,
-			},
-		},
-	}
+		}
 
-	t := new(testing.T)
-	for _, tc := range tcs {
-		Prepare(tc.proc, tc.arg)
-		tc.proc.Reg.InputBatch = newBatch(t, tc.types, tc.attrs, tc.proc)
-		Call(tc.proc, tc.arg)
-		tc.proc.Reg.InputBatch = &batch.Batch{}
-		Call(tc.proc, tc.arg)
-		tc.proc.Reg.InputBatch = nil
-		Call(tc.proc, tc.arg)
+		t := new(testing.T)
+		for _, tc := range tcs {
+			Prepare(tc.proc, tc.arg)
+			tc.proc.Reg.InputBatch = newBatch(t, tc.types, tc.proc, BenchmarkRows)
+			Call(tc.proc, tc.arg)
+			tc.proc.Reg.InputBatch = &batch.Batch{}
+			Call(tc.proc, tc.arg)
+			tc.proc.Reg.InputBatch = nil
+			Call(tc.proc, tc.arg)
+		}
 	}
 }
 
-// create a new block based on the attribute information, flg indicates if the data is all duplicated
-func newBatch(t *testing.T, ts []types.Type, attrs []string, proc *process.Process) *batch.Batch {
-	bat := batch.New(true, attrs)
-	bat.Zs = make([]int64, Rows)
-	bat.Ht = []*vector.Vector{}
-	for i := range bat.Zs {
-		bat.Zs[i] = 1
-	}
+// create a new block based on the type information
+func newBatch(t *testing.T, ts []types.Type, proc *process.Process, rows int64) *batch.Batch {
+	bat := batch.New(len(ts))
+	bat.InitZsOne(int(rows))
 	for i := range bat.Vecs {
 		vec := vector.New(ts[i])
 		switch vec.Typ.Oid {
 		case types.T_int8:
-			data, err := mheap.Alloc(proc.Mp, Rows*1)
+			data, err := mheap.Alloc(proc.Mp, rows*1)
 			require.NoError(t, err)
 			vec.Data = data
-			vs := encoding.DecodeInt8Slice(vec.Data)[:Rows]
+			vs := encoding.DecodeInt8Slice(vec.Data)[:rows]
 			for i := range vs {
 				vs[i] = int8(i)
 			}
 			vec.Col = vs
 		case types.T_int64:
-			data, err := mheap.Alloc(proc.Mp, Rows*8)
+			data, err := mheap.Alloc(proc.Mp, rows*8)
 			require.NoError(t, err)
 			vec.Data = data
-			vs := encoding.DecodeInt64Slice(vec.Data)[:Rows]
+			vs := encoding.DecodeInt64Slice(vec.Data)[:rows]
 			for i := range vs {
 				vs[i] = int64(i)
 			}
 			vec.Col = vs
 		case types.T_float64:
-			data, err := mheap.Alloc(proc.Mp, Rows*8)
+			data, err := mheap.Alloc(proc.Mp, rows*8)
 			require.NoError(t, err)
 			vec.Data = data
-			vs := encoding.DecodeFloat64Slice(vec.Data)[:Rows]
+			vs := encoding.DecodeFloat64Slice(vec.Data)[:rows]
 			for i := range vs {
 				vs[i] = float64(i)
 			}
 			vec.Col = vs
 		case types.T_date:
-			data, err := mheap.Alloc(proc.Mp, Rows*4)
+			data, err := mheap.Alloc(proc.Mp, rows*4)
 			require.NoError(t, err)
 			vec.Data = data
-			vs := encoding.DecodeDateSlice(vec.Data)[:Rows]
+			vs := encoding.DecodeDateSlice(vec.Data)[:rows]
 			for i := range vs {
 				vs[i] = types.Date(i)
 			}
 			vec.Col = vs
 		case types.T_char, types.T_varchar:
 			size := 0
-			vs := make([][]byte, Rows)
+			vs := make([][]byte, rows)
 			for i := range vs {
 				vs[i] = []byte(strconv.Itoa(i))
 				size += len(vs[i])
diff --git a/pkg/sql/colexec2/order/order.go b/pkg/sql/colexec2/order/order.go
new file mode 100644
index 0000000000000000000000000000000000000000..ccd613517a74d260ccc755c562fcedb0f1a9dbb6
--- /dev/null
+++ b/pkg/sql/colexec2/order/order.go
@@ -0,0 +1,91 @@
+// Copyright 2021 Matrix Origin
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package order
+
+import (
+	"bytes"
+	"fmt"
+
+	batch "github.com/matrixorigin/matrixone/pkg/container/batch2"
+	"github.com/matrixorigin/matrixone/pkg/partition"
+	"github.com/matrixorigin/matrixone/pkg/sort"
+	process "github.com/matrixorigin/matrixone/pkg/vm/process2"
+)
+
+func String(arg interface{}, buf *bytes.Buffer) {
+	n := arg.(*Argument)
+	buf.WriteString("Ï„([")
+	for i, f := range n.Fs {
+		if i > 0 {
+			buf.WriteString(", ")
+		}
+		buf.WriteString(f.String())
+	}
+	buf.WriteString(fmt.Sprintf("])"))
+}
+
+func Prepare(_ *process.Process, arg interface{}) error {
+	n := arg.(*Argument)
+	n.ctr = new(Container)
+	{
+		n.ctr.ds = make([]bool, len(n.Fs))
+		n.ctr.poses = make([]int32, len(n.Fs))
+		for i, f := range n.Fs {
+			n.ctr.poses[i] = f.Pos
+			n.ctr.ds[i] = f.Type == Descending
+		}
+	}
+	return nil
+}
+
+func Call(proc *process.Process, arg interface{}) (bool, error) {
+	bat := proc.Reg.InputBatch
+	if bat == nil || len(bat.Zs) == 0 {
+		return false, nil
+	}
+	n := arg.(*Argument)
+	return n.ctr.process(bat, proc)
+}
+
+func (ctr *Container) process(bat *batch.Batch, proc *process.Process) (bool, error) {
+	ovec := batch.GetVector(bat, ctr.poses[0])
+	n := len(bat.Zs)
+	sels := make([]int64, n)
+	for i := range sels {
+		sels[i] = int64(i)
+	}
+	sort.Sort(ctr.ds[0], sels, ovec)
+	if len(ctr.poses) == 1 {
+		batch.Shuffle(bat, sels, proc.Mp)
+		return false, nil
+	}
+	ps := make([]int64, 0, 16)
+	ds := make([]bool, len(sels))
+	for i, j := 1, len(ctr.poses); i < j; i++ {
+		desc := ctr.ds[i]
+		ps = partition.Partition(sels, ds, ps, ovec)
+		vec := batch.GetVector(bat, ctr.poses[i])
+		for i, j := 0, len(ps); i < j; i++ {
+			if i == j-1 {
+				sort.Sort(desc, sels[ps[i]:], vec)
+			} else {
+				sort.Sort(desc, sels[ps[i]:ps[i+1]], vec)
+			}
+		}
+		ovec = vec
+	}
+	batch.Shuffle(bat, sels, proc.Mp)
+	return false, nil
+}
diff --git a/pkg/sql/colexec2/order/order_test.go b/pkg/sql/colexec2/order/order_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..b3442f125f5f3d9c83aa7991e4499a9765c48df1
--- /dev/null
+++ b/pkg/sql/colexec2/order/order_test.go
@@ -0,0 +1,190 @@
+// Copyright 2021 Matrix Origin
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package order
+
+import (
+	"bytes"
+	"strconv"
+	"testing"
+
+	batch "github.com/matrixorigin/matrixone/pkg/container/batch2"
+	"github.com/matrixorigin/matrixone/pkg/container/types"
+	"github.com/matrixorigin/matrixone/pkg/container/vector"
+	"github.com/matrixorigin/matrixone/pkg/encoding"
+	"github.com/matrixorigin/matrixone/pkg/vm/mheap"
+	"github.com/matrixorigin/matrixone/pkg/vm/mmu/guest"
+	"github.com/matrixorigin/matrixone/pkg/vm/mmu/host"
+	process "github.com/matrixorigin/matrixone/pkg/vm/process2"
+	"github.com/stretchr/testify/require"
+)
+
+const (
+	Rows          = 10     // default rows
+	BenchmarkRows = 100000 // default rows for benchmark
+)
+
+// add unit tests for cases
+type orderTestCase struct {
+	arg   *Argument
+	types []types.Type
+	proc  *process.Process
+}
+
+var (
+	tcs []orderTestCase
+)
+
+func init() {
+	hm := host.New(1 << 30)
+	gm := guest.New(1<<30, hm)
+	tcs = []orderTestCase{
+		newTestCase(mheap.New(gm), []types.Type{{Oid: types.T_int8}}, []Field{{Pos: 0, Type: 0}}),
+		newTestCase(mheap.New(gm), []types.Type{{Oid: types.T_int8}}, []Field{{Pos: 0, Type: 2}}),
+		newTestCase(mheap.New(gm), []types.Type{{Oid: types.T_int8}, {Oid: types.T_int64}}, []Field{{Pos: 0, Type: 0}, {Pos: 1, Type: 0}}),
+		newTestCase(mheap.New(gm), []types.Type{{Oid: types.T_int8}, {Oid: types.T_int64}}, []Field{{Pos: 0, Type: 2}, {Pos: 1, Type: 2}}),
+	}
+}
+
+func TestString(t *testing.T) {
+	buf := new(bytes.Buffer)
+	for _, tc := range tcs {
+		String(tc.arg, buf)
+	}
+}
+
+func TestPrepare(t *testing.T) {
+	for _, tc := range tcs {
+		Prepare(tc.proc, tc.arg)
+	}
+}
+
+func TestOrder(t *testing.T) {
+	for _, tc := range tcs {
+		Prepare(tc.proc, tc.arg)
+		tc.proc.Reg.InputBatch = newBatch(t, tc.types, tc.proc, Rows)
+		Call(tc.proc, tc.arg)
+		tc.proc.Reg.InputBatch = newBatch(t, tc.types, tc.proc, Rows)
+		Call(tc.proc, tc.arg)
+		tc.proc.Reg.InputBatch = &batch.Batch{}
+		Call(tc.proc, tc.arg)
+		tc.proc.Reg.InputBatch = nil
+		Call(tc.proc, tc.arg)
+	}
+}
+
+func BenchmarkOrder(b *testing.B) {
+	for i := 0; i < b.N; i++ {
+		hm := host.New(1 << 30)
+		gm := guest.New(1<<30, hm)
+		tcs = []orderTestCase{
+			newTestCase(mheap.New(gm), []types.Type{{Oid: types.T_int8}}, []Field{{Pos: 0, Type: 0}}),
+			newTestCase(mheap.New(gm), []types.Type{{Oid: types.T_int8}}, []Field{{Pos: 0, Type: 2}}),
+			newTestCase(mheap.New(gm), []types.Type{{Oid: types.T_int8}, {Oid: types.T_int64}}, []Field{{Pos: 0, Type: 0}, {Pos: 1, Type: 0}}),
+			newTestCase(mheap.New(gm), []types.Type{{Oid: types.T_int8}, {Oid: types.T_int64}}, []Field{{Pos: 0, Type: 2}, {Pos: 1, Type: 2}}),
+		}
+		t := new(testing.T)
+		for _, tc := range tcs {
+			Prepare(tc.proc, tc.arg)
+			tc.proc.Reg.InputBatch = newBatch(t, tc.types, tc.proc, BenchmarkRows)
+			Call(tc.proc, tc.arg)
+			tc.proc.Reg.InputBatch = newBatch(t, tc.types, tc.proc, BenchmarkRows)
+			Call(tc.proc, tc.arg)
+			tc.proc.Reg.InputBatch = &batch.Batch{}
+			Call(tc.proc, tc.arg)
+			tc.proc.Reg.InputBatch = nil
+			Call(tc.proc, tc.arg)
+		}
+	}
+}
+
+func newTestCase(m *mheap.Mheap, ts []types.Type, fs []Field) orderTestCase {
+	return orderTestCase{
+		types: ts,
+		proc:  process.New(m),
+		arg: &Argument{
+			Fs: fs,
+		},
+	}
+}
+
+// create a new block based on the type information
+func newBatch(t *testing.T, ts []types.Type, proc *process.Process, rows int64) *batch.Batch {
+	bat := batch.New(len(ts))
+	bat.InitZsOne(int(rows))
+	for i := range bat.Vecs {
+		vec := vector.New(ts[i])
+		switch vec.Typ.Oid {
+		case types.T_int8:
+			data, err := mheap.Alloc(proc.Mp, rows*1)
+			require.NoError(t, err)
+			vec.Data = data
+			vs := encoding.DecodeInt8Slice(vec.Data)[:rows]
+			for i := range vs {
+				vs[i] = int8(i)
+			}
+			vec.Col = vs
+		case types.T_int64:
+			data, err := mheap.Alloc(proc.Mp, rows*8)
+			require.NoError(t, err)
+			vec.Data = data
+			vs := encoding.DecodeInt64Slice(vec.Data)[:rows]
+			for i := range vs {
+				vs[i] = int64(i)
+			}
+			vec.Col = vs
+		case types.T_float64:
+			data, err := mheap.Alloc(proc.Mp, rows*8)
+			require.NoError(t, err)
+			vec.Data = data
+			vs := encoding.DecodeFloat64Slice(vec.Data)[:rows]
+			for i := range vs {
+				vs[i] = float64(i)
+			}
+			vec.Col = vs
+		case types.T_date:
+			data, err := mheap.Alloc(proc.Mp, rows*4)
+			require.NoError(t, err)
+			vec.Data = data
+			vs := encoding.DecodeDateSlice(vec.Data)[:rows]
+			for i := range vs {
+				vs[i] = types.Date(i)
+			}
+			vec.Col = vs
+		case types.T_char, types.T_varchar:
+			size := 0
+			vs := make([][]byte, rows)
+			for i := range vs {
+				vs[i] = []byte(strconv.Itoa(i))
+				size += len(vs[i])
+			}
+			data, err := mheap.Alloc(proc.Mp, int64(size))
+			require.NoError(t, err)
+			data = data[:0]
+			col := new(types.Bytes)
+			o := uint32(0)
+			for _, v := range vs {
+				data = append(data, v...)
+				col.Offsets = append(col.Offsets, o)
+				o += uint32(len(v))
+				col.Lengths = append(col.Lengths, uint32(len(v)))
+			}
+			col.Data = data
+			vec.Col = col
+			vec.Data = data
+		}
+		bat.Vecs[i] = vec
+	}
+	return bat
+}
diff --git a/pkg/sql/colexec2/order/types.go b/pkg/sql/colexec2/order/types.go
new file mode 100644
index 0000000000000000000000000000000000000000..bfb3d923a9ec02378f2d01ea15a1361a3b0f5783
--- /dev/null
+++ b/pkg/sql/colexec2/order/types.go
@@ -0,0 +1,63 @@
+// Copyright 2021 Matrix Origin
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package order
+
+import "fmt"
+
+// Direction for ordering results.
+type Direction int8
+
+// Direction values.
+const (
+	DefaultDirection Direction = iota
+	Ascending
+	Descending
+)
+
+type Container struct {
+	ds    []bool  // ds[i] == true: the attrs[i] are in descending order
+	poses []int32 // sorted list of attributes
+}
+
+type Field struct {
+	Pos  int32
+	Type Direction
+}
+
+type Argument struct {
+	Fs  []Field
+	ctr *Container
+}
+
+var directionName = [...]string{
+	DefaultDirection: "",
+	Ascending:        "ASC",
+	Descending:       "DESC",
+}
+
+func (n Field) String() string {
+	s := fmt.Sprintf("%v", n.Pos)
+	if n.Type != DefaultDirection {
+		s += " " + n.Type.String()
+	}
+	return s
+}
+
+func (i Direction) String() string {
+	if i < 0 || i > Direction(len(directionName)-1) {
+		return fmt.Sprintf("Direction(%d)", i)
+	}
+	return directionName[i]
+}
diff --git a/pkg/sql/colexec2/top/top.go b/pkg/sql/colexec2/top/top.go
new file mode 100644
index 0000000000000000000000000000000000000000..256b1bc50e20a2e39cfb50c6226b9f2070026e4b
--- /dev/null
+++ b/pkg/sql/colexec2/top/top.go
@@ -0,0 +1,174 @@
+// Copyright 2021 Matrix Origin
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package top
+
+import (
+	"bytes"
+	"container/heap"
+	"fmt"
+
+	compare "github.com/matrixorigin/matrixone/pkg/compare2"
+	batch "github.com/matrixorigin/matrixone/pkg/container/batch2"
+	"github.com/matrixorigin/matrixone/pkg/container/vector"
+	process "github.com/matrixorigin/matrixone/pkg/vm/process2"
+)
+
+func String(arg interface{}, buf *bytes.Buffer) {
+	n := arg.(*Argument)
+	buf.WriteString("Ï„([")
+	for i, f := range n.Fs {
+		if i > 0 {
+			buf.WriteString(", ")
+		}
+		buf.WriteString(f.String())
+	}
+	buf.WriteString(fmt.Sprintf("], %v)", n.Limit))
+}
+
+func Prepare(_ *process.Process, arg interface{}) error {
+	n := arg.(*Argument)
+	n.ctr = new(Container)
+	{
+		n.ctr.poses = make([]int32, len(n.Fs))
+		for i, f := range n.Fs {
+			n.ctr.poses[i] = f.Pos
+		}
+	}
+	n.ctr.n = len(n.Fs)
+	n.ctr.sels = make([]int64, 0, n.Limit)
+	n.ctr.cmps = make([]compare.Compare, len(n.Fs))
+	return nil
+}
+
+func Call(proc *process.Process, arg interface{}) (bool, error) {
+	n := arg.(*Argument)
+	ctr := n.ctr
+	for {
+		switch ctr.state {
+		case Build:
+			bat := proc.Reg.InputBatch
+			if bat == nil {
+				ctr.state = Eval
+				continue
+			}
+			if len(bat.Zs) == 0 {
+				return false, nil
+			}
+			return false, ctr.build(n, bat, proc)
+		case Eval:
+			ctr.state = End
+			return true, ctr.eval(n.Limit, proc)
+		default:
+			proc.Reg.InputBatch = nil
+			return true, nil
+		}
+	}
+}
+
+func (ctr *Container) build(n *Argument, bat *batch.Batch, proc *process.Process) error {
+	if ctr.bat == nil {
+		batch.Reorder(bat, ctr.poses)
+		ctr.bat = batch.New(len(bat.Vecs))
+		for i, vec := range bat.Vecs {
+			ctr.bat.Vecs[i] = vector.New(vec.Typ)
+		}
+		for i, f := range n.Fs {
+			ctr.cmps[i] = compare.New(bat.Vecs[i].Typ.Oid, f.Type == Descending)
+		}
+		for i := len(n.Fs); i < len(bat.Vecs); i++ {
+			ctr.cmps = append(ctr.cmps, compare.New(bat.Vecs[i].Typ.Oid, true))
+		}
+	} else {
+		batch.Reorder(bat, ctr.poses)
+	}
+	defer batch.Clean(bat, proc.Mp)
+	proc.Reg.InputBatch = &batch.Batch{}
+	return ctr.processBatch(n.Limit, bat, proc)
+}
+
+func (ctr *Container) processBatch(limit int64, bat *batch.Batch, proc *process.Process) error {
+	var start int64
+
+	length := int64(len(bat.Zs))
+	if n := int64(len(ctr.sels)); n < limit {
+		start = limit - n
+		if start > length {
+			start = length
+		}
+		for i := int64(0); i < start; i++ {
+			for j, vec := range ctr.bat.Vecs {
+				if err := vector.UnionOne(vec, bat.Vecs[j], i, proc.Mp); err != nil {
+					batch.Clean(ctr.bat, proc.Mp)
+					return err
+				}
+			}
+			ctr.sels = append(ctr.sels, n)
+			ctr.bat.Zs = append(ctr.bat.Zs, bat.Zs[i])
+			n++
+		}
+		if n == limit {
+			ctr.sort()
+		}
+	}
+	if start == length {
+		return nil
+	}
+
+	// bat is still have items
+	for i, cmp := range ctr.cmps {
+		cmp.Set(1, bat.Vecs[i])
+	}
+	for i, j := start, length; i < j; i++ {
+		if ctr.compare(1, 0, i, ctr.sels[0]) < 0 {
+			for _, cmp := range ctr.cmps {
+				if err := cmp.Copy(1, 0, i, ctr.sels[0], proc); err != nil {
+					batch.Clean(ctr.bat, proc.Mp)
+					return err
+				}
+				ctr.bat.Zs[0] = bat.Zs[i]
+			}
+			heap.Fix(ctr, 0)
+		}
+	}
+	return nil
+}
+
+func (ctr *Container) eval(limit int64, proc *process.Process) error {
+	if int64(len(ctr.sels)) < limit {
+		ctr.sort()
+	}
+	for i, cmp := range ctr.cmps {
+		ctr.bat.Vecs[i] = cmp.Vector()
+	}
+	sels := make([]int64, len(ctr.sels))
+	for i, j := 0, len(ctr.sels); i < j; i++ {
+		sels[len(sels)-1-i] = heap.Pop(ctr).(int64)
+	}
+	if err := batch.Shuffle(ctr.bat, sels, proc.Mp); err != nil {
+		batch.Clean(ctr.bat, proc.Mp)
+		ctr.bat = nil
+	}
+	proc.Reg.InputBatch = ctr.bat
+	ctr.bat = nil
+	return nil
+}
+
+// do sort work for heap, and result order will be set in container.sels
+func (ctr *Container) sort() {
+	for i, cmp := range ctr.cmps {
+		cmp.Set(0, ctr.bat.Vecs[i])
+	}
+	heap.Init(ctr)
+}
diff --git a/pkg/sql/colexec2/top/top_test.go b/pkg/sql/colexec2/top/top_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..8d91a45e4506feafcf9eae333815ce9ae64c7c99
--- /dev/null
+++ b/pkg/sql/colexec2/top/top_test.go
@@ -0,0 +1,190 @@
+// Copyright 2021 Matrix Origin
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package top
+
+import (
+	"bytes"
+	"strconv"
+	"testing"
+
+	batch "github.com/matrixorigin/matrixone/pkg/container/batch2"
+	"github.com/matrixorigin/matrixone/pkg/container/types"
+	"github.com/matrixorigin/matrixone/pkg/container/vector"
+	"github.com/matrixorigin/matrixone/pkg/encoding"
+	"github.com/matrixorigin/matrixone/pkg/vm/mheap"
+	"github.com/matrixorigin/matrixone/pkg/vm/mmu/guest"
+	"github.com/matrixorigin/matrixone/pkg/vm/mmu/host"
+	process "github.com/matrixorigin/matrixone/pkg/vm/process2"
+	"github.com/stretchr/testify/require"
+)
+
+const (
+	Rows          = 10     // default rows
+	BenchmarkRows = 100000 // default rows for benchmark
+)
+
+// add unit tests for cases
+type topTestCase struct {
+	arg   *Argument
+	types []types.Type
+	proc  *process.Process
+}
+
+var (
+	tcs []topTestCase
+)
+
+func init() {
+	hm := host.New(1 << 30)
+	gm := guest.New(1<<30, hm)
+	tcs = []topTestCase{
+		newTestCase(mheap.New(gm), []types.Type{{Oid: types.T_int8}}, 3, []Field{{Pos: 0, Type: 0}}),
+		newTestCase(mheap.New(gm), []types.Type{{Oid: types.T_int8}}, 3, []Field{{Pos: 0, Type: 2}}),
+		newTestCase(mheap.New(gm), []types.Type{{Oid: types.T_int8}, {Oid: types.T_int64}}, 3, []Field{{Pos: 0, Type: 2}, {Pos: 1, Type: 0}}),
+	}
+}
+
+func TestString(t *testing.T) {
+	buf := new(bytes.Buffer)
+	for _, tc := range tcs {
+		String(tc.arg, buf)
+	}
+}
+
+func TestPrepare(t *testing.T) {
+	for _, tc := range tcs {
+		Prepare(tc.proc, tc.arg)
+	}
+}
+
+func TestTop(t *testing.T) {
+	for _, tc := range tcs {
+		Prepare(tc.proc, tc.arg)
+		tc.proc.Reg.InputBatch = newBatch(t, tc.types, tc.proc, Rows)
+		Call(tc.proc, tc.arg)
+		tc.proc.Reg.InputBatch = newBatch(t, tc.types, tc.proc, Rows)
+		Call(tc.proc, tc.arg)
+		tc.proc.Reg.InputBatch = &batch.Batch{}
+		Call(tc.proc, tc.arg)
+		tc.proc.Reg.InputBatch = nil
+		Call(tc.proc, tc.arg)
+		tc.proc.Reg.InputBatch = nil
+		Call(tc.proc, tc.arg)
+	}
+}
+
+func BenchmarkTop(b *testing.B) {
+	for i := 0; i < b.N; i++ {
+		hm := host.New(1 << 30)
+		gm := guest.New(1<<30, hm)
+		tcs = []topTestCase{
+			newTestCase(mheap.New(gm), []types.Type{{Oid: types.T_int8}}, 3, []Field{{Pos: 0, Type: 0}}),
+			newTestCase(mheap.New(gm), []types.Type{{Oid: types.T_int8}}, 3, []Field{{Pos: 0, Type: 2}}),
+		}
+		t := new(testing.T)
+		for _, tc := range tcs {
+			Prepare(tc.proc, tc.arg)
+			tc.proc.Reg.InputBatch = newBatch(t, tc.types, tc.proc, BenchmarkRows)
+			Call(tc.proc, tc.arg)
+			tc.proc.Reg.InputBatch = newBatch(t, tc.types, tc.proc, BenchmarkRows)
+			Call(tc.proc, tc.arg)
+			tc.proc.Reg.InputBatch = &batch.Batch{}
+			Call(tc.proc, tc.arg)
+			tc.proc.Reg.InputBatch = nil
+			Call(tc.proc, tc.arg)
+		}
+	}
+}
+
+func newTestCase(m *mheap.Mheap, ts []types.Type, limit int64, fs []Field) topTestCase {
+	return topTestCase{
+		types: ts,
+		proc:  process.New(m),
+		arg: &Argument{
+			Fs:    fs,
+			Limit: limit,
+		},
+	}
+}
+
+// create a new block based on the type information
+func newBatch(t *testing.T, ts []types.Type, proc *process.Process, rows int64) *batch.Batch {
+	bat := batch.New(len(ts))
+	bat.InitZsOne(int(rows))
+	for i := range bat.Vecs {
+		vec := vector.New(ts[i])
+		switch vec.Typ.Oid {
+		case types.T_int8:
+			data, err := mheap.Alloc(proc.Mp, rows*1)
+			require.NoError(t, err)
+			vec.Data = data
+			vs := encoding.DecodeInt8Slice(vec.Data)[:rows]
+			for i := range vs {
+				vs[i] = int8(i)
+			}
+			vec.Col = vs
+		case types.T_int64:
+			data, err := mheap.Alloc(proc.Mp, rows*8)
+			require.NoError(t, err)
+			vec.Data = data
+			vs := encoding.DecodeInt64Slice(vec.Data)[:rows]
+			for i := range vs {
+				vs[i] = int64(i)
+			}
+			vec.Col = vs
+		case types.T_float64:
+			data, err := mheap.Alloc(proc.Mp, rows*8)
+			require.NoError(t, err)
+			vec.Data = data
+			vs := encoding.DecodeFloat64Slice(vec.Data)[:rows]
+			for i := range vs {
+				vs[i] = float64(i)
+			}
+			vec.Col = vs
+		case types.T_date:
+			data, err := mheap.Alloc(proc.Mp, rows*4)
+			require.NoError(t, err)
+			vec.Data = data
+			vs := encoding.DecodeDateSlice(vec.Data)[:rows]
+			for i := range vs {
+				vs[i] = types.Date(i)
+			}
+			vec.Col = vs
+		case types.T_char, types.T_varchar:
+			size := 0
+			vs := make([][]byte, rows)
+			for i := range vs {
+				vs[i] = []byte(strconv.Itoa(i))
+				size += len(vs[i])
+			}
+			data, err := mheap.Alloc(proc.Mp, int64(size))
+			require.NoError(t, err)
+			data = data[:0]
+			col := new(types.Bytes)
+			o := uint32(0)
+			for _, v := range vs {
+				data = append(data, v...)
+				col.Offsets = append(col.Offsets, o)
+				o += uint32(len(v))
+				col.Lengths = append(col.Lengths, uint32(len(v)))
+			}
+			col.Data = data
+			vec.Col = col
+			vec.Data = data
+		}
+		bat.Vecs[i] = vec
+	}
+	return bat
+}
diff --git a/pkg/sql/colexec2/top/types.go b/pkg/sql/colexec2/top/types.go
new file mode 100644
index 0000000000000000000000000000000000000000..64d663d5df47069ae856f0a19b39078192771e63
--- /dev/null
+++ b/pkg/sql/colexec2/top/types.go
@@ -0,0 +1,112 @@
+// Copyright 2021 Matrix Origin
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package top
+
+import (
+	"fmt"
+
+	compare "github.com/matrixorigin/matrixone/pkg/compare2"
+	batch "github.com/matrixorigin/matrixone/pkg/container/batch2"
+)
+
+const (
+	Build = iota
+	Eval
+	End
+)
+
+// Direction for ordering results.
+type Direction int8
+
+// Direction values.
+const (
+	DefaultDirection Direction = iota
+	Ascending
+	Descending
+)
+
+type Container struct {
+	state int
+	n     int // number of attributes involved in sorting
+	sels  []int64
+	poses []int32 // sorted list of attributes
+	cmps  []compare.Compare
+
+	bat *batch.Batch
+}
+
+type Field struct {
+	Pos  int32
+	Type Direction
+}
+
+type Argument struct {
+	Limit int64
+	Fs    []Field
+	ctr   *Container
+}
+
+var directionName = [...]string{
+	DefaultDirection: "",
+	Ascending:        "ASC",
+	Descending:       "DESC",
+}
+
+func (n Field) String() string {
+	s := fmt.Sprintf("%v", n.Pos)
+	if n.Type != DefaultDirection {
+		s += " " + n.Type.String()
+	}
+	return s
+}
+
+func (i Direction) String() string {
+	if i < 0 || i > Direction(len(directionName)-1) {
+		return fmt.Sprintf("Direction(%d)", i)
+	}
+	return directionName[i]
+}
+
+func (ctr *Container) compare(vi, vj int, i, j int64) int {
+	for k := 0; k < ctr.n; k++ {
+		if r := ctr.cmps[k].Compare(vi, vj, i, j); r != 0 {
+			return r
+		}
+	}
+	return 0
+}
+
+func (ctr *Container) Len() int {
+	return len(ctr.sels)
+}
+
+func (ctr *Container) Less(i, j int) bool {
+	return ctr.compare(0, 0, ctr.sels[i], ctr.sels[j]) > 0
+}
+
+func (ctr *Container) Swap(i, j int) {
+	ctr.sels[i], ctr.sels[j] = ctr.sels[j], ctr.sels[i]
+}
+
+func (ctr *Container) Push(x interface{}) {
+	ctr.sels = append(ctr.sels, x.(int64))
+}
+
+func (ctr *Container) Pop() interface{} {
+	n := len(ctr.sels) - 1
+	x := ctr.sels[n]
+	ctr.sels = ctr.sels[:n]
+	return x
+}
diff --git a/pkg/vm/process2/process.go b/pkg/vm/process2/process.go
new file mode 100644
index 0000000000000000000000000000000000000000..87354c0b28610ed2eaa10d0a530dffa144ef362a
--- /dev/null
+++ b/pkg/vm/process2/process.go
@@ -0,0 +1,64 @@
+// Copyright 2021 Matrix Origin
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package process
+
+import (
+	"github.com/matrixorigin/matrixone/pkg/container/nulls"
+	"github.com/matrixorigin/matrixone/pkg/container/types"
+	"github.com/matrixorigin/matrixone/pkg/container/vector"
+	"github.com/matrixorigin/matrixone/pkg/vm/mheap"
+)
+
+// New creates a new Process.
+// A process stores the execution context.
+func New(m *mheap.Mheap) *Process {
+	return &Process{
+		Mp: m,
+	}
+}
+
+func Get(proc *Process, size int64, typ types.Type) (*vector.Vector, error) {
+	for i, vec := range proc.Reg.Vecs {
+		if int64(cap(vec.Data)) >= size {
+			vec.Ref = 0
+			vec.Or = false
+			vec.Typ = typ
+			nulls.Reset(vec.Nsp)
+			vec.Data = vec.Data[:size]
+			proc.Reg.Vecs[i] = proc.Reg.Vecs[len(proc.Reg.Vecs)-1]
+			proc.Reg.Vecs = proc.Reg.Vecs[:len(proc.Reg.Vecs)-1]
+			return vec, nil
+		}
+	}
+	data, err := mheap.Alloc(proc.Mp, size)
+	if err != nil {
+		return nil, err
+	}
+	vec := vector.New(typ)
+	vec.Data = data
+	return vec, nil
+}
+
+func Put(proc *Process, vec *vector.Vector) {
+	proc.Reg.Vecs = append(proc.Reg.Vecs, vec)
+}
+
+func FreeRegisters(proc *Process) {
+	for _, vec := range proc.Reg.Vecs {
+		vec.Ref = 0
+		vector.Free(vec, proc.Mp)
+	}
+	proc.Reg.Vecs = proc.Reg.Vecs[:0]
+}
diff --git a/pkg/vm/process2/process_test.go b/pkg/vm/process2/process_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..6116f275bbce8e5b2e43d761676bc4b700980e90
--- /dev/null
+++ b/pkg/vm/process2/process_test.go
@@ -0,0 +1,36 @@
+// Copyright 2021 Matrix Origin
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package process
+
+import (
+	"testing"
+
+	"github.com/matrixorigin/matrixone/pkg/container/types"
+	"github.com/matrixorigin/matrixone/pkg/vm/mheap"
+	"github.com/matrixorigin/matrixone/pkg/vm/mmu/guest"
+	"github.com/matrixorigin/matrixone/pkg/vm/mmu/host"
+	"github.com/stretchr/testify/require"
+)
+
+func TestProcess(t *testing.T) {
+	proc := New(mheap.New(guest.New(1<<30, host.New(1<<30))))
+	vec, err := Get(proc, 10, types.Type{Oid: types.T_int8})
+	require.NoError(t, err)
+	Put(proc, vec)
+	vec, err = Get(proc, 10, types.Type{Oid: types.T_int8})
+	require.NoError(t, err)
+	Put(proc, vec)
+	FreeRegisters(proc)
+}
diff --git a/pkg/vm/process2/types.go b/pkg/vm/process2/types.go
new file mode 100644
index 0000000000000000000000000000000000000000..cbf89d23df157d7f7b20f71f160765f900ee7474
--- /dev/null
+++ b/pkg/vm/process2/types.go
@@ -0,0 +1,71 @@
+// Copyright 2021 Matrix Origin
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package process
+
+import (
+	"context"
+
+	batch "github.com/matrixorigin/matrixone/pkg/container/batch2"
+	"github.com/matrixorigin/matrixone/pkg/container/vector"
+	"github.com/matrixorigin/matrixone/pkg/vm/mheap"
+)
+
+// WaitRegister channel
+type WaitRegister struct {
+	Ctx context.Context
+	Ch  chan *batch.Batch
+}
+
+// Register used in execution pipeline and shared with all operators of the same pipeline.
+type Register struct {
+	// InputBatch, stores the result of the previous operator.
+	InputBatch *batch.Batch
+	// Vecs, temporarily stores the column data in the execution of operators
+	// and it can be reused in the future execution to avoid mem alloc and type casting overhead.
+	Vecs []*vector.Vector
+	// MergeReceivers, receives result of multi previous operators from other pipelines
+	// e.g. merge operator.
+	MergeReceivers []*WaitRegister
+}
+
+//Limitation specifies the maximum resources that can be used in one query.
+type Limitation struct {
+	// Size, memory threshold.
+	Size int64
+	// BatchRows, max rows for batch.
+	BatchRows int64
+	// BatchSize, max size for batch.
+	BatchSize int64
+	// PartitionRows, max rows for partition.
+	PartitionRows int64
+}
+
+// Process contains context used in query execution
+// one or more pipeline will be generated for one query,
+// and one pipeline has one process instance.
+type Process struct {
+	// Id, query id.
+	Id  string
+	Reg Register
+	Lim Limitation
+	Mp  *mheap.Mheap
+
+	// unix timestamp
+	UnixTime int64
+
+	// Log Sequence Number
+	Lsn    []byte
+	Cancel context.CancelFunc
+}