Skip to content

Commit 4578b4f

Browse files
authored
planner: add hint support for optimizer cost factors (#60558) (#61904)
ref #60357
1 parent d3110e7 commit 4578b4f

File tree

4 files changed

+119
-2
lines changed

4 files changed

+119
-2
lines changed

pkg/planner/core/casetest/hint/BUILD.bazel

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ go_test(
99
],
1010
data = glob(["testdata/**"]),
1111
flaky = True,
12-
shard_count = 8,
12+
shard_count = 9,
1313
deps = [
1414
"//pkg/config",
1515
"//pkg/domain",

pkg/planner/core/casetest/hint/hint_test.go

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ package hint
1616

1717
import (
1818
"context"
19+
"strconv"
1920
"testing"
2021

2122
"github.com/pingcap/tidb/pkg/domain"
@@ -341,3 +342,90 @@ func TestQBHintHandlerDuplicateObjects(t *testing.T) {
341342
tk.MustQuery("EXPLAIN WITH t AS (SELECT /*+ inl_join(e) */ em.* FROM t_employees em JOIN t_employees e WHERE em.store_id = e.department_id) SELECT * FROM t;")
342343
tk.MustQuery("show warnings").Check(testkit.Rows())
343344
}
345+
346+
func TestOptimizerCostFactorHints(t *testing.T) {
347+
// This test covers a subset of the cost factorst - using hints to increase the cost factor
348+
// of a specific plan type. The test is not exhaustive and does not cover all cost factors.
349+
store := testkit.CreateMockStore(t)
350+
351+
tk := testkit.NewTestKit(t, store)
352+
tk.MustExec("use test")
353+
tk.MustExec("drop table if exists t")
354+
tk.MustExec("create table t(a int, b int, c int, primary key (a), key(b))")
355+
// Insert some data
356+
tk.MustExec("insert into t values (1,1,1),(2,2,2),(3,3,3),(4,4,4),(5,5,5)")
357+
// Analyze table to update statistics
358+
tk.MustExec("analyze table t")
359+
360+
// Test tableFullScan cost factor increase via hint
361+
// Set index scan cost factor variable to isolate testing to TableFullScan
362+
tk.MustExec("set @@session.tidb_opt_index_scan_cost_factor=100")
363+
rs := tk.MustQuery("explain format=verbose select * from t").Rows()
364+
planCost1, err1 := strconv.ParseFloat(rs[0][2].(string), 64)
365+
require.Nil(t, err1)
366+
rs = tk.MustQuery("explain format=verbose select /*+ SET_VAR(tidb_opt_table_full_scan_cost_factor=2) */ * from t").Rows()
367+
planCost2, err2 := strconv.ParseFloat(rs[0][2].(string), 64)
368+
require.Nil(t, err2)
369+
// 1st query should be cheaper than 2nd query
370+
require.Less(t, planCost1, planCost2)
371+
// Reset to index scan to default
372+
tk.MustExec("set @@session.tidb_opt_index_scan_cost_factor=1")
373+
374+
// Test tableReader cost factor increase via hint
375+
// Set index scan cost factor variable to isolate testing to TableReader
376+
tk.MustExec("set @@session.tidb_opt_index_scan_cost_factor=100")
377+
rs = tk.MustQuery("explain format=verbose select * from t").Rows()
378+
planCost1, err1 = strconv.ParseFloat(rs[0][2].(string), 64)
379+
require.Nil(t, err1)
380+
rs = tk.MustQuery("explain format=verbose select /*+ SET_VAR(tidb_opt_table_reader_cost_factor=2) */ * from t").Rows()
381+
planCost2, err2 = strconv.ParseFloat(rs[0][2].(string), 64)
382+
require.Nil(t, err2)
383+
// 1st query should be cheaper than 2nd query
384+
require.Less(t, planCost1, planCost2)
385+
// Reset to index scan variable to default
386+
tk.MustExec("set @@session.tidb_opt_index_scan_cost_factor=1")
387+
388+
// Test tableRangeScan cost factor increase
389+
// Set index scan and table full scan cost factor variables to isolate testing to TableRangeScan
390+
tk.MustExec("set @@session.tidb_opt_index_scan_cost_factor=100")
391+
tk.MustExec("set @@session.tidb_opt_table_full_scan_cost_factor=100")
392+
rs = tk.MustQuery("explain format=verbose select * from t where a > 3").Rows()
393+
planCost1, err1 = strconv.ParseFloat(rs[0][2].(string), 64)
394+
require.Nil(t, err1)
395+
rs = tk.MustQuery("explain format=verbose select /*+ SET_VAR(tidb_opt_table_range_scan_cost_factor=2) */ * from t where a > 3").Rows()
396+
planCost2, err2 = strconv.ParseFloat(rs[0][2].(string), 64)
397+
require.Nil(t, err2)
398+
// 1st query should be cheaper than 2nd query
399+
require.Less(t, planCost1, planCost2)
400+
// Reset to index and table full scan variables to default
401+
tk.MustExec("set @@session.tidb_opt_index_scan_cost_factor=1")
402+
tk.MustExec("set @@session.tidb_opt_table_full_scan_cost_factor=1")
403+
404+
// Test IndexScan cost factor increase
405+
// Increase table scan cost factor to isolate testing to IndexScan
406+
tk.MustExec("set @@session.tidb_opt_table_full_scan_cost_factor=100")
407+
rs = tk.MustQuery("explain format=verbose select b from t where b > 3").Rows()
408+
planCost1, err1 = strconv.ParseFloat(rs[0][2].(string), 64)
409+
require.Nil(t, err1)
410+
rs = tk.MustQuery("explain format=verbose select /*+ SET_VAR(tidb_opt_index_scan_cost_factor=2) */ b from t where b > 3").Rows()
411+
planCost2, err2 = strconv.ParseFloat(rs[0][2].(string), 64)
412+
require.Nil(t, err2)
413+
// 1st query should be cheaper than 2nd query
414+
require.Less(t, planCost1, planCost2)
415+
// Reset table full scan variable to default
416+
tk.MustExec("set @@session.tidb_opt_table_full_scan_cost_factor=1")
417+
418+
// Test IndexReadercost factor increase
419+
// Increase table scan cost factor variable to isolate testing to IndexReader
420+
tk.MustExec("set @@session.tidb_opt_table_full_scan_cost_factor=100")
421+
rs = tk.MustQuery("explain format=verbose select b from t where b > 3").Rows()
422+
planCost1, err1 = strconv.ParseFloat(rs[0][2].(string), 64)
423+
require.Nil(t, err1)
424+
rs = tk.MustQuery("explain format=verbose select /*+ SET_VAR(tidb_opt_index_reader_cost_factor=2) */ b from t where b > 3").Rows()
425+
planCost2, err2 = strconv.ParseFloat(rs[0][2].(string), 64)
426+
require.Nil(t, err2)
427+
// 1st query should be cheaper than 2nd query
428+
require.Less(t, planCost1, planCost2)
429+
// Reset table scan cost factor variable to default
430+
tk.MustExec("set @@session.tidb_opt_table_full_scan_cost_factor=1")
431+
}

pkg/planner/core/plan_cost_ver2_test.go

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -673,7 +673,19 @@ func TestTiFlashCostFactors(t *testing.T) {
673673
require.Nil(t, err3)
674674
// 3rd query should be cheaper than 1st query
675675
require.Less(t, planCost3, planCost1)
676-
// Reset to default
676+
677+
// Reset TiFlash cost factor to default
677678
tk.MustExec("set @@session.tidb_opt_table_tiflash_scan_cost_factor=1")
679+
680+
// Test TiFlash cost factor increase via hint
681+
rs = tk.MustQuery("explain format=verbose select /*+ SET_VAR(tidb_opt_table_tiflash_scan_cost_factor=2) */ * from t").Rows()
682+
planCost4, err4 := strconv.ParseFloat(rs[0][2].(string), 64)
683+
require.Nil(t, err4)
684+
// 1st query should be cheaper than 4th query
685+
require.Less(t, planCost1, planCost4)
686+
687+
// Reset table scan cost factor to default
678688
tk.MustExec("set @@session.tidb_opt_table_full_scan_cost_factor=1")
689+
// Reset TiFlash cop to default
690+
tk.MustExec("set @@session.tidb_allow_tiflash_cop=OFF")
679691
}

pkg/sessionctx/variable/setvar_affect.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,23 @@ var isHintUpdatableVerified = map[string]struct{}{
5454
"tidb_opt_concurrency_factor": {},
5555
"tidb_opt_force_inline_cte": {},
5656
"tidb_opt_use_invisible_indexes": {},
57+
"tidb_opt_hash_agg_cost_factor": {},
58+
"tidb_opt_hash_join_cost_factor": {},
59+
"tidb_opt_index_join_cost_factor": {},
60+
"tidb_opt_index_lookup_cost_factor": {},
61+
"tidb_opt_index_merge_cost_factor": {},
62+
"tidb_opt_index_reader_cost_factor": {},
63+
"tidb_opt_index_scan_cost_factor": {},
64+
"tidb_opt_limit_cost_factor": {},
65+
"tidb_opt_merge_join_cost_factor": {},
66+
"tidb_opt_sort_cost_factor": {},
67+
"tidb_opt_stream_agg_cost_factor": {},
68+
"tidb_opt_table_full_scan_cost_factor": {},
69+
"tidb_opt_table_range_scan_cost_factor": {},
70+
"tidb_opt_table_reader_cost_factor": {},
71+
"tidb_opt_table_rowid_scan_cost_factor": {},
72+
"tidb_opt_table_tiflash_scan_cost_factor": {},
73+
"tidb_opt_topn_cost_factor": {},
5774
"tidb_index_join_batch_size": {},
5875
"tidb_index_lookup_size": {},
5976
"tidb_index_serial_scan_concurrency": {},

0 commit comments

Comments
 (0)