Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merge release-3.0 to release-3.1 #14361

Merged
merged 71 commits into from
Jan 7, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
71 commits
Select commit Hold shift + click to select a range
e8e0fe9
planner/core: fix not null flag for using and natural join (#13735) (…
alivxxx Nov 26, 2019
bcf2f07
expression: fix the corner case of CAST int as unsigned real/decimal …
Deardrops Nov 27, 2019
1db38d5
expression : fix function 'binSearch' in builtinIntervalRealSig not …
sre-bot Nov 27, 2019
159c16d
fix single (#13563)
sre-bot Nov 27, 2019
16781a3
types: Fix potential timezone related bugs caused by `gotime.Local` (…
sre-bot Nov 28, 2019
84e4386
store/tikv: fix lockTTL too large if local time is behind timestamp (…
coocood Dec 3, 2019
599d1c4
ddl: update the error message of "modify/change column" to make it ea…
zimulala Dec 3, 2019
ab73fde
executor: fix data race in TestFastAnalyze (#12910) (#13872)
sre-bot Dec 4, 2019
251574b
privilege: using system session to execute internal sql of RBAC (#138…
Dec 5, 2019
b6a30b8
config: add configuration entry make TiDB version string configurable…
reafans Dec 5, 2019
050a356
*: support split partition table region (#12213) (#13929)
crazycs520 Dec 5, 2019
0201879
*: wait for binlog recovering when using HTTP API (#13740) (#13892)
jackysp Dec 6, 2019
cfbe06a
privilege: fix privilege check of `GRANT ROLE` (#13896) (#13932)
sre-bot Dec 6, 2019
c1624d8
planner/core: raise 'No database selected' error for grant statement …
tiancaiamao Dec 6, 2019
e4bcdd4
executor: fix inconsistent of grants privileges with MySQL when execu…
Dec 9, 2019
e329379
executor: report error in `AddRecordLD` function (#13980)
cfzjywxk Dec 10, 2019
9da133f
*: do not start slow-log timer before parsing (#13846) (#13898)
jackysp Dec 10, 2019
d006af9
bindinfo: fix bindinfo bugs when update cache (#13875) (#13891)
alivxxx Dec 10, 2019
969a020
executor: change pessimistic lock wait start for one statement (#13990)
cfzjywxk Dec 10, 2019
cba3e1a
planner: fixup some bugs with `DEFAULT` expression (#13168)(#13211)(#…
Deardrops Dec 11, 2019
35159fe
session: if txn invalid do not active it and return an error (#13935)…
jackysp Dec 11, 2019
ce88d7b
types: fix insert error when convert string to float (#13716) (#14011)
alivxxx Dec 11, 2019
3a10bb8
privilege: fix `REVOKE` privilege check incompatibility with MySQL (#…
sre-bot Dec 11, 2019
b10d1a5
store/tikv: fix a memory leak in the batchClient for the large transa…
sre-bot Dec 12, 2019
c31b745
stats: remove the lower bound of auto analyze ratio (#13995) (#14015)
alivxxx Dec 12, 2019
be7cb4d
bindinfo, planner: fix sql bind when sql has symbol list (#13889) (#1…
SunRunAway Dec 13, 2019
d312f8a
ddl: fix index length calculation (#13779)
sre-bot Dec 16, 2019
13b945d
*: lock unchanged rows for pessimistic transaction (#14045) (#14050)
coocood Dec 16, 2019
b9ba3ef
mocktikv: add the missing ConflictCommitTS (#14064) (#14080)
sre-bot Dec 16, 2019
5d5b071
executor: init the final recv channel of hash agg with enough chunk (…
winoros Dec 17, 2019
2ed7510
tikv: check lock timeout again after resolving lock (#14066) (#14083)
sticnarf Dec 17, 2019
a3ca490
executor: refine the check of onlyFullGroupBy when groupByItem is par…
XuHuaiyu Dec 17, 2019
9a103ef
server: set `system_time_zone` from `systemTZ` (#13934) (#14086)
bb7133 Dec 17, 2019
3ff5455
planner: fix bug for logical rule outer join elimination (#13947) (#1…
lzmhhh123 Dec 17, 2019
d0502a6
privilege: make 'grant all privileges' work right (#11449) (#14092)
lysu Dec 17, 2019
1866f27
table/tables: fix an error message when table has no partition for va…
sre-bot Dec 18, 2019
4d34a76
bindinfo: remove last semicolon of bind sqls (#14110) (#14113)
alivxxx Dec 18, 2019
7ea2a21
privilege: fix privilege check of `CREATE ROLE` and `DROP ROLE` (#139…
Dec 18, 2019
c598e4b
planner/core: add bit column test about display width range (#11985) …
tangenta Dec 18, 2019
f2ae63e
executor: add SHUTDOWN command and privilege check (#12804) (#14104)
lysu Dec 19, 2019
e4c2216
privilege: fix atomic problem of `DROP ROLE` (#14090) (#14130)
Dec 19, 2019
4cfaf04
planner: fix wrong stats for physical union scan (#14093) (#14133)
lzmhhh123 Dec 19, 2019
1c224aa
session: fix `show variable` result of `tidb_enable_window_function` …
sre-bot Dec 19, 2019
fda6d3b
gcworker: fix potential gcworker goroutine leak during tikv down (#13…
lysu Dec 19, 2019
1686c6b
ddl: fix ErrGCTooEarly when adding an index to the partition table (#…
sre-bot Dec 19, 2019
37b1d77
add binlog prewrite time to record binlog prewrite time consume (#14138)
cfzjywxk Dec 19, 2019
9efbf48
session: support 'GLOBAL SCOPE' for `tidb_enable_table_partition` (#1…
bb7133 Dec 20, 2019
b52cccd
*: revert #10124 and remove sql mode `PadCharToFullLength` (#14007) (…
winoros Dec 20, 2019
620a6c0
infoschema, util: Add more fields to table `events_statements_summary…
djshow832 Dec 20, 2019
c6c5fbf
infoschema, util: refresh statement summary table periodically (#1368…
djshow832 Dec 20, 2019
45c52c4
infoschema, util: add table `events_statements_summary_by_digest_hist…
djshow832 Dec 20, 2019
b47381b
infoschema: add 3 fields to statement summary table (#14096) (#14168)
djshow832 Dec 20, 2019
adbb8b9
set global variable tidb_txn_mode to pessimistic during bootstrap. (#…
sre-bot Dec 21, 2019
36e428e
*: fix condition check push down for pessimistic transaction (#14141)…
jackysp Dec 23, 2019
55a6b73
privilege: fix privilege problem after upgrade (#14177) (#14178)
Dec 23, 2019
70e025f
ddl: check foreign key constraint when drop,modify,change column (#14…
crazycs520 Dec 23, 2019
2f3f57a
executor: cherry-pick lock ctx to 3.0 (#14201)
cfzjywxk Dec 24, 2019
1a32e51
executor: add lock keys duration metric (#14194)
cfzjywxk Dec 24, 2019
da1427a
store/tikv: fix CheckStreamTimeoutLoop goroutine leak (#13812) (#14227)
SunRunAway Dec 25, 2019
4eb6c8e
executor: avoid `ProjectoinExec`'s goroutine leak (#14127) (#14226)
fzhedu Dec 26, 2019
eb355be
*: support certificate based authentication (#13955) (#14202)
lysu Dec 26, 2019
37f099d
server: add lock keys duration in slow log (#14246)
cfzjywxk Dec 26, 2019
90a37b9
fix missing register (#14256)
cfzjywxk Dec 27, 2019
6adce23
store/tikv: keepalive with pd (#14118) (#14233)
nolouch Dec 27, 2019
8f13cf1
executor: add rollback in `releaseSysSession` (#14272)
sre-bot Dec 27, 2019
64abbbd
ddl: fix the bug that VIEWs can be dropped by `DROP TABLE` syn… (#14052)
sre-bot Dec 28, 2019
1ee1b74
planner: support plan digest (#13124) (#14258)
crazycs520 Dec 30, 2019
d84aab8
infoschema: add plan digest to slow log and slow_query (#14000) (#14292)
crazycs520 Jan 1, 2020
e1d8b41
infoschema: add plan field to the statement summary tables (#14182) (…
sre-bot Jan 2, 2020
81d276e
server: log last executed prepared stmt when panic (#12905) (#14322)
lysu Jan 2, 2020
ed3a93b
Merge branch 'release-3.0' into release-3.1
bb7133 Jan 6, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 61 additions & 6 deletions bindinfo/bind_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ func (s *testSuite) SetUpSuite(c *C) {
session.SetSchemaLease(0)
session.DisableStats4Test()
}
bindinfo.Lease = 0
d, err := session.BootstrapSession(s.store)
c.Assert(err, IsNil)
d.SetStatsUpdating(true)
Expand All @@ -99,8 +100,8 @@ func (s *testSuite) TearDownTest(c *C) {
}

func (s *testSuite) cleanBindingEnv(tk *testkit.TestKit) {
tk.MustExec("drop table if exists mysql.bind_info")
tk.MustExec(session.CreateBindInfoTable)
tk.MustExec("truncate table mysql.bind_info")
s.domain.BindHandle().Clear()
}

func (s *testSuite) TestBindParse(c *C) {
Expand Down Expand Up @@ -166,7 +167,7 @@ func (s *testSuite) TestGlobalBinding(c *C) {
metrics.BindMemoryUsage.WithLabelValues(metrics.ScopeGlobal, bindinfo.Using).Write(pb)
c.Assert(pb.GetGauge().GetValue(), Equals, float64(161))

sql, hash := parser.NormalizeDigest("select * from t where i > ?")
sql, hash := parser.NormalizeDigest("select * from t where i > 30.0")

bindData := s.domain.BindHandle().GetBindRecord(hash, sql, "test")
c.Check(bindData, NotNil)
Expand Down Expand Up @@ -388,7 +389,7 @@ func (s *testSuite) TestExplain(c *C) {
tk.MustExec("create table t1(id int)")
tk.MustExec("create table t2(id int)")

tk.MustQuery("explain SELECT * from t1,t2 where t1.id = t2.id").Check(testkit.Rows(
tk.MustQuery("explain SELECT * from t1,t2 where t1.id = t2.id;").Check(testkit.Rows(
"HashLeftJoin_8 12487.50 root inner join, inner:TableReader_15, equal:[eq(test.t1.id, test.t2.id)]",
"├─TableReader_12 9990.00 root data:Selection_11",
"│ └─Selection_11 9990.00 cop not(isnull(test.t1.id))",
Expand All @@ -398,7 +399,7 @@ func (s *testSuite) TestExplain(c *C) {
" └─TableScan_13 10000.00 cop table:t2, range:[-inf,+inf], keep order:false, stats:pseudo",
))

tk.MustQuery("explain SELECT /*+ TIDB_SMJ(t1, t2) */ * from t1,t2 where t1.id = t2.id").Check(testkit.Rows(
tk.MustQuery("explain SELECT /*+ TIDB_SMJ(t1, t2) */ * from t1,t2 where t1.id = t2.id;").Check(testkit.Rows(
"MergeJoin_7 12487.50 root inner join, left key:test.t1.id, right key:test.t2.id",
"├─Sort_11 9990.00 root test.t1.id:asc",
"│ └─TableReader_10 9990.00 root data:Selection_9",
Expand All @@ -412,7 +413,7 @@ func (s *testSuite) TestExplain(c *C) {

tk.MustExec("create global binding for SELECT * from t1,t2 where t1.id = t2.id using SELECT /*+ TIDB_SMJ(t1, t2) */ * from t1,t2 where t1.id = t2.id")

tk.MustQuery("explain SELECT * from t1,t2 where t1.id = t2.id").Check(testkit.Rows(
tk.MustQuery("explain SELECT * from t1,t2 where t1.id = t2.id;").Check(testkit.Rows(
"MergeJoin_7 12487.50 root inner join, left key:test.t1.id, right key:test.t2.id",
"├─Sort_11 9990.00 root test.t1.id:asc",
"│ └─TableReader_10 9990.00 root data:Selection_9",
Expand All @@ -427,6 +428,42 @@ func (s *testSuite) TestExplain(c *C) {
tk.MustExec("drop global binding for SELECT * from t1,t2 where t1.id = t2.id")
}

// TestBindingSymbolList tests sql with "?, ?, ?, ?", fixes #13871
func (s *testSuite) TestBindingSymbolList(c *C) {
tk := testkit.NewTestKit(c, s.store)
s.cleanBindingEnv(tk)
tk.MustExec("use test")
tk.MustExec("drop table if exists t")
tk.MustExec("create table t(a int, b int, INDEX ia (a), INDEX ib (b));")
tk.MustExec("insert into t value(1, 1);")

// before binding
tk.MustQuery("select a, b from t where a = 3 limit 1, 100")
c.Assert(tk.Se.GetSessionVars().StmtCtx.IndexNames[0], Equals, "t:ia")
c.Assert(tk.MustUseIndex("select a, b from t where a = 3 limit 1, 100", "a"), IsTrue)

tk.MustExec(`create global binding for select a, b from t where a = 1 limit 0, 1 using select a, b from t use index (ib) where a = 1 limit 0, 1`)

// after binding
tk.MustQuery("select a, b from t where a = 3 limit 1, 100;")
c.Assert(tk.Se.GetSessionVars().StmtCtx.IndexNames[0], Equals, "t:ib")
c.Assert(tk.MustUseIndex("select a, b from t where a = 3 limit 1, 100", "b"), IsTrue)

// Normalize
sql, hash := parser.NormalizeDigest("select a, b from t where a = 1 limit 0, 1")

bindData := s.domain.BindHandle().GetBindRecord(hash, sql, "test")
c.Assert(bindData, NotNil)
c.Check(bindData.OriginalSQL, Equals, "select a , b from t where a = ? limit ...")
c.Check(bindData.BindSQL, Equals, "select a, b from t use index (ib) where a = 1 limit 0, 1")
c.Check(bindData.Db, Equals, "test")
c.Check(bindData.Status, Equals, "using")
c.Check(bindData.Charset, NotNil)
c.Check(bindData.Collation, NotNil)
c.Check(bindData.CreateTime, NotNil)
c.Check(bindData.UpdateTime, NotNil)
}

func (s *testSuite) TestErrorBind(c *C) {
tk := testkit.NewTestKit(c, s.store)
s.cleanBindingEnv(tk)
Expand Down Expand Up @@ -465,3 +502,21 @@ func (s *testSuite) TestErrorBind(c *C) {
c.Check(err, IsNil)
c.Check(chk.NumRows(), Equals, 0)
}

func (s *testSuite) TestBindingCache(c *C) {
tk := testkit.NewTestKit(c, s.store)
s.cleanBindingEnv(tk)
tk.MustExec("use test")
tk.MustExec("drop table if exists t")
tk.MustExec("create table t(a int, b int, index idx(a))")
tk.MustExec("create global binding for select * from t using select * from t use index(idx);")
tk.MustExec("create database tmp")
tk.MustExec("use tmp")
tk.MustExec("create table t(a int, b int, index idx(a))")
tk.MustExec("create global binding for select * from t using select * from t use index(idx);")

c.Assert(s.domain.BindHandle().Update(false), IsNil)
c.Assert(s.domain.BindHandle().Update(false), IsNil)
res := tk.MustQuery("show global bindings")
c.Assert(len(res.Rows()), Equals, 2)
}
21 changes: 16 additions & 5 deletions bindinfo/handle.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ package bindinfo
import (
"context"
"fmt"
"go.uber.org/zap"
"sync"
"sync/atomic"
"time"
Expand All @@ -31,6 +30,7 @@ import (
"github.com/pingcap/tidb/types"
"github.com/pingcap/tidb/util/logutil"
"github.com/pingcap/tidb/util/sqlexec"
"go.uber.org/zap"
)

// BindHandle is used to handle all global sql bind operations.
Expand Down Expand Up @@ -95,7 +95,7 @@ func NewBindHandle(ctx sessionctx.Context) *BindHandle {
func (h *BindHandle) Update(fullLoad bool) (err error) {
sql := "select original_sql, bind_sql, default_db, status, create_time, update_time, charset, collation from mysql.bind_info"
if !fullLoad {
sql += " where update_time >= \"" + h.lastUpdateTime.String() + "\""
sql += " where update_time > \"" + h.lastUpdateTime.String() + "\""
}

// No need to acquire the session context lock for ExecRestrictedSQL, it
Expand Down Expand Up @@ -304,7 +304,7 @@ func (h *BindHandle) GetAllBindRecord() (bindRecords []*BindMeta) {
}

func (h *BindHandle) newBindMeta(record *BindRecord) (hash string, meta *BindMeta, err error) {
hash = parser.DigestHash(record.OriginalSQL)
hash = parser.DigestNormalized(record.OriginalSQL)
stmtNodes, _, err := h.bindInfo.parser.Parse(record.BindSQL, record.Charset, record.Collation)
if err != nil {
return "", nil, err
Expand All @@ -314,7 +314,7 @@ func (h *BindHandle) newBindMeta(record *BindRecord) (hash string, meta *BindMet
}

func newBindMetaWithoutAst(record *BindRecord) (hash string, meta *BindMeta) {
hash = parser.DigestHash(record.OriginalSQL)
hash = parser.DigestNormalized(record.OriginalSQL)
meta = &BindMeta{BindRecord: record}
return hash, meta
}
Expand Down Expand Up @@ -358,6 +358,7 @@ func (c cache) removeDeletedBindMeta(hash string, meta *BindMeta, scope string)
}
}
}
c[hash] = metas
}

// removeStaleBindMetas removes all the stale BindMeta in the cache.
Expand All @@ -377,12 +378,15 @@ func (c cache) removeStaleBindMetas(hash string, meta *BindMeta, scope string) {
}
}
}
c[hash] = metas
}

func (c cache) copy() cache {
newCache := make(cache, len(c))
for k, v := range c {
newCache[k] = v
bindMetas := make([]*BindMeta, len(v))
copy(bindMetas, v)
newCache[k] = bindMetas
}
return newCache
}
Expand Down Expand Up @@ -445,3 +449,10 @@ func (h *BindHandle) logicalDeleteBindInfoSQL(normdOrigSQL, db string, updateTs
expression.Quote(normdOrigSQL),
expression.Quote(db))
}

// Clear resets the bind handle. It is used for test.
func (h *BindHandle) Clear() {
h.bindInfo.Store(make(cache))
h.invalidBindRecordMap.Store(make(map[string]*invalidBindRecordMap))
h.lastUpdateTime = types.ZeroTimestamp
}
6 changes: 3 additions & 3 deletions bindinfo/session_handle.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ func (h *SessionHandle) appendBindMeta(hash string, meta *BindMeta) {
}

func (h *SessionHandle) newBindMeta(record *BindRecord) (hash string, meta *BindMeta, err error) {
hash = parser.DigestHash(record.OriginalSQL)
hash = parser.DigestNormalized(record.OriginalSQL)
stmtNodes, _, err := h.parser.Parse(record.BindSQL, record.Charset, record.Collation)
if err != nil {
return "", nil, err
Expand Down Expand Up @@ -75,14 +75,14 @@ func (h *SessionHandle) AddBindRecord(record *BindRecord) error {
func (h *SessionHandle) DropBindRecord(record *BindRecord) {
meta := &BindMeta{BindRecord: record}
meta.Status = deleted
hash := parser.DigestHash(record.OriginalSQL)
hash := parser.DigestNormalized(record.OriginalSQL)
h.ch.removeDeletedBindMeta(hash, meta, metrics.ScopeSession)
h.appendBindMeta(hash, meta)
}

// GetBindRecord return the BindMeta of the (normdOrigSQL,db) if BindMeta exist.
func (h *SessionHandle) GetBindRecord(normdOrigSQL, db string) *BindMeta {
hash := parser.DigestHash(normdOrigSQL)
hash := parser.DigestNormalized(normdOrigSQL)
bindRecords := h.ch[hash]
if bindRecords != nil {
for _, bindRecord := range bindRecords {
Expand Down
31 changes: 31 additions & 0 deletions cmd/explaintest/r/explain_easy.result
Original file line number Diff line number Diff line change
Expand Up @@ -489,6 +489,37 @@ explain select distinct t1.a, t1.b from t1 left outer join t2 on t1.a = t2.a;
id count task operator info
IndexReader_9 10000.00 root index:IndexScan_8
└─IndexScan_8 10000.00 cop table:t1, index:a, b, range:[NULL,+inf], keep order:false, stats:pseudo
CREATE TABLE `test01` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`stat_date` int(11) NOT NULL DEFAULT '0',
`show_date` varchar(20) NOT NULL DEFAULT '',
`region_id` bigint(20) unsigned NOT NULL DEFAULT '0',
`period` tinyint(3) unsigned NOT NULL DEFAULT '0',
`registration_num` bigint(20) unsigned NOT NULL DEFAULT '0',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
CREATE TABLE `test02` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`region_name` varchar(128) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
EXPLAIN SELECT COUNT(1) FROM (SELECT COALESCE(b.region_name, '不详') region_name, SUM(a.registration_num) registration_num FROM (SELECT stat_date, show_date, region_id, 0 registration_num FROM test01 WHERE period = 1 AND stat_date >= 20191202 AND stat_date <= 20191202 UNION ALL SELECT stat_date, show_date, region_id, registration_num registration_num FROM test01 WHERE period = 1 AND stat_date >= 20191202 AND stat_date <= 20191202) a LEFT JOIN test02 b ON a.region_id = b.id WHERE registration_num > 0 AND a.stat_date >= '20191202' AND a.stat_date <= '20191202' GROUP BY a.stat_date , a.show_date , COALESCE(b.region_name, '不详') ) JLS;
id count task operator info
StreamAgg_22 1.00 root funcs:count(1)
└─HashAgg_25 1.00 root group by:col_0, col_1, col_2, funcs:firstrow(1)
└─Projection_41 0.01 root a.stat_date, a.show_date, coalesce(test.b.region_name, "不详")
└─IndexJoin_28 0.01 root left outer join, inner:TableReader_27, outer key:a.region_id, inner key:test.b.id
├─Union_30 0.01 root
│ ├─Projection_31 0.00 root test.test01.stat_date, test.test01.show_date, test.test01.region_id, cast(registration_num)
│ │ └─Projection_32 0.00 root test.test01.stat_date, test.test01.show_date, test.test01.region_id, 0
│ │ └─TableDual_33 0.00 root rows:0
│ └─Projection_34 0.01 root test.test01.stat_date, test.test01.show_date, test.test01.region_id, cast(test.test01.registration_num)
│ └─Selection_35 0.01 root gt(cast(test.test01.registration_num), 0)
│ └─TableReader_38 0.01 root data:Selection_37
│ └─Selection_37 0.01 cop eq(test.test01.period, 1), ge(test.test01.stat_date, 20191202), ge(test.test01.stat_date, 20191202), le(test.test01.stat_date, 20191202), le(test.test01.stat_date, 20191202)
│ └─TableScan_36 10000.00 cop table:test01, range:[-inf,+inf], keep order:false, stats:pseudo
└─TableReader_27 1.00 root data:TableScan_26
└─TableScan_26 1.00 cop table:b, range: decided by [a.region_id], keep order:false, stats:pseudo
drop table if exists t;
create table t(a int, nb int not null, nc int not null);
explain select ifnull(a, 0) from t;
Expand Down
32 changes: 32 additions & 0 deletions cmd/explaintest/r/explain_union_scan.result
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
drop table if exists city;
CREATE TABLE `city` (
`id` varchar(70) NOT NULL,
`province_id` int(15) DEFAULT NULL,
`city_name` varchar(90) DEFAULT NULL,
`description` varchar(90) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
load stats "s/explain_union_scan.json";
insert into city values("06766b3ef41d484d8878606393f1ed0b", 88, "chongqing", "chongqing city");
begin;
update city set province_id = 77 where id="06766b3ef41d484d8878606393f1ed0b";
explain select t1.*, t2.province_id as provinceID, t2.city_name as cityName, t3.description as description from city t1 inner join city t2 on t1.id = t2.id left join city t3 on t1.province_id = t3.province_id where t1.province_id > 1 and t1.province_id < 100 limit 10;
id count task operator info
Projection_17 10.00 root test.t1.id, test.t1.province_id, test.t1.city_name, test.t1.description, test.t2.province_id, test.t2.city_name, test.t3.description
└─Limit_20 10.00 root offset:0, count:10
└─HashLeftJoin_21 10.00 root left outer join, inner:UnionScan_52, equal:[eq(test.t1.province_id, test.t3.province_id)]
├─Limit_24 10.00 root offset:0, count:10
│ └─IndexJoin_29 10.00 root inner join, inner:UnionScan_28, outer key:test.t1.id, inner key:test.t2.id
│ ├─UnionScan_38 10.00 root gt(test.t1.province_id, 1), lt(test.t1.province_id, 100)
│ │ └─TableReader_41 10.00 root data:Selection_40
│ │ └─Selection_40 10.00 cop gt(test.t1.province_id, 1), lt(test.t1.province_id, 100)
│ │ └─TableScan_39 14.30 cop table:t1, range:[-inf,+inf], keep order:false
│ └─UnionScan_28 1.00 root
│ └─IndexLookUp_27 1.00 root
│ ├─IndexScan_25 1.00 cop table:t2, index:id, range: decided by [eq(test.t2.id, test.t1.id)], keep order:false
│ └─TableScan_26 1.00 cop table:t2, keep order:false
└─UnionScan_52 519304.44 root gt(test.t3.province_id, 1), lt(test.t3.province_id, 100), not(isnull(test.t3.province_id))
└─TableReader_55 519304.44 root data:Selection_54
└─Selection_54 519304.44 cop gt(test.t3.province_id, 1), lt(test.t3.province_id, 100), not(isnull(test.t3.province_id))
└─TableScan_53 536284.00 cop table:t3, range:[-inf,+inf], keep order:false
commit;
Loading