@@ -16,6 +16,7 @@ package hint
16
16
17
17
import (
18
18
"context"
19
+ "strconv"
19
20
"testing"
20
21
21
22
"github.com/pingcap/tidb/pkg/domain"
@@ -341,3 +342,90 @@ func TestQBHintHandlerDuplicateObjects(t *testing.T) {
341
342
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;" )
342
343
tk .MustQuery ("show warnings" ).Check (testkit .Rows ())
343
344
}
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
+ }
0 commit comments