-
Notifications
You must be signed in to change notification settings - Fork 6.1k
bindinfo: add last_used_date to track bindinfo usage frequency #63409
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
Changes from 15 commits
3b1610f
8860469
c51fe2f
ba0b7c0
466d5cf
176622b
6df8205
7462747
1a952d7
36db6d1
8eb3832
cf3d5a7
6678bef
6f7e7a8
6ea1f17
619bb27
9c66aeb
5d760ec
01bc626
fe9c4f5
ff9e3a9
fedfd53
a1ee5d1
7a7835f
78f6098
c88e475
f8dbbfe
4c8b1d2
a45b570
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,126 @@ | ||
| // Copyright 2025 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 tests | ||
|
|
||
| import ( | ||
| "testing" | ||
| "time" | ||
|
|
||
| "github.com/pingcap/tidb/pkg/bindinfo" | ||
| "github.com/pingcap/tidb/pkg/testkit" | ||
| "github.com/stretchr/testify/require" | ||
| ) | ||
|
|
||
| func TestBindUsageInfo(t *testing.T) { | ||
hawkingrei marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| checklist := []string{ | ||
| "5ce1df6eadf8b24222668b1bd2e995b72d4c88e6fe9340d8b13e834703e28c32", | ||
| "5d3975ef2160c1e0517353798dac90a9914095d82c025e7cd97bd55aeb804798", | ||
| "9d3995845aef70ba086d347f38a4e14c9705e966f7c5793b9fa92194bca2bbef", | ||
| "aa3c510b94b9d680f729252ca88415794c8a4f52172c5f9e06c27bee57d08329", | ||
| } | ||
| bindinfo.UpdateBindingUsageInfoBatchSize = 2 | ||
| bindinfo.MaxWriteInterval = 100 * time.Microsecond | ||
| store, dom := testkit.CreateMockStoreAndDomain(t) | ||
| bindingHandle := dom.BindingHandle() | ||
| tk := testkit.NewTestKit(t, store) | ||
|
|
||
| tk.MustExec(`use test`) | ||
| tk.MustExec(`set @@tidb_opt_enable_fuzzy_binding=1`) | ||
| tk.MustExec("create table t1(a int, b int, c int, key idx_b(b), key idx_c(c))") | ||
| tk.MustExec("create table t2(a int, b int, c int, key idx_b(b), key idx_c(c))") | ||
| tk.MustExec("create table t3(a int, b int, c int, key idx_b(b), key idx_c(c))") | ||
| tk.MustExec("create table t4(a int, b int, c int, key idx_b(b), key idx_c(c))") | ||
| tk.MustExec("create table t5(a int, b int, c int, key idx_b(b), key idx_c(c))") | ||
|
|
||
| tk.MustExec("prepare stmt1 from 'delete from t1 where b = 1 and c > 1';") | ||
| tk.MustExec("prepare stmt2 from 'delete t1, t2 from t1 inner join t2 on t1.b = t2.b';") | ||
| tk.MustExec("prepare stmt3 from 'update t1 set a = 1 where b = 1 and c > 1';") | ||
| tk.MustExec("execute stmt1;") | ||
| tk.MustExec("create global binding for delete from t1 where b = 1 and c > 1 using delete /*+ use_index(t1,idx_c) */ from t1 where b = 1 and c > 1") | ||
| tk.MustExec("create global binding for delete t1, t2 from t1 inner join t2 on t1.b = t2.b using delete /*+ inl_join(t1) */ t1, t2 from t1 inner join t2 on t1.b = t2.b") | ||
| tk.MustExec("create global binding for update t1 set a = 1 where b = 1 and c > 1 using update /*+ use_index(t1,idx_c) */ t1 set a = 1 where b = 1 and c > 1") | ||
| // corss database binding | ||
hawkingrei marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| tk.MustExec(`create global binding using select /*+ leading(t1, t2, t3, t4, t5) */ * from *.t1, *.t2, *.t3, *.t4, *.t5`) | ||
| tk.MustExec("select * from t1, t2, t3, t4, t5") | ||
| tk.MustExec("execute stmt1;") | ||
| origin := tk.MustQuery(`select sql_digest,last_used_date from mysql.bind_info where original_sql != 'builtin_pseudo_sql_for_bind_lock' order by sql_digest`) | ||
hawkingrei marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
hawkingrei marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| origin.Check(testkit.Rows( | ||
| "5ce1df6eadf8b24222668b1bd2e995b72d4c88e6fe9340d8b13e834703e28c32 <nil>", | ||
| "5d3975ef2160c1e0517353798dac90a9914095d82c025e7cd97bd55aeb804798 <nil>", | ||
| "9d3995845aef70ba086d347f38a4e14c9705e966f7c5793b9fa92194bca2bbef <nil>", | ||
| "aa3c510b94b9d680f729252ca88415794c8a4f52172c5f9e06c27bee57d08329 <nil>")) | ||
| time.Sleep(50 * time.Microsecond) | ||
| require.NoError(t, bindingHandle.UpdateBindingUsageInfoToStorage()) | ||
| result := tk.MustQuery(`select sql_digest,last_used_date from mysql.bind_info where original_sql != 'builtin_pseudo_sql_for_bind_lock' order by sql_digest`) | ||
hawkingrei marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| t.Log("result:", result.Rows()) | ||
| // The last_used_date should be updated. | ||
| require.True(t, !origin.Equal(result.Rows())) | ||
| var last *testkit.Result | ||
| for idx := range 5 { | ||
| bindinfo.UpdateBindingUsageInfoBatchSize = max(1, idx) | ||
| tk.MustExec("execute stmt1;") | ||
| tk.MustExec("execute stmt2;") | ||
| tk.MustExec("execute stmt3;") | ||
| tk.MustExec("select * from t1, t2, t3, t4, t5") | ||
| time.Sleep(1 * time.Second) | ||
| // Set all last_used_date to null to simulate that the bindinfo in storage is not updated. | ||
| tk.MustExec(`update mysql.bind_info set last_used_date = null where original_sql != 'builtin_pseudo_sql_for_bind_lock'`) | ||
| require.NoError(t, bindingHandle.UpdateBindingUsageInfoToStorage()) | ||
| checkBindinfoInMemory(t, bindingHandle, checklist) | ||
| tk.MustQuery(`select last_used_date from mysql.bind_info where original_sql != 'builtin_pseudo_sql_for_bind_lock' and last_used_date is null`).Check(testkit.Rows()) | ||
| result := tk.MustQuery(`select sql_digest,last_used_date from mysql.bind_info where original_sql != 'builtin_pseudo_sql_for_bind_lock' order by sql_digest`) | ||
| t.Log("result:", result.Rows()) | ||
| if last == nil { | ||
| last = result | ||
| } else { | ||
| require.True(t, last.Equal(result.Rows())) | ||
| } | ||
|
||
| } | ||
| // Set all last_used_date to null to simulate that the bindinfo in storage is not updated. | ||
| tk.MustExec(`update mysql.bind_info set last_used_date = null where original_sql != 'builtin_pseudo_sql_for_bind_lock'`) | ||
| for idx := range 5 { | ||
| bindinfo.UpdateBindingUsageInfoBatchSize = max(1, idx) | ||
| time.Sleep(1 * time.Second) | ||
| // No used, so last_used_date should not be updated. | ||
| require.NoError(t, bindingHandle.UpdateBindingUsageInfoToStorage()) | ||
| tk.MustQuery(`select last_used_date from mysql.bind_info where last_used_date is not null`).Check(testkit.Rows()) | ||
| } | ||
| tk.MustExec("execute stmt1;") | ||
| tk.MustExec("execute stmt2;") | ||
| tk.MustExec("execute stmt3;") | ||
| tk.MustExec(`delete from mysql.bind_info where original_sql != 'builtin_pseudo_sql_for_bind_lock'`) | ||
hawkingrei marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| // Alought we execute the stmts, but we set a very long interval, so last_used_date should not be updated. | ||
hawkingrei marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| require.NoError(t, bindingHandle.UpdateBindingUsageInfoToStorage()) | ||
| tk.MustQuery(`select * from mysql.bind_info where original_sql != 'builtin_pseudo_sql_for_bind_lock'`).Check(testkit.Rows()) | ||
| tk.MustExec("execute stmt1;") | ||
| tk.MustExec("execute stmt2;") | ||
| tk.MustExec("execute stmt3;") | ||
| tk.MustExec("select * from t1, t2, t3, t4, t5") | ||
| time.Sleep(1 * time.Second) | ||
| require.NoError(t, bindingHandle.UpdateBindingUsageInfoToStorage()) | ||
| // it has been updated again. | ||
| tk.MustQuery(`select * from mysql.bind_info where original_sql != 'builtin_pseudo_sql_for_bind_lock' and last_used_date is null`).Check(testkit.Rows()) | ||
| } | ||
|
|
||
| func checkBindinfoInMemory(t *testing.T, bindingHandle bindinfo.BindingHandle, checklist []string) { | ||
| for _, digest := range checklist { | ||
| binding := bindingHandle.GetBinding(digest) | ||
| require.NotNil(t, binding) | ||
| lastSaved := binding.UsageInfo.LastSavedAt.Load() | ||
| if lastSaved != nil { | ||
| require.GreaterOrEqual(t, *binding.UsageInfo.LastSavedAt.Load(), *binding.UsageInfo.LastUsedAt.Load()) | ||
| } | ||
| } | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.