diff --git a/pkg/ccl/serverccl/statusccl/tenant_status_test.go b/pkg/ccl/serverccl/statusccl/tenant_status_test.go index e1a64ece7f7a..4f7e4299fdc2 100644 --- a/pkg/ccl/serverccl/statusccl/tenant_status_test.go +++ b/pkg/ccl/serverccl/statusccl/tenant_status_test.go @@ -439,6 +439,7 @@ VALUES (1, 10, 100), (2, 20, 200), (3, 30, 300) Exec(t, "SELECT * FROM test") // Record scan on secondary index. + // Note that this is an index join and will also read from the primary index. cluster.tenantConn(randomServer). Exec(t, "SELECT * FROM test@test_a_idx") testTableIDStr := cluster.tenantConn(randomServer). @@ -463,7 +464,7 @@ WHERE table_id = ` + testTableIDStr // Assert index usage data was inserted. expected := [][]string{ - {testTableIDStr, "1", "1", "true"}, + {testTableIDStr, "1", "2", "true"}, // Primary index {testTableIDStr, "2", "1", "true"}, } cluster.tenantConn(randomServer).CheckQueryResults(t, query, expected) @@ -771,6 +772,7 @@ VALUES (1, 10, 100), (2, 20, 200), (3, 30, 300) testingCluster.tenantConn(0).Exec(t, "SELECT * FROM idx_test.test") // Record scan on secondary index. + // Note that this is an index join and will also read from the primary index. testingCluster.tenantConn(1).Exec(t, "SELECT * FROM idx_test.test@test_a_idx") testTableIDStr := testingCluster.tenantConn(2).QueryStr(t, "SELECT 'idx_test.test'::regclass::oid")[0][0] testTableID, err := strconv.Atoi(testTableIDStr) @@ -789,7 +791,7 @@ WHERE ` actual := testingCluster.tenantConn(2).QueryStr(t, query, testTableID) expected := [][]string{ - {testTableIDStr, "1", "1", "true"}, + {testTableIDStr, "1", "2", "true"}, {testTableIDStr, "2", "1", "true"}, } diff --git a/pkg/server/index_usage_stats_test.go b/pkg/server/index_usage_stats_test.go index 7c7507d83f39..4f8b46a3768c 100644 --- a/pkg/server/index_usage_stats_test.go +++ b/pkg/server/index_usage_stats_test.go @@ -76,6 +76,11 @@ func TestStatusAPIIndexUsage(t *testing.T) { LastRead: timeutil.Now(), } + expectedStatsIndexPrimary := roachpb.IndexUsageStatistics{ + TotalReadCount: 1, + LastRead: timeutil.Now(), + } + firstPgURL, firstServerConnCleanup := sqlutils.PGUrl( t, firstServer.ServingSQLAddr(), "CreateConnections" /* prefix */, url.User(security.RootUser)) defer firstServerConnCleanup() @@ -111,6 +116,11 @@ func TestStatusAPIIndexUsage(t *testing.T) { require.NoError(t, err) require.False(t, rows.Next()) + indexKeyPrimary := roachpb.IndexUsageKey{ + TableID: roachpb.TableID(tableID), + IndexID: 1, // t@t_pkey + } + indexKeyA := roachpb.IndexUsageKey{ TableID: roachpb.TableID(tableID), IndexID: 2, // t@t_a_idx @@ -150,7 +160,7 @@ func TestStatusAPIIndexUsage(t *testing.T) { _, err = secondServerSQLConn.Exec("SELECT k FROM t WHERE a = 10 AND b = 200") require.NoError(t, err) - // Record a full scan over t_b_idx. + // Record an index join and full scan of t_b_idx. _, err = secondServerSQLConn.Exec("SELECT * FROM t@t_b_idx") require.NoError(t, err) @@ -164,13 +174,19 @@ func TestStatusAPIIndexUsage(t *testing.T) { thirdLocalStatsReader := thirdServer.SQLServer().(*sql.Server).GetLocalIndexStatistics() // First node should have nothing. - stats := firstLocalStatsReader.Get(indexKeyA.TableID, indexKeyA.IndexID) + stats := firstLocalStatsReader.Get(indexKeyPrimary.TableID, indexKeyPrimary.IndexID) + require.Equal(t, roachpb.IndexUsageStatistics{}, stats, "expecting empty stats on node 1, but found %v", stats) + + stats = firstLocalStatsReader.Get(indexKeyA.TableID, indexKeyA.IndexID) require.Equal(t, roachpb.IndexUsageStatistics{}, stats, "expecting empty stats on node 1, but found %v", stats) stats = firstLocalStatsReader.Get(indexKeyB.TableID, indexKeyB.IndexID) require.Equal(t, roachpb.IndexUsageStatistics{}, stats, "expecting empty stats on node 1, but found %v", stats) // Third node should have nothing. + stats = firstLocalStatsReader.Get(indexKeyPrimary.TableID, indexKeyPrimary.IndexID) + require.Equal(t, roachpb.IndexUsageStatistics{}, stats, "expecting empty stats on node 3, but found %v", stats) + stats = thirdLocalStatsReader.Get(indexKeyA.TableID, indexKeyA.IndexID) require.Equal(t, roachpb.IndexUsageStatistics{}, stats, "expecting empty stats on node 3, but found %v", stats) @@ -178,6 +194,9 @@ func TestStatusAPIIndexUsage(t *testing.T) { require.Equal(t, roachpb.IndexUsageStatistics{}, stats, "expecting empty stats on node 1, but found %v", stats) // Second server should have nonempty local storage. + stats = secondLocalStatsReader.Get(indexKeyPrimary.TableID, indexKeyPrimary.IndexID) + compareStatsHelper(t, expectedStatsIndexPrimary, stats, time.Minute) + stats = secondLocalStatsReader.Get(indexKeyA.TableID, indexKeyA.IndexID) compareStatsHelper(t, expectedStatsIndexA, stats, time.Minute) @@ -197,6 +216,8 @@ func TestStatusAPIIndexUsage(t *testing.T) { } statsEntries++ switch stats.Key.IndexID { + case indexKeyPrimary.IndexID: // t@t_pkey + compareStatsHelper(t, expectedStatsIndexPrimary, stats.Stats, time.Minute) case indexKeyA.IndexID: // t@t_a_idx compareStatsHelper(t, expectedStatsIndexA, stats.Stats, time.Minute) case indexKeyB.IndexID: // t@t_b_idx @@ -204,7 +225,7 @@ func TestStatusAPIIndexUsage(t *testing.T) { } } - require.True(t, statsEntries == 2, "expect to find two stats entries in RPC response, but found %d", statsEntries) + require.Equal(t, 3, statsEntries, "expect to find 3 stats entries in RPC response, but found %d", statsEntries) // Test disabling subsystem. _, err = secondServerSQLConn.Exec("SET CLUSTER SETTING sql.metrics.index_usage_stats.enabled = false") @@ -232,7 +253,7 @@ func TestStatusAPIIndexUsage(t *testing.T) { compareStatsHelper(t, expectedStatsIndexB, stats.Stats, time.Minute) } } - require.True(t, statsEntries == 2, "expect to find two stats entries in RPC response, but found %d", statsEntries) + require.Equal(t, 3, statsEntries, "expect to find 3 stats entries in RPC response, but found %d", statsEntries) } func TestGetTableID(t *testing.T) { diff --git a/pkg/sql/opt_exec_factory.go b/pkg/sql/opt_exec_factory.go index a65b2dd63f9a..77420dd3580d 100644 --- a/pkg/sql/opt_exec_factory.go +++ b/pkg/sql/opt_exec_factory.go @@ -610,9 +610,18 @@ func (ef *execFactory) ConstructIndexJoin( return nil, err } - tableScan.index = tabDesc.GetPrimaryIndex() + idx := tabDesc.GetPrimaryIndex() + tableScan.index = idx tableScan.disableBatchLimit() + if !ef.isExplain { + idxUsageKey := roachpb.IndexUsageKey{ + TableID: roachpb.TableID(tabDesc.GetID()), + IndexID: roachpb.IndexID(idx.GetID()), + } + ef.planner.extendedEvalCtx.indexUsageStats.RecordRead(idxUsageKey) + } + n := &indexJoinNode{ input: input.(planNode), table: tableScan,