Files
tidb/pkg/executor/parallel_apply_test.go
2024-02-29 11:03:31 +00:00

508 lines
25 KiB
Go

// Copyright 2020 PingCAP, Inc.
//
// 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 executor_test
import (
"fmt"
"strings"
"testing"
"github.com/pingcap/failpoint"
"github.com/pingcap/tidb/pkg/testkit"
"github.com/stretchr/testify/require"
)
func checkApplyPlan(t *testing.T, tk *testkit.TestKit, sql string, parallel int) {
results := tk.MustQuery("explain analyze " + sql)
containApply := false
for _, row := range results.Rows() {
line := fmt.Sprintf("%v", row)
if strings.Contains(line, "Apply") {
if parallel > 0 { // check the concurrency if parallel is larger than 0
str := "Concurrency:"
if parallel > 1 {
str += fmt.Sprintf("%v", parallel)
}
require.Contains(t, line, str)
}
containApply = true
break
}
}
require.True(t, containApply)
}
func TestParallelApplyPlan(t *testing.T) {
store := testkit.CreateMockStore(t)
tk := testkit.NewTestKit(t, store)
tk.MustExec("use test")
tk.MustExec("drop table if exists t")
tk.MustExec("create table t (a int, b int)")
tk.MustExec("insert into t values (0, 0), (1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6), (7, 7), (8, 8), (9, 9), (null, null)")
q1 := "select t1.b from t t1 where t1.b > (select max(b) from t t2 where t1.a > t2.a)"
checkApplyPlan(t, tk, q1, 0)
tk.MustQuery(q1).Sort().Check(testkit.Rows("1", "2", "3", "4", "5", "6", "7", "8", "9"))
tk.MustExec("set tidb_enable_parallel_apply=true")
checkApplyPlan(t, tk, q1, 1)
tk.MustQuery(q1).Sort().Check(testkit.Rows("1", "2", "3", "4", "5", "6", "7", "8", "9"))
q2 := "select * from t t0 where t0.b <= (select max(t1.b) from t t1 where t1.b > (select max(b) from t t2 where t1.a > t2.a and t0.a > t2.a));"
checkApplyPlan(t, tk, q2, 1) // only the outside apply can be parallel
tk.MustQuery(q2).Sort().Check(testkit.Rows("1 1", "2 2", "3 3", "4 4", "5 5", "6 6", "7 7", "8 8", "9 9"))
q3 := "select t1.b from t t1 where t1.b > (select max(b) from t t2 where t1.a > t2.a) order by t1.a"
checkApplyPlan(t, tk, q3, 0)
tk.MustExec("alter table t add index idx(a)")
checkApplyPlan(t, tk, q3, 1)
tk.MustQuery(q3).Sort().Check(testkit.Rows("1", "2", "3", "4", "5", "6", "7", "8", "9"))
tk.MustQuery("show warnings").Check(testkit.Rows("Warning 1105 Parallel Apply rejects the possible order properties of its outer child currently"))
}
func TestApplyColumnType(t *testing.T) {
store := testkit.CreateMockStore(t)
tk := testkit.NewTestKit(t, store)
tk.MustExec("use test")
tk.MustExec("set tidb_enable_parallel_apply=true")
// int
tk.MustExec("create table t(a int, b int)")
tk.MustExec("create table t1(a int, b int)")
tk.MustExec("insert into t values(1,1), (2,2), (5,5), (2, 4), (5, 2), (9, 4)")
tk.MustExec("insert into t1 values(2, 3), (4, 9), (10, 4), (1, 10)")
sql := "select * from t where t.b > (select min(t1.b) from t1 where t1.a > t.a)"
checkApplyPlan(t, tk, sql, 1)
tk.MustQuery(sql).Sort().Check(testkit.Rows("5 5"))
// varchar
tk.MustExec("drop table t, t1")
tk.MustExec("create table t1(a varchar(255), b varchar(255))")
tk.MustExec("create table t2(a varchar(255))")
tk.MustExec(`insert into t1 values("aa", "bb"), ("aa", "tikv"), ("bb", "cc"), ("bb", "ee")`)
tk.MustExec(`insert into t2 values("kk"), ("aa"), ("dd"), ("bb")`)
sql = "select (select min(t2.a) from t2 where t2.a > t1.a) from t1"
checkApplyPlan(t, tk, sql, 1)
tk.MustQuery(sql).Sort().Check(testkit.Rows("bb", "bb", "dd", "dd"))
// bit
tk.MustExec("drop table t1, t2")
tk.MustExec("create table t1(a bit(10), b int)")
tk.MustExec("create table t2(a bit(10), b int)")
tk.MustExec(`insert into t1 values ('1', 1), ('2', 2), ('3', 3), ('4', 4), ('1', 1), ('2', 2), ('3', 3), ('4', 4)`)
tk.MustExec(`insert into t2 values ('1', 1), ('2', 2), ('3', 3), ('4', 4), ('1', 1), ('2', 2), ('3', 3), ('4', 4)`)
sql = "select b from t1 where t1.b > (select min(t2.b) from t2 where t2.a < t1.a)"
checkApplyPlan(t, tk, sql, 1)
tk.MustQuery(sql).Sort().Check(testkit.Rows("2", "2", "3", "3", "4", "4"))
// char
tk.MustExec("drop table t1, t2")
tk.MustExec("create table t1(a char(25), b int)")
tk.MustExec("create table t2(a char(10), b int)")
tk.MustExec(`insert into t1 values("abc", 1), ("abc", "5"), ("fff", 4), ("fff", 9), ("tidb", 6), ("tidb", 5)`)
tk.MustExec(`insert into t2 values()`)
sql = "select t1.b from t1 where t1.b > (select max(t2.b) from t2 where t2.a > t1.a)"
checkApplyPlan(t, tk, sql, 1)
tk.MustQuery(sql).Sort().Check(testkit.Rows())
// double
tk.MustExec("drop table t1, t2")
tk.MustExec("create table t1(a int, b double)")
tk.MustExec("create table t2(a int, b double)")
tk.MustExec("insert into t1 values(1, 2.12), (1, 1.11), (2, 3), (2, 4.56), (5, 55), (5, -4)")
tk.MustExec("insert into t2 values(1, 3.22), (3, 4.5), (5, 2.3), (4, 5.55)")
sql = "select * from t1 where t1.a < (select avg(t2.a) from t2 where t2.b > t1.b)"
checkApplyPlan(t, tk, sql, 1)
tk.MustQuery(sql).Sort().Check(testkit.Rows("1 1.11", "1 2.12", "2 3", "2 4.56"))
// date
tk.MustExec("drop table t1, t2")
tk.MustExec("create table t1(a date, b int, c int)")
tk.MustExec("create table t2(a date, b int)")
tk.MustExec(`insert into t1 values("2020-01-01", 3, 4), ("2020-01-01", 4, 5), ("2020-01-01", 4, 3), ("2020-02-01", 7, 7), ("2020-02-01", 6, 6)`)
tk.MustExec(`insert into t2 values("2020-01-02", 4), ("2020-02-02", 8), ("2020-02-02", 7)`)
sql = "select * from t1 where t1.b >= (select min(t2.b) from t2 where t2.a > t1.a) and t1.c >= (select min(t2.b) from t2 where t2.a > t1.a)"
tk.MustQuery(sql).Sort().Check(testkit.Rows("2020-01-01 4 5", "2020-02-01 7 7"))
// datetime
tk.MustExec("drop table t1, t2")
tk.MustExec("create table t1(a datetime, b int)")
tk.MustExec("create table t2(a datetime, b int)")
tk.MustExec(`insert into t1 values("2020-01-01 00:00:00", 1), ("2020-01-01 00:00:00", 2), ("2020-06-06 00:00:00", 3), ("2020-06-06 00:00:00", 4), ("2020-09-08 00:00:00", 4)`)
tk.MustExec(`insert into t2 values("2020-01-01 00:00:00", 1), ("2020-01-01 00:00:01", 2), ("2020-08-20 00:00:00", 4)`)
sql = "select b from t1 where t1.b >= (select max(t2.b) from t2 where t2.a > t1.a)"
checkApplyPlan(t, tk, sql, 1)
tk.MustQuery(sql).Sort().Check(testkit.Rows("4"))
// timestamp
tk.MustExec("drop table t1, t2")
tk.MustExec("create table t1(a timestamp, b int)")
tk.MustExec("create table t2(a timestamp, b int)")
tk.MustExec(`insert into t1 values("2020-01-01 00:00:00", 1), ("2020-01-01 00:00:00", 2), ("2020-06-06 00:00:00", 3), ("2020-06-06 00:00:00", 4), ("2020-09-08 00:00:00", 4)`)
tk.MustExec(`insert into t2 values("2020-01-01 00:00:00", 1), ("2020-01-01 00:00:01", 2), ("2020-08-20 00:00:00", 4)`)
sql = "select b from t1 where t1.b >= (select max(t2.b) from t2 where t2.a > t1.a)"
checkApplyPlan(t, tk, sql, 1)
tk.MustQuery(sql).Sort().Check(testkit.Rows("4"))
}
func TestApplyMultiColumnType(t *testing.T) {
store := testkit.CreateMockStore(t)
tk := testkit.NewTestKit(t, store)
tk.MustExec("use test")
tk.MustExec("set tidb_enable_parallel_apply=true")
// int & int
tk.MustExec("create table t1(a int, b int)")
tk.MustExec("create table t2(a int, b int)")
tk.MustExec("insert into t1 values (1, 1), (1, 1), (2, 2), (2, 3), (2, 3), (1, 1), (1, 1), (2, 2), (2, 3), (2, 3)")
tk.MustExec("insert into t2 values (2, 2), (3,3), (-1, 1), (5, 4), (2, 2), (3,3), (-1, 1), (5, 4)")
sql := "select (select count(*) from t2 where t2.a > t1.a and t2.b > t1.a) from t1"
checkApplyPlan(t, tk, sql, 1)
tk.MustQuery(sql).Sort().Check(testkit.Rows("4", "4", "4", "4", "4", "4", "6", "6", "6", "6"))
// int & char
tk.MustExec("drop table t1, t2")
tk.MustExec("create table t1(a int, b char(20))")
tk.MustExec("create table t2(a int, b char(20))")
tk.MustExec(`insert into t1 values (1, "a"), (2, "b"), (3, "c"), (1, "a"), (2, "b"), (3, "c")`)
tk.MustExec(`insert into t2 values (1, "a"), (2, "b"), (3, "c"), (1, "a"), (2, "b"), (3, "c")`)
sql = "select (select sum(t2.a) from t2 where t2.a > t1.a or t2.b < t1.b) from t1"
checkApplyPlan(t, tk, sql, 1)
tk.MustQuery(sql).Sort().Check(testkit.Rows("10", "10", "6", "6", "8", "8"))
// int & bit
tk.MustExec("drop table t1, t2")
tk.MustExec("create table t1(a int, b bit(10), c int)")
tk.MustExec("create table t2(a int, b int, c int)")
tk.MustExec(`insert into t1 values (1, '1', 1), (2, '2', 4), (3, '3', 6), (4, '4', 8), (1, '1', 1), (2, '2', 4), (3, '3', 6), (4, '4', 8)`)
tk.MustExec(`insert into t2 values (1, 1111, 11), (2, 2222, 22), (1, 1111, 11), (2, 2222, 22)`)
sql = "select a, c from t1 where (select max(t2.c) from t2 where t2.a > t1.a and t2.b > t1.b) > 4"
checkApplyPlan(t, tk, sql, 1)
tk.MustQuery(sql).Sort().Check(testkit.Rows("1 1", "1 1"))
// char & char
tk.MustExec("drop table t1, t2")
tk.MustExec("create table t1(a char(20), b varchar(255))")
tk.MustExec("create table t2(a char(20), b varchar(255))")
tk.MustExec(`insert into t1 values ('7', '7'), ('8', '8'), ('9', '9'), ('7', '7'), ('8', '8'), ('9', '9')`)
tk.MustExec(`insert into t2 values ('7', '7'), ('8', '8'), ('9', '9'), ('7', '7'), ('8', '8'), ('9', '9')`)
sql = "select count(*) from t1 where (select sum(t2.a) from t2 where t2.a >= t1.a and t2.b >= t1.b) > 4"
checkApplyPlan(t, tk, sql, 1)
tk.MustQuery(sql).Sort().Check(testkit.Rows("6"))
// enum & char
tk.MustExec("drop table t1, t2")
tk.MustExec(`create table t1(a varchar(20), b enum("a", "b", "c", "d", "e","f"))`)
tk.MustExec("create table t2(a varchar(20), b int)")
tk.MustExec(`insert into t1 values ('1', 'a'), ('2', 'b'), ('3', 'c'), ('1', 'a'), ('2', 'b'), ('3', 'c')`)
tk.MustExec(`insert into t2 values ('1', 100), ('2', 200), ('3', 300), ('4', 400), ('1', 100), ('2', 200), ('3', 300), ('4', 400)`)
sql = "select * from t1 where (select sum(t2.b) from t2 where t2.a > t1.a and t2.b * 2 > t1.b) > 0"
checkApplyPlan(t, tk, sql, 1)
tk.MustQuery(sql).Sort().Check(testkit.Rows("1 a", "1 a", "2 b", "2 b", "3 c", "3 c"))
// char & bit
tk.MustExec("drop table t1, t2")
tk.MustExec("create table t1(a varchar(20), b bit(10))")
tk.MustExec("create table t2(a varchar(20), b int)")
tk.MustExec("insert into t1 values ('1', '1'), ('2', '2'), ('3', '3'), ('4', '4'), ('1', '1'), ('2', '2'), ('3', '3'), ('4', '4')")
tk.MustExec("insert into t2 values ('1', 1), ('2', 2), ('3', 3), ('4', 4), ('1', 1), ('2', 2), ('3', 3), ('4', 4)")
sql = "select a from t1 where (select sum(t2.b) from t2 where t2.a > t1.a and t2.b < t1.b) > 4"
checkApplyPlan(t, tk, sql, 1)
tk.MustQuery(sql).Sort().Check(testkit.Rows("1", "1", "2", "2", "3", "3"))
// int & double
tk.MustExec("drop table t1, t2")
tk.MustExec("create table t1 (a int, b double)")
tk.MustExec("create table t2 (a int, b double)")
tk.MustExec("insert into t1 values (1, 1.1), (2, 2.2), (3, 3.3), (4, 4.4), (1, 1.1), (2, 2.2), (3, 3.3), (4, 4.4)")
tk.MustExec("insert into t2 values (1, 1.1), (2, 2.2), (3, 3.3), (4, 4.4), (1, 1.1), (2, 2.2), (3, 3.3), (4, 4.4)")
sql = "select * from t1 where (select min(t2.a) from t2 where t2.a < t1.a and t2.a > 1 and t2.b < t1.b) > 0"
checkApplyPlan(t, tk, sql, 1)
tk.MustQuery(sql).Sort().Check(testkit.Rows("3 3.3", "3 3.3", "4 4.4", "4 4.4"))
// int & datetime
tk.MustExec("drop table t1, t2")
tk.MustExec("create table t1(a int, b datetime)")
tk.MustExec("create table t2(a int, b datetime)")
tk.MustExec(`insert into t1 values (1, "2020-01-01"), (2, "2020-02-02"), (3, "2020-03-03"), (1, "2020-01-01"), (2, "2020-02-02"), (3, "2020-03-03")`)
tk.MustExec(`insert into t2 values (1, "2020-01-01"), (2, "2020-02-02"), (3, "2020-03-03"), (1, "2020-01-01"), (2, "2020-02-02"), (3, "2020-03-03")`)
sql = `select * from t1 where (select count(*) from t2 where t2.a >= t1.a and t2.b between t1.b and "2020-09-07 00:00:00") > 1`
checkApplyPlan(t, tk, sql, 1)
tk.MustQuery(sql).Sort().Check(testkit.Rows("1 2020-01-01 00:00:00", "1 2020-01-01 00:00:00", "2 2020-02-02 00:00:00", "2 2020-02-02 00:00:00", "3 2020-03-03 00:00:00", "3 2020-03-03 00:00:00"))
// int & int & char
tk.MustExec("drop table t1, t2")
tk.MustExec("create table t1(a int, b int, c varchar(20))")
tk.MustExec("create table t2(a int, b int, c varchar(20))")
tk.MustExec("insert into t1 values (1, 1, '1'), (2, 2, '2'), (3, 3, '3'), (1, 1, '1'), (2, 2, '2'), (3, 3, '3')")
tk.MustExec("insert into t2 values (1, 1, '1'), (2, 2, '2'), (3, 3, '3'), (1, 1, '1'), (2, 2, '2'), (3, 3, '3')")
sql = "select (select min(t2.a) from t2 where t2.a > t1.a and t2.b > t1.b and t2.c > t1.c) from t1"
checkApplyPlan(t, tk, sql, 1)
tk.MustQuery(sql).Sort().Check(testkit.Rows("2", "2", "3", "3", "<nil>", "<nil>"))
}
func TestMultipleApply(t *testing.T) {
store := testkit.CreateMockStore(t)
tk := testkit.NewTestKit(t, store)
tk.MustExec("use test")
tk.MustExec("set tidb_enable_parallel_apply=true")
// compare apply with constant values
tk.MustExec("drop table if exists t1, t2")
tk.MustExec(`create table t1(a varchar(20), b enum("a", "b", "c", "d", "e","f"))`)
tk.MustExec("create table t2(a varchar(20), b int)")
tk.MustExec(`insert into t1 values ("1", "a"), ("2", "b"), ("3", "c"), ("4", "d"), ("1", "a"), ("2", "b"), ("3", "c"), ("4", "d")`)
tk.MustExec(`insert into t2 values ("1", 1), ("2", 2), ("3", 3), ("4", 4), ("1", 1), ("2", 2), ("3", 3), ("4", 4)`)
sql := "select * from t1 where (select sum(t2.b) from t2 where t2.a > t1.a) >= (select sum(t2.b) from t2 where t2.b > t1.b)"
checkApplyPlan(t, tk, sql, 1)
tk.MustQuery(sql).Sort().Check(testkit.Rows("1 a", "1 a", "2 b", "2 b", "3 c", "3 c"))
// 2 apply operators in where conditions
tk.MustExec("drop table if exists t1, t2")
tk.MustExec("create table t1(a int, b double)")
tk.MustExec("create table t2(a int, b double)")
tk.MustExec("insert into t1 values (1, 1.1), (2, 2.2), (3, 3.3), (4, 4.4), (1, 1.1), (2, 2.2), (3, 3.3), (4, 4.4)")
tk.MustExec("insert into t2 values (1, 1.1), (2, 2.2), (3, 3.3), (4, 4.4), (1, 1.1), (2, 2.2), (3, 3.3), (4, 4.4)")
sql = "select * from t1 where (select min(t2.a) from t2 where t2.a < t1.a and t2.a > 1) * (select min(t2.a) from t2 where t2.b < t1.b) > 1"
checkApplyPlan(t, tk, sql, 1)
tk.MustQuery(sql).Sort().Check(testkit.Rows("3 3.3", "3 3.3", "4 4.4", "4 4.4"))
// 2 apply operators and compare it with constant values
tk.MustExec("drop table if exists t1, t2")
tk.MustExec("create table t1(a varchar(20), b bit(10))")
tk.MustExec("create table t2(a varchar(20), b int)")
tk.MustExec("insert into t1 values ('1', '1'), ('2', '2'), ('3', '3'), ('4', '4'), ('1', '1'), ('2', '2'), ('3', '3'), ('4', '4')")
tk.MustExec("insert into t2 values ('1', 1111), ('2', 2222), ('3', 3333), ('4', 4444), ('1', 1111), ('2', 2222), ('3', 3333), ('4', 4444)")
sql = "select a from t1 where (select sum(t2.b) from t2 where t2.a > t1.a) > 4 and (select sum(t2.b) from t2 where t2.b > t1.b) > 4"
checkApplyPlan(t, tk, sql, 1)
tk.MustQuery(sql).Sort().Check(testkit.Rows("1", "1", "2", "2", "3", "3"))
// multiple fields and where conditions
tk.MustExec("drop table if exists t1, t2")
tk.MustExec("create table t1(a int, b int, c varchar(20))")
tk.MustExec("create table t2(a int, b int, c varchar(20))")
tk.MustExec("insert into t1 values (1, 1, '1'), (2, 2, '2'), (3, 3, '3'), (4, 4, '4'), (1, 1, '1'), (2, 2, '2'), (3, 3, '3'), (4, 4, '4')")
tk.MustExec("insert into t2 values (1, 1, '1'), (2, 2, '2'), (3, 3, '3'), (4, 4, '4'), (1, 1, '1'), (2, 2, '2'), (3, 3, '3'), (4, 4, '4')")
sql = "select (select min(t2.a) from t2 where t2.a > t1.a and t2.b > t1.b), (select max(t2.a) from t2 where t2.a > t1.a and t2.b > t1.b) from t1 where (select count(*) from t2 where t2.c > t1.c) > 3"
checkApplyPlan(t, tk, sql, 1)
tk.MustQuery(sql).Sort().Check(testkit.Rows("2 4", "2 4", "3 4", "3 4"))
}
func TestApplyWithOtherOperators(t *testing.T) {
store := testkit.CreateMockStore(t)
tk := testkit.NewTestKit(t, store)
tk.MustExec("use test")
tk.MustExec("set tidb_enable_parallel_apply=true")
// hash join
tk.MustExec("drop table if exists t1, t2")
tk.MustExec("create table t1(a int, b int)")
tk.MustExec("create table t2(a int, b int)")
tk.MustExec("insert into t1 values (1, 1), (2, 2), (3, 3), (1, 1), (2, 2), (3, 3)")
tk.MustExec("insert into t2 values (1, 1), (2, 2), (3, 3), (1, 1), (2, 2), (3, 3)")
sql := "select /*+ hash_join(t1) */ (select count(t2.b) from t2 where t1.a > t2.a) from t1, t2 where t1.a = t2.a"
checkApplyPlan(t, tk, sql, 1)
tk.MustQuery(sql).Sort().Check(testkit.Rows("0", "0", "0", "0", "2", "2", "2", "2", "4", "4", "4", "4"))
// merge join
tk.MustExec("drop table if exists t1, t2")
tk.MustExec("create table t1(a double, b int)")
tk.MustExec("create table t2(a int, b int)")
tk.MustExec("insert into t1 values (1, 1), (2, 2), (3, 3), (1, 1), (2, 2), (3, 3)")
tk.MustExec("insert into t2 values (1, 1), (2, 2), (3, 3), (1, 1), (2, 2), (3, 3)")
sql = "select /*+ merge_join(t1) */ (select count(t2.b) from t2 where t1.a > t2.a) from t1, t2 where t1.a = t2.a"
checkApplyPlan(t, tk, sql, 1)
tk.MustQuery(sql).Sort().Check(testkit.Rows("0", "0", "0", "0", "2", "2", "2", "2", "4", "4", "4", "4"))
// index merge join
tk.MustExec("drop table if exists t1, t2")
tk.MustExec("create table t1(a int primary key, b int)")
tk.MustExec("create table t2(a int, b int, index idx(a))")
tk.MustExec("insert into t1 values (1, 1), (2, 2), (3, 3)")
tk.MustExec("insert into t2 values (1, 1), (2, 2), (3, 3), (1, 1), (2, 2), (3, 3)")
sql = "select /*+ inl_merge_join(t1) */ (select count(t2.b) from t2 where t1.a > t2.a) from t1, t2 where t1.a = t2.a"
checkApplyPlan(t, tk, sql, 1)
tk.MustQuery(sql).Sort().Check(testkit.Rows("0", "0", "2", "2", "4", "4"))
sql = "select /*+ inl_merge_join(t2) */ (select count(t2.b) from t2 where t1.a > t2.a) from t1, t2 where t1.a = t2.a"
checkApplyPlan(t, tk, sql, 1)
tk.MustQuery(sql).Sort().Check(testkit.Rows("0", "0", "2", "2", "4", "4"))
// index hash join
tk.MustExec("drop table if exists t1, t2")
tk.MustExec("create table t1(a int, b int, index idx(a, b))")
tk.MustExec("create table t2(a int, b int, index idx(a))")
tk.MustExec("insert into t1 values (1, 1), (2, 2), (3, 3), (1, 1), (2, 2), (3, 3)")
tk.MustExec("insert into t2 values (1, 1), (2, 2), (3, 3), (1, 1), (2, 2), (3, 3)")
sql = "select /*+ inl_hash_join(t1) */ (select count(t2.b) from t2 where t1.a > t2.a) from t1, t2 where t1.a = t2.a"
checkApplyPlan(t, tk, sql, 1)
tk.MustQuery(sql).Sort().Check(testkit.Rows("0", "0", "0", "0", "2", "2", "2", "2", "4", "4", "4", "4"))
sql = "select /*+ inl_hash_join(t2) */ (select count(t2.b) from t2 where t1.a > t2.a) from t1, t2 where t1.a = t2.a"
checkApplyPlan(t, tk, sql, 1)
tk.MustQuery(sql).Sort().Check(testkit.Rows("0", "0", "0", "0", "2", "2", "2", "2", "4", "4", "4", "4"))
// index join
tk.MustExec("drop table if exists t1, t2")
tk.MustExec("create table t1(a int , b int, unique index idx(a))")
tk.MustExec("create table t2(a int, b int, unique index idx(a))")
tk.MustExec("insert into t1 values (1, 1), (2, 2), (3, 3)")
tk.MustExec("insert into t2 values (1, 1), (2, 2), (3, 3)")
sql = "select /*+ inl_join(t1) */ (select count(t2.b) from t2 where t1.a > t2.a) from t1, t2 where t1.a = t2.a"
checkApplyPlan(t, tk, sql, 1)
tk.MustQuery(sql).Sort().Check(testkit.Rows("0", "1", "2"))
sql = "select /*+ inl_join(t2) */ (select count(t2.b) from t2 where t1.a > t2.a) from t1, t2 where t1.a = t2.a"
checkApplyPlan(t, tk, sql, 1)
tk.MustQuery(sql).Sort().Check(testkit.Rows("0", "1", "2"))
// index merge
tk.MustExec("drop table if exists t")
tk.MustExec("create table t(a int, b int, c int, index idxa(a), unique index idxb(b))")
tk.MustExec("insert into t values (1, 1, 1), (2, 2, 2), (3, 3, 3), (4, 4, 4), (1, 5, 1), (2, 6, 2), (3, 7, 3), (4, 8, 4)")
sql = "select /*+ use_index_merge(t) */ * from t where (a > 0 or b < 0) and (select count(*) from t t1 where t1.c > t.a) > 0"
checkApplyPlan(t, tk, sql, 1)
tk.MustQuery(sql).Sort().Check(testkit.Rows("1 1 1", "1 5 1", "2 2 2", "2 6 2", "3 3 3", "3 7 3"))
// aggregation
tk.MustExec("drop table if exists t")
tk.MustExec("create table t(a int, b int)")
tk.MustExec("insert into t values (1, 1), (2, 2), (3, 3), (4, 4), (1, 1), (2, 2), (3, 3), (4, 4)")
sql = "select /*+ stream_agg() */ a from t where (select count(*) from t1 where t1.b > t.a) > 1 group by a"
checkApplyPlan(t, tk, sql, 1)
tk.MustQuery(sql).Sort().Check(testkit.Rows("1"))
sql = "select /*+ hash_agg() */ a from t where (select count(*) from t1 where t1.b > t.a) > 1 group by a"
checkApplyPlan(t, tk, sql, 1)
tk.MustQuery(sql).Sort().Check(testkit.Rows("1"))
}
func TestApplyConcurrency(t *testing.T) {
store := testkit.CreateMockStore(t)
tk := testkit.NewTestKit(t, store)
tk.MustExec("use test")
tk.MustExec("set tidb_enable_parallel_apply=true")
// tidb_executor_concurrency
tk.MustExec("drop table if exists t1, t2")
tk.MustExec("create table t1(a int, b int)")
tk.MustExec("create table t2(a int, b int)")
sql := "select * from t1 where t1.b > (select sum(t2.b) from t2 where t2.a > t1.a)"
tk.MustExec("set tidb_executor_concurrency = 3")
checkApplyPlan(t, tk, sql, 3)
tk.MustExec("set tidb_executor_concurrency = 5")
checkApplyPlan(t, tk, sql, 5)
// concurrency
tk.MustExec("drop table if exists t")
tk.MustExec("create table t (a int)")
vals := ""
n := 100
for i := 1; i <= n; i++ {
if i > 1 {
vals += ","
}
vals = vals + fmt.Sprintf("(%v)", i)
}
tk.MustExec(fmt.Sprintf("insert into t values %v", vals))
sql = "select sum(a) from t where t.a >= (select max(a) from t t1 where t1.a <= t.a)"
for cc := 1; cc <= 10; cc += 3 {
tk.MustExec(fmt.Sprintf("set tidb_executor_concurrency = %v", cc))
tk.MustQuery(sql).Check(testkit.Rows(fmt.Sprintf("%v", (n*(n+1))/2)))
}
}
func TestApplyCacheRatio(t *testing.T) {
store := testkit.CreateMockStore(t)
tk := testkit.NewTestKit(t, store)
tk.MustExec("use test")
tk.MustExec("drop table if exists t1, t2")
tk.MustExec("create table t1(a int, b int)")
tk.MustExec("create table t2(a int, b int)")
sql := "select * from t1 where (select min(t2.b) from t2 where t2.a> t1.a) > 10"
tk.MustExec("insert into t2 values (1, 1), (2, 2), (3, 3), (4, 4), (5, 5)")
checkRatio := func(ratio string) bool {
rows := tk.MustQuery("explain analyze " + sql).Rows()
for _, r := range rows {
line := fmt.Sprintf("%v", r)
if strings.Contains(line, "cacheHitRatio:"+ratio) {
return true
}
}
return false
}
// 10%
tk.MustExec("insert into t1 values (1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6), (7, 7), (8, 8), (9, 9), (1, 1)")
require.True(t, checkRatio("10.000%"))
tk.MustExec("set tidb_mem_quota_apply_cache = 0")
require.False(t, checkRatio(""))
tk.MustExec("set tidb_mem_quota_apply_cache = 33554432")
// 20%
tk.MustExec("truncate t1")
tk.MustExec("insert into t1 values (1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6), (7, 7), (8, 8), (2, 2), (1, 1)")
require.True(t, checkRatio("20.000%"))
tk.MustExec("set tidb_mem_quota_apply_cache = 0")
require.False(t, checkRatio(""))
tk.MustExec("set tidb_mem_quota_apply_cache = 33554432")
// 50%
tk.MustExec("truncate t1")
tk.MustExec("insert into t1 values (1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (1, 1), (2, 2), (3, 3), (4, 4), (5, 5)")
require.True(t, checkRatio("50.000%"))
tk.MustExec("set tidb_mem_quota_apply_cache = 0")
require.False(t, checkRatio(""))
}
func TestApplyGoroutinePanic(t *testing.T) {
store := testkit.CreateMockStore(t)
tk := testkit.NewTestKit(t, store)
tk.MustExec("use test")
tk.MustExec("set tidb_enable_parallel_apply=true")
tk.MustExec("drop table if exists t1, t2")
tk.MustExec("create table t1(a int, b int)")
tk.MustExec("create table t2(a int, b int)")
tk.MustExec("insert into t1 values (1, 1), (1, 1), (2, 2), (2, 3), (2, 3), (1, 1), (1, 1), (2, 2), (2, 3), (2, 3)")
tk.MustExec("insert into t2 values (2, 2), (3,3), (-1, 1), (5, 4), (2, 2), (3,3), (-1, 1), (5, 4)")
// no panic
sql := "select (select count(*) from t2 where t2.a > t1.a and t2.b > t1.a) from t1"
checkApplyPlan(t, tk, sql, 1)
tk.MustQuery(sql).Sort().Check(testkit.Rows("4", "4", "4", "4", "4", "4", "6", "6", "6", "6"))
// panic in a inner worker
require.NoError(t, failpoint.Enable("github.com/pingcap/tidb/pkg/executor/parallelApplyInnerWorkerPanic", "panic"))
err := tk.QueryToErr(sql)
require.Error(t, err)
require.NoError(t, failpoint.Disable("github.com/pingcap/tidb/pkg/executor/parallelApplyInnerWorkerPanic"))
for _, panicName := range []string{"parallelApplyInnerWorkerPanic", "parallelApplyOuterWorkerPanic", "parallelApplyGetCachePanic", "parallelApplySetCachePanic"} {
panicPath := fmt.Sprintf("github.com/pingcap/tidb/pkg/executor/%v", panicName)
require.NoError(t, failpoint.Enable(panicPath, "panic"))
require.Error(t, tk.QueryToErr(sql))
require.NoError(t, failpoint.Disable(panicPath))
}
}
func TestParallelApplyCorrectness(t *testing.T) {
store := testkit.CreateMockStore(t)
tk := testkit.NewTestKit(t, store)
tk.MustExec("use test")
tk.MustExec("drop table if exists t1;")
tk.MustExec("create table t1 (c1 bigint, c2 int, c3 int, c4 int, primary key(c1, c2), index (c3));")
tk.MustExec("insert into t1 values(1, 1, 1, 1), (1, 2, 3, 3), (2, 1, 4, 4), (2, 2, 2, 2);")
tk.MustExec("set tidb_enable_parallel_apply=true")
sql := "select (select /*+ NO_DECORRELATE() */ sum(c4) from t1 where t1.c3 = alias.c3) from t1 alias where alias.c1 = 1;"
tk.MustQuery(sql).Sort().Check(testkit.Rows("1", "3"))
tk.MustExec("set tidb_enable_parallel_apply=false")
tk.MustQuery(sql).Sort().Check(testkit.Rows("1", "3"))
}