Skip to content
This repository was archived by the owner on Jan 28, 2021. It is now read-only.

Commit b8d9155

Browse files
authored
Merge pull request #842 from erizocosmico/fix/distinct-ordered-rule
analyzer: only optimize distinct for sorts where first column is in schema
2 parents fb0e801 + 2a6ea8d commit b8d9155

File tree

3 files changed

+63
-17
lines changed

3 files changed

+63
-17
lines changed

engine_test.go

+14
Original file line numberDiff line numberDiff line change
@@ -1570,6 +1570,20 @@ var queries = []struct {
15701570
`SELECT (SELECT i FROM mytable ORDER BY i ASC LIMIT 1) AS x`,
15711571
[]sql.Row{{int64(1)}},
15721572
},
1573+
{
1574+
`SELECT DISTINCT n FROM bigtable ORDER BY t`,
1575+
[]sql.Row{
1576+
{int64(1)},
1577+
{int64(9)},
1578+
{int64(7)},
1579+
{int64(3)},
1580+
{int64(2)},
1581+
{int64(8)},
1582+
{int64(6)},
1583+
{int64(5)},
1584+
{int64(4)},
1585+
},
1586+
},
15731587
}
15741588

15751589
func TestQueries(t *testing.T) {

sql/analyzer/optimization_rules.go

+6-4
Original file line numberDiff line numberDiff line change
@@ -34,17 +34,19 @@ func optimizeDistinct(ctx *sql.Context, a *Analyzer, node sql.Node) (sql.Node, e
3434

3535
a.Log("optimize distinct, node of type: %T", node)
3636
if n, ok := node.(*plan.Distinct); ok {
37-
var isSorted bool
37+
var sortField *expression.GetField
3838
plan.Inspect(n, func(node sql.Node) bool {
3939
a.Log("checking for optimization in node of type: %T", node)
40-
if _, ok := node.(*plan.Sort); ok {
41-
isSorted = true
40+
if sort, ok := node.(*plan.Sort); ok && sortField == nil {
41+
if col, ok := sort.SortFields[0].Column.(*expression.GetField); ok {
42+
sortField = col
43+
}
4244
return false
4345
}
4446
return true
4547
})
4648

47-
if isSorted {
49+
if sortField != nil && n.Schema().Contains(sortField.Name(), sortField.Table()) {
4850
a.Log("distinct optimized for ordered output")
4951
return plan.NewOrderedDistinct(n.Child), nil
5052
}

sql/analyzer/optimization_rules_test.go

+43-13
Original file line numberDiff line numberDiff line change
@@ -186,24 +186,54 @@ func TestEraseProjection(t *testing.T) {
186186
}
187187

188188
func TestOptimizeDistinct(t *testing.T) {
189-
require := require.New(t)
190-
191-
t1 := memory.NewTable("foo", nil)
192-
t2 := memory.NewTable("foo", nil)
189+
t1 := memory.NewTable("foo", sql.Schema{
190+
{Name: "a", Source: "foo"},
191+
{Name: "b", Source: "foo"},
192+
})
193193

194-
notSorted := plan.NewDistinct(plan.NewResolvedTable(t1))
195-
sorted := plan.NewDistinct(plan.NewSort(nil, plan.NewResolvedTable(t2)))
194+
testCases := []struct {
195+
name string
196+
child sql.Node
197+
optimized bool
198+
}{
199+
{
200+
"without sort",
201+
plan.NewResolvedTable(t1),
202+
false,
203+
},
204+
{
205+
"sort but column not projected",
206+
plan.NewSort(
207+
[]plan.SortField{
208+
{Column: gf(0, "foo", "c")},
209+
},
210+
plan.NewResolvedTable(t1),
211+
),
212+
false,
213+
},
214+
{
215+
"sort and column projected",
216+
plan.NewSort(
217+
[]plan.SortField{
218+
{Column: gf(0, "foo", "a")},
219+
},
220+
plan.NewResolvedTable(t1),
221+
),
222+
true,
223+
},
224+
}
196225

197226
rule := getRule("optimize_distinct")
198227

199-
analyzedNotSorted, err := rule.Apply(sql.NewEmptyContext(), nil, notSorted)
200-
require.NoError(err)
201-
202-
analyzedSorted, err := rule.Apply(sql.NewEmptyContext(), nil, sorted)
203-
require.NoError(err)
228+
for _, tt := range testCases {
229+
t.Run(tt.name, func(t *testing.T) {
230+
node, err := rule.Apply(sql.NewEmptyContext(), nil, plan.NewDistinct(tt.child))
231+
require.NoError(t, err)
204232

205-
require.Equal(notSorted, analyzedNotSorted)
206-
require.Equal(plan.NewOrderedDistinct(sorted.Child), analyzedSorted)
233+
_, ok := node.(*plan.OrderedDistinct)
234+
require.Equal(t, tt.optimized, ok)
235+
})
236+
}
207237
}
208238

209239
func TestMoveJoinConditionsToFilter(t *testing.T) {

0 commit comments

Comments
 (0)