This is an automated email from the ASF dual-hosted git repository.

jt2594838 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/iotdb.git


The following commit(s) were added to refs/heads/master by this push:
     new 6be80261199 Supported "need last cache" semantic for table/database 
schema (#15538)
6be80261199 is described below

commit 6be80261199331b045e2e9527f77c410fd1a4add
Author: Caideyipi <[email protected]>
AuthorDate: Mon Aug 24 12:29:50 2026 +0800

    Supported "need last cache" semantic for table/database schema (#15538)
    
    * partial
    
    * Partial
    
    * Update confignode.thrift
    
    * table schema
    
    * Update CreateTableProcedure.java
    
    * Partial
    
    * Update ConfigMTree.java
    
    * Update confignode.thrift
    
    * Partial
    
    * Update ShowCreateTableTask.java
    
    * Update ShowCreateViewTask.java
    
    * partial
    
    * Update InformationSchemaUtils.java
    
    * Partial
    
    * Partial
    
    * Partial
    
    * partial
    
    * Update IdentifierParser.g4
    
    * partial
    
    * Partial
    
    * Update IoTDBTableIT.java
    
    * Update IoTDBDatabaseIT.java
    
    * Update IoTDBDatabaseIT.java
    
    * Update IoTDBTableIT.java
    
    * Refactor
    
    * partial
    
    * Update PartitionCache.java
    
    * Update PartitionCache.java
    
    * Partial
    
    * Partial
    
    * Update IoTDBTableIT.java
    
    * Update IoTDBTableIT.java
    
    * Fix
    
    * fix-merge
    
    * fix
    
    * fix
    
    * fix
    
    * IT-fix
    
    * Update IoTDBDatabaseIT.java
    
    * fix
    
    * fix
    
    * fix
    
    * fix
    
    * Fix show create table last cache expectation
    
    * Added tests
    
    * Clear last cache when disabling need_last_cache
    
    * Fix need_last_cache handling
    
    * Fix table device schema cache test isolation
---
 .../relational/it/schema/IoTDBDatabaseIT.java      | 125 ++++++++++----
 .../iotdb/relational/it/schema/IoTDBTableIT.java   | 125 +++++++++++++-
 iotdb-client/client-cpp/examples/README.md         |   4 +-
 iotdb-client/client-cpp/examples/README_zh.md      |   4 +-
 .../org/apache/iotdb/db/qp/sql/IdentifierParser.g4 |   1 +
 .../org/apache/iotdb/db/qp/sql/IoTDBSqlParser.g4   |   1 +
 .../antlr4/org/apache/iotdb/db/qp/sql/SqlLexer.g4  |   4 +
 .../iotdb/confignode/i18n/ConfigNodeMessages.java  |   3 +
 .../iotdb/confignode/i18n/ConfigNodeMessages.java  |   3 +
 .../manager/schema/ClusterSchemaManager.java       |  76 ++++++++-
 .../persistence/schema/ClusterSchemaInfo.java      |  20 +++
 .../confignode/persistence/schema/ConfigMTree.java |   5 +
 .../impl/schema/table/CreateTableProcedure.java    |   4 +
 .../table/view/CreateTableViewProcedure.java       |   9 +
 .../manager/ClusterSchemaManagerTest.java          |  15 ++
 .../InformationSchemaContentSupplierFactory.java   |   3 +
 .../plan/analyze/ClusterPartitionFetcher.java      |   4 +
 .../plan/analyze/IPartitionFetcher.java            |   2 +
 .../analyze/cache/partition/PartitionCache.java    |  81 +++++++--
 .../execution/config/TableConfigTaskVisitor.java   |  69 ++++++--
 .../config/metadata/DatabaseSchemaTask.java        |   3 +
 .../metadata/relational/AbstractDatabaseTask.java  |   1 +
 .../metadata/relational/ShowCreateTableTask.java   |   8 +-
 .../config/metadata/relational/ShowDBTask.java     |   1 +
 .../metadata/relational/ShowTablesDetailsTask.java |   3 +
 .../db/queryengine/plan/parser/ASTVisitor.java     |   7 +
 .../relational/metadata/TableMetadataImpl.java     |   2 +
 .../fetcher/cache/TableDeviceSchemaCache.java      |  38 ++++-
 .../cache/TreeDeviceSchemaCacheManager.java        |   9 +
 .../metadata/DatabaseSchemaStatement.java          |  15 ++
 .../statement/metadata/ShowDatabaseStatement.java  |   1 +
 .../db/schemaengine/table/DataNodeTableCache.java  |  21 +++
 .../schemaengine/table/InformationSchemaUtils.java |   4 +-
 .../cache/TreeDeviceSchemaCacheManagerTest.java    |  29 ++++
 .../plan/analyze/cache/PartitionCacheTest.java     |  31 +++-
 .../config/metadata/DatabaseSchemaTaskTest.java    |  57 +++++++
 .../fetcher/cache/TableDeviceSchemaCacheTest.java  | 184 ++++++++++++++++++---
 .../schema/column/ColumnHeaderConstant.java        |  11 +-
 .../commons/schema/table/InformationSchema.java    |   8 +
 .../iotdb/commons/schema/table/TreeViewSchema.java |   2 +
 .../apache/iotdb/commons/schema/table/TsTable.java |  26 ++-
 .../src/main/thrift/confignode.thrift              |   3 +
 42 files changed, 913 insertions(+), 109 deletions(-)

diff --git 
a/integration-test/src/test/java/org/apache/iotdb/relational/it/schema/IoTDBDatabaseIT.java
 
b/integration-test/src/test/java/org/apache/iotdb/relational/it/schema/IoTDBDatabaseIT.java
index a6124c547a6..3d24915c1fe 100644
--- 
a/integration-test/src/test/java/org/apache/iotdb/relational/it/schema/IoTDBDatabaseIT.java
+++ 
b/integration-test/src/test/java/org/apache/iotdb/relational/it/schema/IoTDBDatabaseIT.java
@@ -113,6 +113,7 @@ public class IoTDBDatabaseIT {
 
       statement.execute("alter database if exists test1 set properties 
ttl='INF'");
       statement.execute("alter database test set properties ttl=default");
+      statement.execute("alter database test set properties 
need_last_cache=false");
 
       String[] databaseNames = new String[] {"test"};
       String[] TTLs = new String[] {"INF"};
@@ -171,6 +172,7 @@ public class IoTDBDatabaseIT {
           assertTrue(resultSet.getInt(7) >= defaultSchemaRegionGroupNum[cnt]);
           assertEquals(dataRegionGroupNum[cnt], resultSet.getInt(8));
           assertTrue(resultSet.getInt(9) >= defaultDataRegionGroupNum[cnt]);
+          assertFalse(resultSet.getBoolean(10));
           cnt++;
         }
         assertEquals(databaseNames.length, cnt);
@@ -321,6 +323,37 @@ public class IoTDBDatabaseIT {
     }
   }
 
+  @Test
+  public void testNeedLastCacheDatabaseProperty() throws SQLException {
+    try (final Connection connection =
+            EnvFactory.getEnv().getConnection(BaseEnv.TABLE_SQL_DIALECT);
+        final Statement statement = connection.createStatement()) {
+      statement.execute("create database need_cache_false with 
(need_last_cache=false)");
+      statement.execute("create database need_cache_default");
+
+      assertDatabaseNeedLastCache(statement, "need_cache_false", false);
+      assertDatabaseNeedLastCache(statement, "need_cache_default", true);
+
+      statement.execute("alter database need_cache_false set properties 
need_last_cache=true");
+      assertDatabaseNeedLastCache(statement, "need_cache_false", true);
+
+      statement.execute("alter database need_cache_false set properties 
need_last_cache=false");
+      assertDatabaseNeedLastCache(statement, "need_cache_false", false);
+
+      statement.execute("alter database need_cache_false set properties 
need_last_cache=default");
+      assertDatabaseNeedLastCache(statement, "need_cache_false", true);
+
+      try {
+        statement.execute("create database need_cache_invalid with 
(need_last_cache=1)");
+        fail("non-boolean need_last_cache should be rejected");
+      } catch (final SQLException e) {
+        assertEquals(
+            "701: need_last_cache value must be a BooleanLiteral, but now is 
LongLiteral, value: 1",
+            e.getMessage());
+      }
+    }
+  }
+
   @Test
   public void testShowCreatePipe() throws SQLException {
     try (final Connection connection =
@@ -346,6 +379,30 @@ public class IoTDBDatabaseIT {
     }
   }
 
+  private static void assertDatabaseNeedLastCache(
+      final Statement statement, final String database, final boolean expected)
+      throws SQLException {
+    try (final ResultSet resultSet = statement.executeQuery("SHOW DATABASES 
DETAILS")) {
+      boolean found = false;
+      while (resultSet.next()) {
+        if (!database.equals(resultSet.getString("Database"))) {
+          continue;
+        }
+        found = true;
+        assertEquals(expected, resultSet.getBoolean("NeedLastCache"));
+      }
+      assertTrue(found);
+    }
+
+    TestUtils.assertResultSetEqual(
+        statement.executeQuery(
+            "select database, need_last_cache from 
information_schema.databases where database = '"
+                + database
+                + "'"),
+        "database,need_last_cache,",
+        Collections.singleton(database + "," + expected + ","));
+  }
+
   private static void assertShowCreateSystemDatabaseFails(
       final Statement statement, final String database) throws SQLException {
     try {
@@ -503,7 +560,8 @@ public class IoTDBDatabaseIT {
                   "schema_region_group_num,INT32,ATTRIBUTE,",
                   "max_schema_region_group_num,INT32,ATTRIBUTE,",
                   "data_region_group_num,INT32,ATTRIBUTE,",
-                  "max_data_region_group_num,INT32,ATTRIBUTE,")));
+                  "max_data_region_group_num,INT32,ATTRIBUTE,",
+                  "need_last_cache,BOOLEAN,ATTRIBUTE,")));
       TestUtils.assertResultSetEqual(
           statement.executeQuery("desc tables"),
           "ColumnName,DataType,Category,",
@@ -514,7 +572,8 @@ public class IoTDBDatabaseIT {
                   "ttl(ms),STRING,ATTRIBUTE,",
                   "status,STRING,ATTRIBUTE,",
                   "comment,STRING,ATTRIBUTE,",
-                  "table_type,STRING,ATTRIBUTE,")));
+                  "table_type,STRING,ATTRIBUTE,",
+                  "need_last_cache,BOOLEAN,ATTRIBUTE,")));
       TestUtils.assertResultSetEqual(
           statement.executeQuery("desc columns"),
           "ColumnName,DataType,Category,",
@@ -727,6 +786,7 @@ public class IoTDBDatabaseIT {
             for (int columnIndex = 3; columnIndex <= 9; columnIndex++) {
               assertNull(resultSet.getObject(columnIndex));
             }
+            assertFalse(resultSet.getBoolean(10));
           } else {
             assertEquals("test", resultSet.getString(1));
             assertEquals("INF", resultSet.getString(2));
@@ -737,6 +797,7 @@ public class IoTDBDatabaseIT {
             assertTrue(resultSet.getInt(7) >= 1);
             assertEquals(0, resultSet.getInt(8));
             assertTrue(resultSet.getInt(9) >= 2);
+            assertTrue(resultSet.getBoolean(10));
           }
           cnt++;
         }
@@ -744,32 +805,32 @@ public class IoTDBDatabaseIT {
       }
       TestUtils.assertResultSetEqual(
           statement.executeQuery("show devices from tables where status = 
'USING'"),
-          "database,table_name,ttl(ms),status,comment,table_type,",
+          
"database,table_name,ttl(ms),status,comment,table_type,need_last_cache,",
           new HashSet<>(
               Arrays.asList(
-                  "information_schema,databases,INF,USING,null,SYSTEM VIEW,",
-                  "information_schema,tables,INF,USING,null,SYSTEM VIEW,",
-                  "information_schema,columns,INF,USING,null,SYSTEM VIEW,",
-                  "information_schema,queries,INF,USING,null,SYSTEM VIEW,",
-                  "information_schema,regions,INF,USING,null,SYSTEM VIEW,",
-                  "information_schema,topics,INF,USING,null,SYSTEM VIEW,",
-                  "information_schema,pipe_plugins,INF,USING,null,SYSTEM 
VIEW,",
-                  "information_schema,pipes,INF,USING,null,SYSTEM VIEW,",
-                  "information_schema,services,INF,USING,null,SYSTEM VIEW,",
-                  "information_schema,subscriptions,INF,USING,null,SYSTEM 
VIEW,",
-                  "information_schema,views,INF,USING,null,SYSTEM VIEW,",
-                  "information_schema,functions,INF,USING,null,SYSTEM VIEW,",
-                  "information_schema,configurations,INF,USING,null,SYSTEM 
VIEW,",
-                  "information_schema,keywords,INF,USING,null,SYSTEM VIEW,",
-                  "information_schema,nodes,INF,USING,null,SYSTEM VIEW,",
-                  "information_schema,table_disk_usage,INF,USING,null,SYSTEM 
VIEW,",
-                  "information_schema,config_nodes,INF,USING,null,SYSTEM 
VIEW,",
-                  "information_schema,data_nodes,INF,USING,null,SYSTEM VIEW,",
-                  "information_schema,connections,INF,USING,null,SYSTEM VIEW,",
-                  "information_schema,current_queries,INF,USING,null,SYSTEM 
VIEW,",
-                  
"information_schema,queries_costs_histogram,INF,USING,null,SYSTEM VIEW,",
-                  "test,test,INF,USING,test,BASE TABLE,",
-                  "test,view_table,100,USING,null,VIEW FROM TREE,")));
+                  "information_schema,databases,INF,USING,null,SYSTEM 
VIEW,false,",
+                  "information_schema,tables,INF,USING,null,SYSTEM 
VIEW,false,",
+                  "information_schema,columns,INF,USING,null,SYSTEM 
VIEW,false,",
+                  "information_schema,queries,INF,USING,null,SYSTEM 
VIEW,false,",
+                  "information_schema,regions,INF,USING,null,SYSTEM 
VIEW,false,",
+                  "information_schema,topics,INF,USING,null,SYSTEM 
VIEW,false,",
+                  "information_schema,pipe_plugins,INF,USING,null,SYSTEM 
VIEW,false,",
+                  "information_schema,pipes,INF,USING,null,SYSTEM VIEW,false,",
+                  "information_schema,services,INF,USING,null,SYSTEM 
VIEW,false,",
+                  "information_schema,subscriptions,INF,USING,null,SYSTEM 
VIEW,false,",
+                  "information_schema,views,INF,USING,null,SYSTEM VIEW,false,",
+                  "information_schema,functions,INF,USING,null,SYSTEM 
VIEW,false,",
+                  "information_schema,configurations,INF,USING,null,SYSTEM 
VIEW,false,",
+                  "information_schema,keywords,INF,USING,null,SYSTEM 
VIEW,false,",
+                  "information_schema,nodes,INF,USING,null,SYSTEM VIEW,false,",
+                  "information_schema,table_disk_usage,INF,USING,null,SYSTEM 
VIEW,false,",
+                  "information_schema,config_nodes,INF,USING,null,SYSTEM 
VIEW,false,",
+                  "information_schema,data_nodes,INF,USING,null,SYSTEM 
VIEW,false,",
+                  "information_schema,connections,INF,USING,null,SYSTEM 
VIEW,false,",
+                  "information_schema,current_queries,INF,USING,null,SYSTEM 
VIEW,false,",
+                  
"information_schema,queries_costs_histogram,INF,USING,null,SYSTEM VIEW,false,",
+                  "test,test,INF,USING,test,BASE TABLE,true,",
+                  "test,view_table,100,USING,null,VIEW FROM TREE,true,")));
       TestUtils.assertResultSetEqual(
           statement.executeQuery("count devices from tables where status = 
'USING'"),
           "count(devices),",
@@ -876,6 +937,13 @@ public class IoTDBDatabaseIT {
     try (final Connection connection = EnvFactory.getEnv().getConnection();
         final Statement statement = connection.createStatement()) {
       statement.execute("create database root.test");
+      statement.execute("alter database root.test WITH NEED_LAST_CACHE=false");
+      try (final ResultSet resultSet = statement.executeQuery("SHOW DATABASES 
DETAILS root.test")) {
+        assertTrue(resultSet.next());
+        assertEquals("root.test", resultSet.getString("Database"));
+        assertFalse(resultSet.getBoolean("NeedLastCache"));
+        assertFalse(resultSet.next());
+      }
       Assert.assertThrows(
           IoTDBSQLException.class,
           () ->
@@ -999,8 +1067,9 @@ public class IoTDBDatabaseIT {
           Collections.singleton("information_schema,INF,null,null,null,"));
       TestUtils.assertResultSetEqual(
           userStmt.executeQuery("select * from information_schema.databases"),
-          
"database,ttl(ms),schema_replication_factor,data_replication_factor,time_partition_interval,schema_region_group_num,max_schema_region_group_num,data_region_group_num,max_data_region_group_num,",
-          
Collections.singleton("information_schema,INF,null,null,null,null,null,null,null,"));
+          
"database,ttl(ms),schema_replication_factor,data_replication_factor,time_partition_interval,schema_region_group_num,max_schema_region_group_num,data_region_group_num,max_data_region_group_num,need_last_cache,",
+          Collections.singleton(
+              
"information_schema,INF,null,null,null,null,null,null,null,false,"));
     }
 
     try (final Connection adminCon = 
EnvFactory.getEnv().getConnection(BaseEnv.TABLE_SQL_DIALECT);
diff --git 
a/integration-test/src/test/java/org/apache/iotdb/relational/it/schema/IoTDBTableIT.java
 
b/integration-test/src/test/java/org/apache/iotdb/relational/it/schema/IoTDBTableIT.java
index c3a72d3c23a..4c13f660972 100644
--- 
a/integration-test/src/test/java/org/apache/iotdb/relational/it/schema/IoTDBTableIT.java
+++ 
b/integration-test/src/test/java/org/apache/iotdb/relational/it/schema/IoTDBTableIT.java
@@ -135,6 +135,7 @@ public class IoTDBTableIT {
       String[] ttls = new String[] {"INF"};
       String[] statuses = new String[] {"USING"};
       String[] comments = new String[] {"test"};
+      String[] needLastCaches = new String[] {"true"};
 
       statement.execute("use test2");
 
@@ -154,6 +155,7 @@ public class IoTDBTableIT {
           assertEquals(ttls[cnt], resultSet.getString(2));
           assertEquals(statuses[cnt], resultSet.getString(3));
           assertEquals(comments[cnt], resultSet.getString(4));
+          assertEquals(needLastCaches[cnt], resultSet.getString(6));
           cnt++;
         }
         assertEquals(tableNames.length, cnt);
@@ -198,6 +200,9 @@ public class IoTDBTableIT {
 
       statement.execute("comment on table test1.table1 is 'new_test'");
       comments = new String[] {"new_test"};
+
+      statement.execute("alter table test1.table1 set properties 
need_last_cache=false");
+      needLastCaches = new String[] {"false"};
       // using SHOW tables from
       try (final ResultSet resultSet = statement.executeQuery("SHOW tables 
details from test1")) {
         int cnt = 0;
@@ -211,6 +216,7 @@ public class IoTDBTableIT {
           assertEquals(tableNames[cnt], resultSet.getString(1));
           assertEquals(ttls[cnt], resultSet.getString(2));
           assertEquals(comments[cnt], resultSet.getString(4));
+          assertEquals(needLastCaches[cnt], resultSet.getString(6));
           cnt++;
         }
         assertEquals(tableNames.length, cnt);
@@ -314,7 +320,7 @@ public class IoTDBTableIT {
           statement.executeQuery("show create table table2"),
           "Table,Create Table,",
           Collections.singleton(
-              "table2,CREATE TABLE \"table2\" (\"t1\" TIMESTAMP 
TIME,\"region_id\" STRING TAG,\"plant_id\" STRING TAG,\"color\" STRING 
ATTRIBUTE,\"temperature\" FLOAT FIELD,\"speed\" DOUBLE FIELD COMMENT 'fast') 
WITH (ttl=6600000),"));
+              "table2,CREATE TABLE \"table2\" (\"t1\" TIMESTAMP 
TIME,\"region_id\" STRING TAG,\"plant_id\" STRING TAG,\"color\" STRING 
ATTRIBUTE,\"temperature\" FLOAT FIELD,\"speed\" DOUBLE FIELD COMMENT 'fast') 
WITH (ttl=6600000, need_last_cache=true),"));
 
       try {
         statement.execute("alter table table2 add column speed DOUBLE FIELD");
@@ -626,13 +632,122 @@ public class IoTDBTableIT {
           statement.executeQuery("show create table test100"),
           "Table,Create Table,",
           Collections.singleton(
-              "test100,CREATE TABLE \"test100\" (\"t1\" TIMESTAMP TIME) WITH 
(ttl='INF'),"));
+              "test100,CREATE TABLE \"test100\" (\"t1\" TIMESTAMP TIME) WITH 
(ttl='INF', need_last_cache=true),"));
     } catch (final SQLException e) {
       e.printStackTrace();
       fail(e.getMessage());
     }
   }
 
+  @Test
+  public void testNeedLastCacheTableAndViewProperty() throws Exception {
+    try (final Connection treeConnection = EnvFactory.getEnv().getConnection();
+        final Statement treeStatement = treeConnection.createStatement()) {
+      treeStatement.execute("create database root.need_cache_view_source");
+      treeStatement.execute("create timeseries 
root.need_cache_view_source.d1.s1 int32");
+    }
+
+    try (final Connection connection =
+            EnvFactory.getEnv().getConnection(BaseEnv.TABLE_SQL_DIALECT);
+        final Statement statement = connection.createStatement()) {
+      statement.execute("create database need_cache_db with 
(need_last_cache=false)");
+      statement.execute("create database need_cache_default_db");
+      statement.execute("use need_cache_db");
+
+      statement.execute(
+          "create table inherited_table(time timestamp time, device_id string 
tag, temperature float field)");
+      statement.execute(
+          "create table override_table(time timestamp time, device_id string 
tag, temperature float field) with (need_last_cache=true)");
+      statement.execute(
+          "create table explicit_false_table(time timestamp time, device_id 
string tag, temperature float field) with (need_last_cache=false)");
+
+      assertTableNeedLastCache(statement, "need_cache_db", "inherited_table", 
false);
+      assertTableNeedLastCache(statement, "need_cache_db", "override_table", 
true);
+      assertTableNeedLastCache(statement, "need_cache_db", 
"explicit_false_table", false);
+
+      TestUtils.assertResultSetEqual(
+          statement.executeQuery("show create table explicit_false_table"),
+          "Table,Create Table,",
+          Collections.singleton(
+              "explicit_false_table,CREATE TABLE \"explicit_false_table\" 
(\"time\" TIMESTAMP TIME,\"device_id\" STRING TAG,\"temperature\" FLOAT FIELD) 
WITH (ttl='INF', need_last_cache=false),"));
+
+      statement.execute("alter table inherited_table set properties 
need_last_cache=true");
+      assertTableNeedLastCache(statement, "need_cache_db", "inherited_table", 
true);
+
+      statement.execute("alter table inherited_table set properties 
need_last_cache=default");
+      assertTableNeedLastCache(statement, "need_cache_db", "inherited_table", 
false);
+
+      statement.execute("alter table override_table set properties 
need_last_cache=false");
+      assertTableNeedLastCache(statement, "need_cache_db", "override_table", 
false);
+
+      statement.execute("alter table override_table set properties 
need_last_cache=true");
+      assertTableNeedLastCache(statement, "need_cache_db", "override_table", 
true);
+
+      statement.execute("use need_cache_default_db");
+      statement.execute(
+          "create table default_reset_table(time timestamp time, device_id 
string tag, temperature float field) with (need_last_cache=false)");
+      statement.execute("alter table default_reset_table set properties 
need_last_cache=default");
+      assertTableNeedLastCache(statement, "need_cache_default_db", 
"default_reset_table", true);
+
+      statement.execute("use need_cache_db");
+      try {
+        statement.execute(
+            "create view invalid_need_cache_view (tag1 string tag, s1 int32 
field) restrict with (ttl=100, need_last_cache=false) as 
root.need_cache_view_source.**");
+        fail("tree view need_last_cache should be rejected");
+      } catch (final SQLException e) {
+        assertEquals(
+            "701: The tree view does not support need_last_cache property.", 
e.getMessage());
+      }
+
+      statement.execute(
+          "create view explicit_view (tag1 string tag, s1 int32 field) 
restrict with (ttl=100) as root.need_cache_view_source.**");
+
+      TestUtils.assertResultSetEqual(
+          statement.executeQuery("show create view explicit_view"),
+          "View,Create View,",
+          Collections.singleton(
+              "explicit_view,CREATE VIEW \"explicit_view\" (\"time\" TIMESTAMP 
TIME,\"tag1\" STRING TAG,\"s1\" INT32 FIELD) RESTRICT WITH (ttl=100) AS 
root.\"need_cache_view_source\".**,"));
+
+      try {
+        statement.execute("alter view explicit_view set properties 
need_last_cache=false");
+        fail("tree view need_last_cache alter should be rejected");
+      } catch (final SQLException e) {
+        assertEquals(
+            "701: The tree view does not support need_last_cache property.", 
e.getMessage());
+      }
+    }
+  }
+
+  private static void assertTableNeedLastCache(
+      final Statement statement,
+      final String database,
+      final String table,
+      final boolean expectedNeedLastCache)
+      throws SQLException {
+    try (final ResultSet resultSet =
+        statement.executeQuery("show tables details from " + database)) {
+      boolean found = false;
+      while (resultSet.next()) {
+        if (!table.equals(resultSet.getString("TableName"))) {
+          continue;
+        }
+        found = true;
+        assertEquals(expectedNeedLastCache, 
resultSet.getBoolean("NeedLastCache"));
+      }
+      assertTrue(found);
+    }
+
+    TestUtils.assertResultSetEqual(
+        statement.executeQuery(
+            "select database, table_name, need_last_cache from 
information_schema.tables where database = '"
+                + database
+                + "' and table_name = '"
+                + table
+                + "'"),
+        "database,table_name,need_last_cache,",
+        Collections.singleton(database + "," + table + "," + 
expectedNeedLastCache + ","));
+  }
+
   @Test
   public void testTableAuth() throws SQLException {
     try (final Connection adminCon = 
EnvFactory.getEnv().getConnection(BaseEnv.TABLE_SQL_DIALECT);
@@ -649,7 +764,7 @@ public class IoTDBTableIT {
       Assert.assertThrows(SQLException.class, () -> userStmt.execute("select * 
from db.test"));
       TestUtils.assertResultSetEqual(
           userStmt.executeQuery("select * from information_schema.tables where 
database = 'db'"),
-          "database,table_name,ttl(ms),status,comment,table_type,",
+          
"database,table_name,ttl(ms),status,comment,table_type,need_last_cache,",
           Collections.emptySet());
       TestUtils.assertResultSetEqual(
           userStmt.executeQuery("select * from information_schema.columns 
where database = 'db'"),
@@ -932,8 +1047,8 @@ public class IoTDBTableIT {
 
       TestUtils.assertResultSetEqual(
           statement.executeQuery("show tables details"),
-          "TableName,TTL(ms),Status,Comment,TableType,",
-          Collections.singleton("view_table,100,USING,comment,VIEW FROM 
TREE,"));
+          "TableName,TTL(ms),Status,Comment,TableType,NeedLastCache,",
+          Collections.singleton("view_table,100,USING,comment,VIEW FROM 
TREE,true,"));
 
       TestUtils.assertResultSetEqual(
           statement.executeQuery("desc view_table"),
diff --git a/iotdb-client/client-cpp/examples/README.md 
b/iotdb-client/client-cpp/examples/README.md
index 763ec693bee..f45d54c9903 100644
--- a/iotdb-client/client-cpp/examples/README.md
+++ b/iotdb-client/client-cpp/examples/README.md
@@ -149,9 +149,9 @@ iotdb_session.dll
 **Prerequisites on the target PC**
 
 - **64-bit Windows** (examples are built x64).
-- **[Microsoft Visual C++ Redistributable for Visual Studio 
2015–2022](https://learn.microsoft.com/en-us/cpp/windows/latest-supported-vc-redist)**
  
+- **[Microsoft Visual C++ Redistributable for Visual Studio 
2015–2022](https://learn.microsoft.com/en-us/cpp/windows/latest-supported-vc-redist)**
   (x64). The SDK and examples are built with **`/MD`**; the redistributable
-  supplies `vcruntime140.dll`, `msvcp140.dll`, etc.  
+  supplies `vcruntime140.dll`, `msvcp140.dll`, etc.
   Installing this package is enough—you do **not** need Visual Studio or the
   IoTDB SDK on the target machine.
 
diff --git a/iotdb-client/client-cpp/examples/README_zh.md 
b/iotdb-client/client-cpp/examples/README_zh.md
index 4adc38a3fc7..2a660b4b6e9 100644
--- a/iotdb-client/client-cpp/examples/README_zh.md
+++ b/iotdb-client/client-cpp/examples/README_zh.md
@@ -146,9 +146,9 @@ iotdb_session.dll
 **目标机器前置条件**
 
 - **64 位 Windows**(示例为 x64 构建)。
-- 安装 **[Microsoft Visual C++ 2015–2022 
可再发行组件包(x64)](https://learn.microsoft.com/zh-cn/cpp/windows/latest-supported-vc-redist)**。
  
+- 安装 **[Microsoft Visual C++ 2015–2022 
可再发行组件包(x64)](https://learn.microsoft.com/zh-cn/cpp/windows/latest-supported-vc-redist)**。
   SDK 与示例均使用 **`/MD`**(动态 CRT),该安装包提供 `vcruntime140.dll`、
-  `msvcp140.dll` 等运行时。  
+  `msvcp140.dll` 等运行时。
   **仅安装此 Redistributable 即可**,目标机 **不需要** Visual Studio,也
   **不需要** IoTDB SDK 头文件或 Thrift/Boost。
 
diff --git 
a/iotdb-core/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IdentifierParser.g4
 
b/iotdb-core/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IdentifierParser.g4
index 135b674554b..9613a453c96 100644
--- 
a/iotdb-core/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IdentifierParser.g4
+++ 
b/iotdb-core/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IdentifierParser.g4
@@ -156,6 +156,7 @@ keyWords
     | MODELS
     | MODIFY
     | NAN
+    | NEED_LAST_CACHE
     | NODEID
     | NODES
     | NONE
diff --git 
a/iotdb-core/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IoTDBSqlParser.g4 
b/iotdb-core/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IoTDBSqlParser.g4
index e2ae5144caf..7bf79721e8f 100644
--- 
a/iotdb-core/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IoTDBSqlParser.g4
+++ 
b/iotdb-core/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IoTDBSqlParser.g4
@@ -116,6 +116,7 @@ databaseAttributesClause
 
 databaseAttributeClause
     : databaseAttributeKey operator_eq INTEGER_LITERAL
+    | NEED_LAST_CACHE operator_eq boolean_literal
     ;
 
 databaseAttributeKey
diff --git 
a/iotdb-core/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/SqlLexer.g4 
b/iotdb-core/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/SqlLexer.g4
index 4d915459c39..5ba86f80f8a 100644
--- a/iotdb-core/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/SqlLexer.g4
+++ b/iotdb-core/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/SqlLexer.g4
@@ -1239,6 +1239,10 @@ MAX_DATA_REGION_GROUP_NUM
     : M A X '_' D A T A '_' R E G I O N '_' G R O U P '_' N U M
     ;
 
+NEED_LAST_CACHE
+    : N E E D '_' L A S T '_' C A C H E
+    ;
+
 CURRENT_TIMESTAMP
     : C U R R E N T '_' T I M E S T A M P
     ;
diff --git 
a/iotdb-core/confignode/src/main/i18n/en/org/apache/iotdb/confignode/i18n/ConfigNodeMessages.java
 
b/iotdb-core/confignode/src/main/i18n/en/org/apache/iotdb/confignode/i18n/ConfigNodeMessages.java
index 5ac20660610..c4832cd886c 100644
--- 
a/iotdb-core/confignode/src/main/i18n/en/org/apache/iotdb/confignode/i18n/ConfigNodeMessages.java
+++ 
b/iotdb-core/confignode/src/main/i18n/en/org/apache/iotdb/confignode/i18n/ConfigNodeMessages.java
@@ -367,6 +367,9 @@ public final class ConfigNodeMessages {
       "schema_region_consensus_protocol_class";
   public static final String 
SEND_RPC_TO_DATA_NODE_FOR_CHANGING_REGIONS_LEADER_ON =
       "Send RPC to data node: {} for changing regions leader on it";
+  public static final String
+      
LOG_SETNEEDLASTCACHE_THE_NEED_LAST_CACHE_FLAG_OF_DATABASE_ARG_IS_ADJUSTED_TO_ARG_C7CFFABC
 =
+          "[SetNeedLastCache] The need last cache flag of Database: {} is 
adjusted to: {}";
   public static final String SETTTL_THE_TTL_OF_DATABASE_IS_ADJUSTED_TO =
       "[SetTTL] The ttl of Database: {} is adjusted to: {}";
   public static final String SNAPSHOT_DIRECTORY_CAN_NOT_BE_CREATED =
diff --git 
a/iotdb-core/confignode/src/main/i18n/zh/org/apache/iotdb/confignode/i18n/ConfigNodeMessages.java
 
b/iotdb-core/confignode/src/main/i18n/zh/org/apache/iotdb/confignode/i18n/ConfigNodeMessages.java
index 9519406be3c..3029154ab3e 100644
--- 
a/iotdb-core/confignode/src/main/i18n/zh/org/apache/iotdb/confignode/i18n/ConfigNodeMessages.java
+++ 
b/iotdb-core/confignode/src/main/i18n/zh/org/apache/iotdb/confignode/i18n/ConfigNodeMessages.java
@@ -340,6 +340,9 @@ public final class ConfigNodeMessages {
       "schema_region_consensus_protocol_class";
   public static final String 
SEND_RPC_TO_DATA_NODE_FOR_CHANGING_REGIONS_LEADER_ON =
       "向 data node: {} 发送 RPC 以切换其上的 region leader";
+  public static final String
+      
LOG_SETNEEDLASTCACHE_THE_NEED_LAST_CACHE_FLAG_OF_DATABASE_ARG_IS_ADJUSTED_TO_ARG_C7CFFABC
 =
+          "[SetNeedLastCache] Database:{} 的 need last cache 标志已调整为:{}";
   public static final String SETTTL_THE_TTL_OF_DATABASE_IS_ADJUSTED_TO =
       "[SetTTL] Database: {} 的 TTL 已调整为:{}";
   public static final String SNAPSHOT_DIRECTORY_CAN_NOT_BE_CREATED = "无法创建快照目录 
[{}]。";
diff --git 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/schema/ClusterSchemaManager.java
 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/schema/ClusterSchemaManager.java
index c28034cb9a7..840be42d48c 100644
--- 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/schema/ClusterSchemaManager.java
+++ 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/schema/ClusterSchemaManager.java
@@ -156,6 +156,14 @@ public class ClusterSchemaManager {
   private static final String CONSENSUS_WRITE_ERROR =
       
ConfigNodeMessages.FAILED_IN_THE_WRITE_API_EXECUTING_THE_CONSENSUS_LAYER_DUE;
 
+  public static boolean isNeedLastCacheEnabled(final TDatabaseSchema 
databaseSchema) {
+    return !databaseSchema.isSetNeedLastCache() || 
databaseSchema.isNeedLastCache();
+  }
+
+  private static boolean needInvalidateLastCache(final TDatabaseSchema after) {
+    return after.isSetNeedLastCache() && !after.isNeedLastCache();
+  }
+
   public ClusterSchemaManager(
       final IManager configManager,
       final ClusterSchemaInfo clusterSchemaInfo,
@@ -235,7 +243,9 @@ public class ClusterSchemaManager {
     TSStatus result;
     final TDatabaseSchema databaseSchema = databaseSchemaPlan.getSchema();
 
-    if (!isDatabaseExist(databaseSchema.getName())) {
+    try {
+      getDatabaseSchemaByName(databaseSchema.getName());
+    } catch (final DatabaseNotExistsException e) {
       // Reject if Database doesn't exist
       result = new TSStatus(TSStatusCode.DATABASE_NOT_EXIST.getStatusCode());
       result.setMessage(
@@ -274,11 +284,16 @@ public class ClusterSchemaManager {
                   isGeneratedByPipe
                       ? new PipeEnrichedPlan(databaseSchemaPlan)
                       : databaseSchemaPlan);
-      PartitionMetrics.bindDatabaseReplicationFactorMetricsWhenUpdate(
-          MetricService.getInstance(),
-          databaseSchemaPlan.getSchema().getName(),
-          databaseSchemaPlan.getSchema().getDataReplicationFactor(),
-          databaseSchemaPlan.getSchema().getSchemaReplicationFactor());
+      if (result.getCode() == TSStatusCode.SUCCESS_STATUS.getStatusCode()) {
+        if (needInvalidateLastCache(databaseSchema)) {
+          invalidateLastCache(databaseSchema.getName());
+        }
+        PartitionMetrics.bindDatabaseReplicationFactorMetricsWhenUpdate(
+            MetricService.getInstance(),
+            databaseSchemaPlan.getSchema().getName(),
+            databaseSchemaPlan.getSchema().getDataReplicationFactor(),
+            databaseSchemaPlan.getSchema().getSchemaReplicationFactor());
+      }
       return result;
     } catch (final ConsensusException e) {
       LOGGER.warn(CONSENSUS_WRITE_ERROR, e);
@@ -388,6 +403,7 @@ public class ClusterSchemaManager {
       
databaseInfo.setDataReplicationFactor(databaseSchema.getDataReplicationFactor());
       
databaseInfo.setTimePartitionOrigin(databaseSchema.getTimePartitionOrigin());
       
databaseInfo.setTimePartitionInterval(databaseSchema.getTimePartitionInterval());
+      databaseInfo.setNeedLastCache(isNeedLastCacheEnabled(databaseSchema));
       databaseInfo.setMaxSchemaRegionNum(
           getMaxRegionGroupNum(database, TConsensusGroupType.SchemaRegion));
       databaseInfo.setMaxDataRegionNum(
@@ -920,6 +936,10 @@ public class ClusterSchemaManager {
                       
.MESSAGE_FAILED_CREATE_DATABASE_TIMEPARTITIONINTERVAL_SHOULD_POSITIVE_BB1B473F);
     }
 
+    if (!databaseSchema.isSetNeedLastCache()) {
+      databaseSchema.setNeedLastCache(true);
+    }
+
     if (isSystemDatabase || isAuditDatabase) {
       databaseSchema.setMinSchemaRegionGroupNum(1);
     } else if (!databaseSchema.isSetMinSchemaRegionGroupNum()) {
@@ -1772,6 +1792,13 @@ public class ClusterSchemaManager {
       return result.get();
     }
 
+    if (isTableView && 
updatedProperties.containsKey(TsTable.NEED_LAST_CACHE_PROPERTY)) {
+      return new Pair<>(
+          RpcUtils.getStatus(
+              TSStatusCode.SEMANTIC_ERROR, 
TreeViewSchema.UNSUPPORTED_NEED_LAST_CACHE_PROPERTY),
+          null);
+    }
+
     updatedProperties
         .keySet()
         .removeIf(
@@ -1782,20 +1809,55 @@ public class ClusterSchemaManager {
       return new Pair<>(RpcUtils.SUCCESS_STATUS, null);
     }
 
+    final TDatabaseSchema databaseSchema;
+    try {
+      databaseSchema =
+          updatedProperties.containsKey(TsTable.NEED_LAST_CACHE_PROPERTY)
+                  && 
Objects.isNull(updatedProperties.get(TsTable.NEED_LAST_CACHE_PROPERTY))
+              ? getDatabaseSchemaByName(database)
+              : null;
+    } catch (final DatabaseNotExistsException e) {
+      throw new MetadataException(e);
+    }
+
     final TsTable updatedTable = new TsTable(originalTable);
     updatedProperties.forEach(
         (k, v) -> {
           originalProperties.put(k, 
originalTable.getPropValue(k).orElse(null));
           if (Objects.nonNull(v)) {
             updatedTable.addProp(k, v);
+          } else if (TsTable.NEED_LAST_CACHE_PROPERTY.equals(k)
+              && Objects.nonNull(databaseSchema)
+              && databaseSchema.isSetNeedLastCache()) {
+            updatedTable.addProp(k, 
String.valueOf(databaseSchema.isNeedLastCache()));
           } else {
             updatedTable.removeProp(k);
           }
         });
-
     return new Pair<>(RpcUtils.SUCCESS_STATUS, updatedTable);
   }
 
+  private void invalidateLastCache(final String database) {
+    final Map<Integer, TDataNodeLocation> dataNodeLocationMap =
+        getNodeManager().getRegisteredDataNodeLocations();
+    final DataNodeAsyncRequestContext<String, TSStatus> clientHandler =
+        new DataNodeAsyncRequestContext<>(
+            CnToDnAsyncRequestType.INVALIDATE_LAST_CACHE, database, 
dataNodeLocationMap);
+    
CnToDnInternalServiceAsyncRequestManager.getInstance().sendAsyncRequestWithRetry(clientHandler);
+    clientHandler
+        .getResponseMap()
+        .forEach(
+            (dataNodeId, status) -> {
+              if (status.getCode() != 
TSStatusCode.SUCCESS_STATUS.getStatusCode()) {
+                LOGGER.warn(
+                    "Failed to invalidate last cache of database {} on 
DataNode {}, status: {}",
+                    database,
+                    dataNodeId,
+                    status);
+              }
+            });
+  }
+
   public static Optional<Pair<TSStatus, TsTable>> checkTable4View(
       final String database, final TsTable table, final boolean isView) {
     if (!isView && TreeViewSchema.isTreeViewTable(table)) {
diff --git 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/schema/ClusterSchemaInfo.java
 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/schema/ClusterSchemaInfo.java
index 6553fa6566e..1b9c880cd6a 100644
--- 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/schema/ClusterSchemaInfo.java
+++ 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/schema/ClusterSchemaInfo.java
@@ -143,6 +143,7 @@ import static 
org.apache.iotdb.commons.schema.SchemaConstant.ALL_TEMPLATE;
 import static 
org.apache.iotdb.commons.schema.SchemaConstant.SYSTEM_DATABASE_PATTERN;
 import static 
org.apache.iotdb.commons.schema.table.Audit.TABLE_MODEL_AUDIT_DATABASE;
 import static 
org.apache.iotdb.commons.schema.table.Audit.TREE_MODEL_AUDIT_DATABASE;
+import static 
org.apache.iotdb.commons.schema.table.TsTable.NEED_LAST_CACHE_PROPERTY;
 import static org.apache.iotdb.commons.schema.table.TsTable.TTL_PROPERTY;
 
 /**
@@ -270,6 +271,15 @@ public class ClusterSchemaInfo implements 
SnapshotProcessor {
             currentSchema.getTTL());
       }
 
+      if (alterSchema.isSetNeedLastCache()) {
+        currentSchema.setNeedLastCache(alterSchema.isNeedLastCache());
+        LOGGER.info(
+            ConfigNodeMessages
+                
.LOG_SETNEEDLASTCACHE_THE_NEED_LAST_CACHE_FLAG_OF_DATABASE_ARG_IS_ADJUSTED_TO_ARG_C7CFFABC,
+            currentSchema.getName(),
+            currentSchema.isNeedLastCache());
+      }
+
       mTree
           .getDatabaseNodeByDatabasePath(partialPathName)
           .getAsMNode()
@@ -1333,6 +1343,11 @@ public class ClusterSchemaInfo implements 
SnapshotProcessor {
                             TreeViewSchema.isTreeViewTable(pair.getLeft())
                                 ? TableType.VIEW_FROM_TREE.ordinal()
                                 : TableType.BASE_TABLE.ordinal());
+                        info.setNeedLastCache(
+                            pair.getLeft()
+                                .getPropValue(NEED_LAST_CACHE_PROPERTY)
+                                .map(Boolean::parseBoolean)
+                                .orElse(true));
                         return info;
                       })
                   .collect(Collectors.toList())
@@ -1381,6 +1396,11 @@ public class ClusterSchemaInfo implements 
SnapshotProcessor {
                                         
TreeViewSchema.isTreeViewTable(pair.getLeft())
                                             ? 
TableType.VIEW_FROM_TREE.ordinal()
                                             : TableType.BASE_TABLE.ordinal());
+                                    info.setNeedLastCache(
+                                        pair.getLeft()
+                                            
.getPropValue(NEED_LAST_CACHE_PROPERTY)
+                                            .map(Boolean::parseBoolean)
+                                            .orElse(true));
                                     return info;
                                   })
                               .collect(Collectors.toList()))));
diff --git 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/schema/ConfigMTree.java
 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/schema/ConfigMTree.java
index 7456f339af7..12f6a2baaa1 100644
--- 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/schema/ConfigMTree.java
+++ 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/schema/ConfigMTree.java
@@ -969,6 +969,11 @@ public class ConfigMTree {
               && databaseNode.getDatabaseSchema().isSetTTL()
               && databaseNode.getDatabaseSchema().getTTL() != Long.MAX_VALUE) {
             table.addProp(k, 
String.valueOf(databaseNode.getDatabaseSchema().getTTL()));
+          } else if (k.equals(TsTable.NEED_LAST_CACHE_PROPERTY)
+              && databaseNode.getDatabaseSchema().isSetNeedLastCache()) {
+            table.addProp(
+                TsTable.NEED_LAST_CACHE_PROPERTY,
+                
String.valueOf(databaseNode.getDatabaseSchema().isNeedLastCache()));
           } else {
             table.removeProp(k);
           }
diff --git 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/table/CreateTableProcedure.java
 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/table/CreateTableProcedure.java
index edf9d0923c4..f2379ae1256 100644
--- 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/table/CreateTableProcedure.java
+++ 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/table/CreateTableProcedure.java
@@ -135,6 +135,10 @@ public class CreateTableProcedure
             && schema.getTTL() != Long.MAX_VALUE) {
           table.addProp(TsTable.TTL_PROPERTY, String.valueOf(schema.getTTL()));
         }
+        if (!table.getPropValue(TsTable.NEED_LAST_CACHE_PROPERTY).isPresent()
+            && schema.isSetNeedLastCache()) {
+          table.addProp(TsTable.NEED_LAST_CACHE_PROPERTY, 
String.valueOf(schema.isNeedLastCache()));
+        }
         setNextState(CreateTableState.PRE_CREATE);
       }
     } catch (final MetadataException | DatabaseNotExistsException e) {
diff --git 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/table/view/CreateTableViewProcedure.java
 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/table/view/CreateTableViewProcedure.java
index 88a16315729..f699a88a6ed 100644
--- 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/table/view/CreateTableViewProcedure.java
+++ 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/table/view/CreateTableViewProcedure.java
@@ -72,8 +72,17 @@ public class CreateTableViewProcedure extends 
CreateTableProcedure {
 
   @Override
   protected void checkTableExistence(final ConfigNodeProcedureEnv env) {
+    if (table.getPropValue(TsTable.NEED_LAST_CACHE_PROPERTY).isPresent()) {
+      setFailure(
+          new ProcedureException(
+              new IoTDBException(
+                  TreeViewSchema.UNSUPPORTED_NEED_LAST_CACHE_PROPERTY,
+                  TSStatusCode.SEMANTIC_ERROR.getStatusCode())));
+      return;
+    }
     if (!replace) {
       super.checkTableExistence(env);
+      table.removeProp(TsTable.NEED_LAST_CACHE_PROPERTY);
     } else {
       try {
         final Optional<Pair<TsTable, TableNodeStatus>> oldTableAndStatus =
diff --git 
a/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/manager/ClusterSchemaManagerTest.java
 
b/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/manager/ClusterSchemaManagerTest.java
index baa49ff2d31..7e080458c2d 100644
--- 
a/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/manager/ClusterSchemaManagerTest.java
+++ 
b/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/manager/ClusterSchemaManagerTest.java
@@ -23,6 +23,7 @@ import 
org.apache.iotdb.commons.schema.table.TsTableInternalRPCUtil;
 import org.apache.iotdb.confignode.manager.schema.ClusterSchemaManager;
 import org.apache.iotdb.confignode.manager.schema.ClusterSchemaQuotaStatistics;
 import org.apache.iotdb.confignode.persistence.schema.ClusterSchemaInfo;
+import org.apache.iotdb.confignode.rpc.thrift.TDatabaseSchema;
 
 import org.apache.tsfile.utils.Pair;
 import org.junit.Assert;
@@ -49,6 +50,20 @@ public class ClusterSchemaManagerTest {
     Assert.assertEquals(20, ClusterSchemaManager.calcMaxRegionGroupNum(3, 1.0, 
120, 2, 3, 5));
   }
 
+  @Test
+  public void testNeedLastCacheDefaultsToTrueWhenUnset() {
+    final TDatabaseSchema unsetSchema = new TDatabaseSchema();
+    
Assert.assertTrue(ClusterSchemaManager.isNeedLastCacheEnabled(unsetSchema));
+
+    final TDatabaseSchema enabledSchema = new TDatabaseSchema();
+    enabledSchema.setNeedLastCache(true);
+    
Assert.assertTrue(ClusterSchemaManager.isNeedLastCacheEnabled(enabledSchema));
+
+    final TDatabaseSchema disabledSchema = new TDatabaseSchema();
+    disabledSchema.setNeedLastCache(false);
+    
Assert.assertFalse(ClusterSchemaManager.isNeedLastCacheEnabled(disabledSchema));
+  }
+
   @Test
   public void testGetAllTableInfoForDataNodeActivationWithDeletedDatabase() {
     final IManager configManager = Mockito.mock(IManager.class);
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/source/relational/InformationSchemaContentSupplierFactory.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/source/relational/InformationSchemaContentSupplierFactory.java
index 4f01b5230ad..c0e7ca6d91a 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/source/relational/InformationSchemaContentSupplierFactory.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/source/relational/InformationSchemaContentSupplierFactory.java
@@ -350,6 +350,7 @@ public class InformationSchemaContentSupplierFactory {
       columnBuilders[6].writeInt(currentDatabase.getMaxSchemaRegionNum());
       columnBuilders[7].writeInt(currentDatabase.getDataRegionNum());
       columnBuilders[8].writeInt(currentDatabase.getMaxDataRegionNum());
+      columnBuilders[9].writeBoolean(currentDatabase.isNeedLastCache());
       resultBuilder.declarePosition();
       currentDatabase = null;
     }
@@ -404,6 +405,7 @@ public class InformationSchemaContentSupplierFactory {
                               table.getTableName(),
                               
table.getPropValue(TTL_PROPERTY).orElse(TTL_INFINITE));
                       info.setState(TableNodeStatus.USING.ordinal());
+                      info.setNeedLastCache(false);
                       return info;
                     })
                 .collect(Collectors.toList()));
@@ -438,6 +440,7 @@ public class InformationSchemaContentSupplierFactory {
         columnBuilders[5].writeBinary(
             new Binary(TableType.BASE_TABLE.getName(), 
TSFileConfig.STRING_CHARSET));
       }
+      columnBuilders[6].writeBoolean(currentTable.isNeedLastCache());
       resultBuilder.declarePosition();
       currentTable = null;
     }
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/ClusterPartitionFetcher.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/ClusterPartitionFetcher.java
index 7bb7478950b..99d7de4defd 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/ClusterPartitionFetcher.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/ClusterPartitionFetcher.java
@@ -358,6 +358,10 @@ public class ClusterPartitionFetcher implements 
IPartitionFetcher {
     return getOrCreateSchemaPartition(database, deviceIDs, false, null);
   }
 
+  public boolean needLastCache(final String database) {
+    return partitionCache.isNeedLastCache(database);
+  }
+
   private SchemaPartition getOrCreateSchemaPartition(
       final String database,
       final @Nullable List<IDeviceID> deviceIDs,
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/IPartitionFetcher.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/IPartitionFetcher.java
index 0549ec39647..99f1b9f99c3 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/IPartitionFetcher.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/IPartitionFetcher.java
@@ -26,6 +26,7 @@ import org.apache.iotdb.commons.partition.SchemaPartition;
 import org.apache.iotdb.commons.path.PathPatternTree;
 import org.apache.iotdb.mpp.rpc.thrift.TRegionRouteReq;
 
+import org.apache.tsfile.annotations.TableModel;
 import org.apache.tsfile.file.metadata.IDeviceID;
 
 import javax.annotation.Nullable;
@@ -123,6 +124,7 @@ public interface IPartitionFetcher {
    *
    * <p>The device id shall be [table, seg1, ....]
    */
+  @TableModel
   SchemaPartition getSchemaPartition(
       final String database, final @Nullable List<IDeviceID> deviceIDs);
 }
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/cache/partition/PartitionCache.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/cache/partition/PartitionCache.java
index 4b8ee72ffd4..bbe149142fc 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/cache/partition/PartitionCache.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/cache/partition/PartitionCache.java
@@ -61,6 +61,7 @@ import 
org.apache.iotdb.db.protocol.client.ConfigNodeClientManager;
 import org.apache.iotdb.db.protocol.client.ConfigNodeInfo;
 import org.apache.iotdb.db.protocol.session.IClientSession;
 import org.apache.iotdb.db.protocol.session.SessionManager;
+import 
org.apache.iotdb.db.queryengine.plan.relational.metadata.fetcher.cache.TreeDeviceSchemaCacheManager;
 import org.apache.iotdb.db.schemaengine.lease.MetadataLeaseManager;
 import org.apache.iotdb.db.schemaengine.schemaregion.utils.MetaUtils;
 import org.apache.iotdb.db.service.metrics.CacheMetrics;
@@ -69,6 +70,8 @@ import org.apache.iotdb.rpc.TSStatusCode;
 import com.github.benmanes.caffeine.cache.Cache;
 import com.github.benmanes.caffeine.cache.Caffeine;
 import org.apache.thrift.TException;
+import org.apache.tsfile.annotations.TableModel;
+import org.apache.tsfile.annotations.TreeModel;
 import org.apache.tsfile.file.metadata.IDeviceID;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -94,6 +97,10 @@ public class PartitionCache {
       IoTDBDescriptor.getInstance().getMemoryConfig();
   private static final List<String> ROOT_PATH = Arrays.asList("root", "**");
 
+  private static boolean isNeedLastCacheEnabled(final TDatabaseSchema 
databaseSchema) {
+    return !databaseSchema.isSetNeedLastCache() || 
databaseSchema.isNeedLastCache();
+  }
+
   /** calculate slotId by device */
   private final String seriesSlotExecutorName = 
config.getSeriesPartitionExecutorClass();
 
@@ -101,7 +108,7 @@ public class PartitionCache {
   private final SeriesPartitionExecutor partitionExecutor;
 
   /** the cache of database */
-  private final Set<String> databaseCache = new HashSet<>();
+  private final Map<String, Boolean> database2NeedLastCacheCache = new 
HashMap<>();
 
   /** database -> schemaPartitionTable */
   private final Cache<String, SchemaPartitionTable> schemaPartitionCache;
@@ -209,7 +216,7 @@ public class PartitionCache {
    * @return database name, return {@code null} if cache miss
    */
   private String getDatabaseName(final IDeviceID deviceID) {
-    for (final String database : databaseCache) {
+    for (final String database : database2NeedLastCacheCache.keySet()) {
       if (PathUtils.isStartWith(deviceID, database)) {
         return database;
       }
@@ -226,7 +233,7 @@ public class PartitionCache {
   private boolean containsDatabase(final String database) {
     databaseCacheLock.readLock().lock();
     try {
-      return databaseCache.contains(database);
+      return database2NeedLastCacheCache.containsKey(database);
     } finally {
       databaseCacheLock.readLock().unlock();
     }
@@ -255,7 +262,7 @@ public class PartitionCache {
         if (databaseSchemaResp.getStatus().getCode()
             == TSStatusCode.SUCCESS_STATUS.getStatusCode()) {
           // update all database into cache
-          
updateDatabaseCache(databaseSchemaResp.getDatabaseSchemaMap().keySet());
+          updateDatabaseCache(databaseSchemaResp.getDatabaseSchemaMap());
           getDatabaseMap(result, deviceIDs, true);
         }
       }
@@ -264,19 +271,39 @@ public class PartitionCache {
     }
   }
 
+  @TreeModel
+  public boolean isNeedLastCache(final String database) {
+    Boolean needLastCache = database2NeedLastCacheCache.get(database);
+    if (Objects.nonNull(needLastCache)) {
+      return needLastCache;
+    }
+    try {
+      fetchDatabaseAndUpdateCache(false);
+    } catch (final TException | ClientManagerException e) {
+      logger.warn(
+          "Failed to get need_last_cache info for database {}, will put cache 
anyway, exception: {}",
+          database,
+          e.getMessage());
+      return true;
+    }
+    needLastCache = database2NeedLastCacheCache.get(database);
+    return Objects.isNull(needLastCache) || needLastCache;
+  }
+
   /** get all database from configNode and update database cache. */
-  private void fetchDatabaseAndUpdateCache() throws ClientManagerException, 
TException {
+  private void fetchDatabaseAndUpdateCache(final boolean isTableModel)
+      throws ClientManagerException, TException {
     databaseCacheLock.writeLock().lock();
     try (final ConfigNodeClient client =
         configNodeClientManager.borrowClient(ConfigNodeInfo.CONFIG_REGION_ID)) 
{
       final TGetDatabaseReq req =
           new TGetDatabaseReq(ROOT_PATH, SchemaConstant.ALL_MATCH_SCOPE_BINARY)
-              .setIsTableModel(true)
+              .setIsTableModel(isTableModel)
               .setCanSeeAuditDB(true);
       final TDatabaseSchemaResp databaseSchemaResp = 
client.getMatchedDatabaseSchemas(req);
       if (databaseSchemaResp.getStatus().getCode() == 
TSStatusCode.SUCCESS_STATUS.getStatusCode()) {
         // update all database into cache
-        
updateDatabaseCache(databaseSchemaResp.getDatabaseSchemaMap().keySet());
+        updateDatabaseCache(databaseSchemaResp.getDatabaseSchemaMap());
       }
     } finally {
       databaseCacheLock.writeLock().unlock();
@@ -534,6 +561,7 @@ public class PartitionCache {
     }
   }
 
+  @TableModel
   public void checkAndAutoCreateDatabase(
       final String database, final boolean isAutoCreate, final String 
userName) {
     failIfMetadataLeaseFenced();
@@ -541,7 +569,7 @@ public class PartitionCache {
     if (!isExisted) {
       try {
         // try to fetch database from config node when miss
-        fetchDatabaseAndUpdateCache();
+        fetchDatabaseAndUpdateCache(true);
         isExisted = containsDatabase(database);
         if (!isExisted && isAutoCreate) {
           // try to auto create database of failed device
@@ -560,12 +588,39 @@ public class PartitionCache {
   /**
    * update database cache
    *
-   * @param databaseNames the database names that need to update
+   * @param databases names of databases created through local {@code 
setDatabase} requests. Those
+   *     requests leave {@code needLastCache} unset, which is 
backward-compatibly treated as
+   *     enabled.
+   */
+  public void updateDatabaseCache(final Set<String> databases) {
+    databaseCacheLock.writeLock().lock();
+    try {
+      databases.forEach(
+          database -> {
+            // The newly created schemas omit needLastCache, whose 
compatibility default is true.
+            database2NeedLastCacheCache.put(database, true);
+          });
+    } finally {
+      databaseCacheLock.writeLock().unlock();
+    }
+  }
+
+  /**
+   * update database cache
+   *
+   * @param databaseMap the database names and need last cache that need to 
update
    */
-  public void updateDatabaseCache(final Set<String> databaseNames) {
+  public void updateDatabaseCache(final Map<String, TDatabaseSchema> 
databaseMap) {
     databaseCacheLock.writeLock().lock();
     try {
-      databaseCache.addAll(databaseNames);
+      databaseMap.forEach(
+          (database, schema) -> {
+            final boolean needLastCache = isNeedLastCacheEnabled(schema);
+            database2NeedLastCacheCache.put(database, needLastCache);
+            if (!needLastCache) {
+              
TreeDeviceSchemaCacheManager.getInstance().invalidateDatabaseLastCache(database);
+            }
+          });
     } finally {
       databaseCacheLock.writeLock().unlock();
     }
@@ -575,7 +630,7 @@ public class PartitionCache {
   public void removeFromDatabaseCache() {
     databaseCacheLock.writeLock().lock();
     try {
-      databaseCache.clear();
+      database2NeedLastCacheCache.clear();
     } finally {
       databaseCacheLock.writeLock().unlock();
     }
@@ -1111,7 +1166,7 @@ public class PartitionCache {
   public String toString() {
     return "PartitionCache{"
         + ", databaseCache="
-        + databaseCache
+        + database2NeedLastCacheCache
         + ", replicaSetCache="
         + groupIdToReplicaSetMap
         + ", schemaPartitionCache="
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/TableConfigTaskVisitor.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/TableConfigTaskVisitor.java
index 1ff61937f4b..d2f81429d45 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/TableConfigTaskVisitor.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/TableConfigTaskVisitor.java
@@ -37,6 +37,7 @@ import 
org.apache.iotdb.commons.pipe.config.constant.PipeSinkConstant;
 import org.apache.iotdb.commons.pipe.config.constant.PipeSourceConstant;
 import org.apache.iotdb.commons.pipe.config.constant.SystemConstant;
 import 
org.apache.iotdb.commons.queryengine.plan.relational.metadata.QualifiedObjectName;
+import 
org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.BooleanLiteral;
 import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.DataType;
 import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.Expression;
 import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.Literal;
@@ -294,9 +295,11 @@ import static 
org.apache.iotdb.commons.executable.ExecutableManager.getUnTrusted
 import static 
org.apache.iotdb.commons.executable.ExecutableManager.isUriTrusted;
 import static 
org.apache.iotdb.commons.queryengine.plan.relational.type.InternalTypeManager.getTSDataType;
 import static 
org.apache.iotdb.commons.queryengine.plan.relational.type.TypeSignatureTranslator.toTypeSignature;
+import static 
org.apache.iotdb.commons.schema.table.TsTable.NEED_LAST_CACHE_PROPERTY;
 import static 
org.apache.iotdb.commons.schema.table.TsTable.TABLE_ALLOWED_PROPERTIES;
 import static org.apache.iotdb.commons.schema.table.TsTable.TIME_COLUMN_NAME;
 import static org.apache.iotdb.commons.schema.table.TsTable.TTL_PROPERTY;
+import static 
org.apache.iotdb.db.queryengine.plan.execution.config.metadata.relational.AbstractDatabaseTask.NEED_LAST_CACHE_KEY;
 import static 
org.apache.iotdb.db.queryengine.plan.execution.config.metadata.relational.CreateDBTask.MAX_DATA_REGION_GROUP_NUM_KEY;
 import static 
org.apache.iotdb.db.queryengine.plan.execution.config.metadata.relational.CreateDBTask.MAX_SCHEMA_REGION_GROUP_NUM_KEY;
 import static 
org.apache.iotdb.db.queryengine.plan.execution.config.metadata.relational.CreateDBTask.TIME_PARTITION_INTERVAL_KEY;
@@ -375,6 +378,11 @@ public class TableConfigTaskVisitor implements 
AstVisitor<IConfigTask, MPPQueryC
               schema.setTTL(Long.MAX_VALUE);
             }
             break;
+          case NEED_LAST_CACHE_KEY:
+            if (node.getType() == 
DatabaseSchemaStatement.DatabaseSchemaStatementType.ALTER) {
+              schema.setNeedLastCache(true);
+            }
+            break;
           default:
             throw new SemanticException(
                 DataNodeQueryMessages.UNSUPPORTED_DATABASE_PROPERTY_KEY + key);
@@ -410,6 +418,9 @@ public class TableConfigTaskVisitor implements 
AstVisitor<IConfigTask, MPPQueryC
           schema.setMaxDataRegionGroupNum(
               parseIntFromLiteral(value, MAX_DATA_REGION_GROUP_NUM_KEY));
           break;
+        case NEED_LAST_CACHE_KEY:
+          schema.setNeedLastCache(parseBooleanFromLiteral(value, 
NEED_LAST_CACHE_KEY));
+          break;
         default:
           throw new SemanticException(
               DataNodeQueryMessages.UNSUPPORTED_DATABASE_PROPERTY_KEY + key);
@@ -590,6 +601,7 @@ public class TableConfigTaskVisitor implements 
AstVisitor<IConfigTask, MPPQueryC
 
   @Override
   public IConfigTask visitCreateView(final CreateView node, final 
MPPQueryContext context) {
+    validateTreeViewProperties(node.getProperties());
     final Pair<String, TsTable> databaseTablePair = 
parseTable4CreateTableOrView(node, context);
     final TsTable table = databaseTablePair.getRight();
     accessControl.checkCanCreateViewFromTreePath(node.getPrefixPath(), 
context);
@@ -843,13 +855,17 @@ public class TableConfigTaskVisitor implements 
AstVisitor<IConfigTask, MPPQueryC
     accessControl.checkCanAlterTable(
         context.getSession().getUserName(), new QualifiedObjectName(database, 
tableName), context);
 
+    final boolean isTreeView = node.getType() == SetProperties.Type.TREE_VIEW;
+    if (isTreeView) {
+      validateTreeViewProperties(node.getProperties());
+    }
     return new AlterTableSetPropertiesTask(
         database,
         tableName,
         convertPropertiesToMap(node.getProperties(), true),
         context.getQueryId().getId(),
         node.ifExists(),
-        node.getType() == SetProperties.Type.TREE_VIEW);
+        isTreeView);
   }
 
   @Override
@@ -920,6 +936,15 @@ public class TableConfigTaskVisitor implements 
AstVisitor<IConfigTask, MPPQueryC
     return new Pair<>(database, name.getSuffix());
   }
 
+  private void validateTreeViewProperties(final List<Property> propertyList) {
+    for (final Property property : propertyList) {
+      final String key = 
property.getName().getValue().toLowerCase(Locale.ENGLISH);
+      if (NEED_LAST_CACHE_PROPERTY.equals(key)) {
+        throw new 
SemanticException(TreeViewSchema.UNSUPPORTED_NEED_LAST_CACHE_PROPERTY);
+      }
+    }
+  }
+
   private Map<String, String> convertPropertiesToMap(
       final List<Property> propertyList, final boolean serializeDefault) {
     final Map<String, String> map = new HashMap<>();
@@ -932,17 +957,27 @@ public class TableConfigTaskVisitor implements 
AstVisitor<IConfigTask, MPPQueryC
       if (TABLE_ALLOWED_PROPERTIES.contains(key)) {
         if (!property.isSetToDefault()) {
           final Expression value = property.getNonDefaultValue();
-          final Optional<String> strValue = 
parseStringFromLiteralIfBinary(value);
-          if (strValue.isPresent()) {
-            if (!strValue.get().equalsIgnoreCase(TTL_INFINITE)) {
-              throw new SemanticException(
-                  
DataNodeQueryMessages.TTL_VALUE_MUST_BE_INF_OR_A_LONG_LITERAL_BUT_NOW_IS + 
value);
-            }
-            map.put(key, strValue.get().toUpperCase(Locale.ENGLISH));
-            continue;
+          switch (key) {
+            case TTL_PROPERTY:
+              final Optional<String> strValue = 
parseStringFromLiteralIfBinary(value);
+              if (strValue.isPresent()) {
+                if (!strValue.get().equalsIgnoreCase(TTL_INFINITE)) {
+                  throw new SemanticException(
+                      
DataNodeQueryMessages.TTL_VALUE_MUST_BE_INF_OR_A_LONG_LITERAL_BUT_NOW_IS
+                          + value);
+                }
+                map.put(key, strValue.get().toUpperCase(Locale.ENGLISH));
+                continue;
+              }
+              map.put(key, String.valueOf(parseLongFromLiteral(value, 
TTL_PROPERTY)));
+              break;
+            case NEED_LAST_CACHE_PROPERTY:
+              map.put(
+                  key, String.valueOf(parseBooleanFromLiteral(value, 
NEED_LAST_CACHE_PROPERTY)));
+              break;
+            default:
+              break;
           }
-          // TODO: support validation for other properties
-          map.put(key, String.valueOf(parseLongFromLiteral(value, 
TTL_PROPERTY)));
         } else if (serializeDefault) {
           map.put(key, null);
         }
@@ -1124,6 +1159,18 @@ public class TableConfigTaskVisitor implements 
AstVisitor<IConfigTask, MPPQueryC
     return new SetSystemStatusTask(((SetSystemStatusStatement) 
node.getInnerTreeStatement()));
   }
 
+  private boolean parseBooleanFromLiteral(final Object value, final String 
name) {
+    if (!(value instanceof BooleanLiteral)) {
+      throw new SemanticException(
+          name
+              + " value must be a BooleanLiteral, but now is "
+              + (Objects.nonNull(value) ? value.getClass().getSimpleName() : 
null)
+              + ", value: "
+              + value);
+    }
+    return ((BooleanLiteral) value).getValue();
+  }
+
   private Optional<String> parseStringFromLiteralIfBinary(final Object value) {
     return value instanceof Literal && ((Literal) value).getTsValue() 
instanceof Binary
         ? Optional.of(
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/metadata/DatabaseSchemaTask.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/metadata/DatabaseSchemaTask.java
index 31c96887600..581b1ed2b99 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/metadata/DatabaseSchemaTask.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/metadata/DatabaseSchemaTask.java
@@ -73,6 +73,9 @@ public class DatabaseSchemaTask implements IConfigTask {
     if (databaseSchemaStatement.getMaxDataRegionGroupNum() != null) {
       
databaseSchema.setMaxDataRegionGroupNum(databaseSchemaStatement.getMaxDataRegionGroupNum());
     }
+    if (databaseSchemaStatement.isSetNeedLastCache()) {
+      
databaseSchema.setNeedLastCache(databaseSchemaStatement.isNeedLastCache());
+    }
     databaseSchema.setIsTableModel(false);
     return databaseSchema;
   }
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/metadata/relational/AbstractDatabaseTask.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/metadata/relational/AbstractDatabaseTask.java
index 59b50536c15..c1b6ba6bfc3 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/metadata/relational/AbstractDatabaseTask.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/metadata/relational/AbstractDatabaseTask.java
@@ -29,6 +29,7 @@ public abstract class AbstractDatabaseTask implements 
IConfigTask {
   public static final String TIME_PARTITION_INTERVAL_KEY = 
"time_partition_interval";
   public static final String MAX_SCHEMA_REGION_GROUP_NUM_KEY = 
"max_schema_region_group_num";
   public static final String MAX_DATA_REGION_GROUP_NUM_KEY = 
"max_data_region_group_num";
+  public static final String NEED_LAST_CACHE_KEY = "need_last_cache";
 
   // Deprecated
   public static final String SCHEMA_REPLICATION_FACTOR_KEY = 
"schema_replication_factor";
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/metadata/relational/ShowCreateTableTask.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/metadata/relational/ShowCreateTableTask.java
index 229cf9aa5f4..98a0d7b6feb 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/metadata/relational/ShowCreateTableTask.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/metadata/relational/ShowCreateTableTask.java
@@ -138,12 +138,16 @@ public class ShowCreateTableTask extends 
AbstractTableTask {
     if (table.getPropValue(TsTable.COMMENT_KEY).isPresent()) {
       builder.append(" COMMENT 
").append(getString(table.getPropValue(TsTable.COMMENT_KEY).get()));
     }
-
     String ttlString = 
table.getPropValue(TsTable.TTL_PROPERTY).orElse(TTL_INFINITE);
     if (ttlString.equals(TTL_INFINITE)) {
       ttlString = "'" + ttlString + "'";
     }
-    builder.append(" WITH (ttl=").append(ttlString).append(")");
+    builder
+        .append(" WITH (ttl=")
+        .append(ttlString)
+        .append(", need_last_cache=")
+        
.append(table.getPropValue(TsTable.NEED_LAST_CACHE_PROPERTY).orElse("true"))
+        .append(")");
 
     return builder.toString();
   }
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/metadata/relational/ShowDBTask.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/metadata/relational/ShowDBTask.java
index 128458888dc..05999e3f69d 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/metadata/relational/ShowDBTask.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/metadata/relational/ShowDBTask.java
@@ -169,6 +169,7 @@ public class ShowDBTask implements IConfigTask {
       
builder.getColumnBuilder(6).writeInt(storageGroupInfo.getMaxSchemaRegionNum());
       
builder.getColumnBuilder(7).writeInt(storageGroupInfo.getDataRegionNum());
       
builder.getColumnBuilder(8).writeInt(storageGroupInfo.getMaxDataRegionNum());
+      
builder.getColumnBuilder(9).writeBoolean(storageGroupInfo.isNeedLastCache());
       builder.declarePosition();
     }
 
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/metadata/relational/ShowTablesDetailsTask.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/metadata/relational/ShowTablesDetailsTask.java
index 228b1dd266a..2ddf07f9e0f 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/metadata/relational/ShowTablesDetailsTask.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/metadata/relational/ShowTablesDetailsTask.java
@@ -104,6 +104,9 @@ public class ShowTablesDetailsTask implements IConfigTask {
                               ? 
TableType.values()[tableInfo.getType()].getName()
                               : TableType.BASE_TABLE.getName(),
                           TSFileConfig.STRING_CHARSET));
+              builder
+                  .getColumnBuilder(5)
+                  .writeBoolean(!tableInfo.isSetNeedLastCache() || 
tableInfo.isNeedLastCache());
 
               builder.declarePosition();
             });
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/parser/ASTVisitor.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/parser/ASTVisitor.java
index e1ef66774f9..dc78f695902 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/parser/ASTVisitor.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/parser/ASTVisitor.java
@@ -3016,6 +3016,13 @@ public class ASTVisitor extends 
IoTDBSqlParserBaseVisitor<Statement> {
         ctx.databaseAttributeClause()) {
       final IoTDBSqlParser.DatabaseAttributeKeyContext attributeKey =
           attribute.databaseAttributeKey();
+      if (attributeKey == null) {
+        if (attribute.NEED_LAST_CACHE() != null) {
+          databaseSchemaStatement.setNeedLastCache(
+              Boolean.parseBoolean(attribute.boolean_literal().getText()));
+        }
+        continue;
+      }
       if (attributeKey.TTL() != null) {
         final long ttl = Long.parseLong(attribute.INTEGER_LITERAL().getText());
         databaseSchemaStatement.setTtl(ttl);
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/metadata/TableMetadataImpl.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/metadata/TableMetadataImpl.java
index 9e736a35c58..6332596ee88 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/metadata/TableMetadataImpl.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/metadata/TableMetadataImpl.java
@@ -67,6 +67,7 @@ import org.apache.iotdb.udf.api.relational.AggregateFunction;
 import org.apache.iotdb.udf.api.relational.ScalarFunction;
 import org.apache.iotdb.udf.api.relational.TableFunction;
 
+import org.apache.tsfile.annotations.TableModel;
 import org.apache.tsfile.file.metadata.IDeviceID;
 import org.apache.tsfile.read.common.type.ObjectType;
 import org.apache.tsfile.read.common.type.Type;
@@ -1746,6 +1747,7 @@ public class TableMetadataImpl implements Metadata {
     return partitionFetcher.getOrCreateSchemaPartition(database, deviceIDList, 
userName);
   }
 
+  @TableModel
   @Override
   public SchemaPartition getSchemaPartition(
       final String database, final List<IDeviceID> deviceIDList) {
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/metadata/fetcher/cache/TableDeviceSchemaCache.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/metadata/fetcher/cache/TableDeviceSchemaCache.java
index 15bd7ab6eca..1c11148ffc4 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/metadata/fetcher/cache/TableDeviceSchemaCache.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/metadata/fetcher/cache/TableDeviceSchemaCache.java
@@ -27,6 +27,7 @@ import org.apache.iotdb.commons.path.PartialPath;
 import org.apache.iotdb.commons.path.PathPatternUtil;
 import 
org.apache.iotdb.commons.queryengine.plan.relational.metadata.QualifiedObjectName;
 import org.apache.iotdb.commons.schema.table.PreDeleteTsTable;
+import org.apache.iotdb.commons.schema.table.TsTable;
 import org.apache.iotdb.commons.service.metric.MetricService;
 import org.apache.iotdb.commons.utils.PathUtils;
 import org.apache.iotdb.db.conf.DataNodeMemoryConfig;
@@ -109,24 +110,44 @@ public class TableDeviceSchemaCache {
 
   private final ReentrantReadWriteLock readWriteLock = new 
ReentrantReadWriteLock(false);
 
-  private final IMemoryBlock memoryBlock;
+  @Nullable private final IMemoryBlock memoryBlock;
 
   private TableDeviceSchemaCache() {
-    memoryBlock =
+    this(
         memoryConfig
             .getSchemaCacheMemoryManager()
-            .exactAllocate(DataNodeMemoryConfig.SCHEMA_CACHE, 
MemoryBlockType.STATIC);
+            .exactAllocate(DataNodeMemoryConfig.SCHEMA_CACHE, 
MemoryBlockType.STATIC),
+        true);
+  }
+
+  private TableDeviceSchemaCache(final IMemoryBlock memoryBlock, final boolean 
bindMetrics) {
+    this(memoryBlock.getTotalMemorySizeInBytes(), memoryBlock, bindMetrics);
+  }
+
+  private TableDeviceSchemaCache(
+      final long memoryCapacity,
+      final @Nullable IMemoryBlock memoryBlock,
+      final boolean bindMetrics) {
+    this.memoryBlock = memoryBlock;
     dualKeyCache =
         new DualKeyCacheBuilder<TableId, IDeviceID, TableDeviceCacheEntry>()
             .cacheEvictionPolicy(
                 
DualKeyCachePolicy.valueOf(config.getDataNodeSchemaCacheEvictionPolicy()))
-            .memoryCapacity(memoryBlock.getTotalMemorySizeInBytes())
+            .memoryCapacity(memoryCapacity)
             .firstKeySizeComputer(TableId::estimateSize)
             .secondKeySizeComputer(deviceID -> (int) deviceID.ramBytesUsed())
             .valueSizeComputer(TableDeviceCacheEntry::estimateSize)
             .build();
-    memoryBlock.allocate(memoryBlock.getTotalMemorySizeInBytes());
-    MetricService.getInstance().addMetricSet(new 
TableDeviceSchemaCacheMetrics(this));
+    if (Objects.nonNull(this.memoryBlock)) {
+      this.memoryBlock.allocate(this.memoryBlock.getTotalMemorySizeInBytes());
+    }
+    if (bindMetrics) {
+      MetricService.getInstance().addMetricSet(new 
TableDeviceSchemaCacheMetrics(this));
+    }
+  }
+
+  static TableDeviceSchemaCache createForTest(final long memoryCapacity) {
+    return new TableDeviceSchemaCache(memoryCapacity, null, false);
   }
 
   public static TableDeviceSchemaCache getInstance() {
@@ -239,8 +260,9 @@ public class TableDeviceSchemaCache {
     readWriteLock.readLock().lock();
     try {
       // Avoid stale table
-      if (Objects.isNull(
-          DataNodeTableCache.getInstance().getTable(database, 
deviceId.getTableName(), false))) {
+      final TsTable table =
+          DataNodeTableCache.getInstance().getTable(database, 
deviceId.getTableName(), false);
+      if (Objects.isNull(table) || 
Boolean.FALSE.equals(table.getCachedNeedLastCache())) {
         return;
       }
       dualKeyCache.update(
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/metadata/fetcher/cache/TreeDeviceSchemaCacheManager.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/metadata/fetcher/cache/TreeDeviceSchemaCacheManager.java
index 29a66bdcdf0..0f0f92ef0ff 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/metadata/fetcher/cache/TreeDeviceSchemaCacheManager.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/metadata/fetcher/cache/TreeDeviceSchemaCacheManager.java
@@ -30,6 +30,7 @@ import 
org.apache.iotdb.db.exception.metadata.view.InsertNonWritableViewExceptio
 import org.apache.iotdb.db.i18n.DataNodeSchemaMessages;
 import org.apache.iotdb.db.queryengine.common.schematree.ClusterSchemaTree;
 import 
org.apache.iotdb.db.queryengine.common.schematree.IMeasurementSchemaInfo;
+import org.apache.iotdb.db.queryengine.plan.analyze.ClusterPartitionFetcher;
 import org.apache.iotdb.db.queryengine.plan.analyze.schema.ISchemaComputation;
 import org.apache.iotdb.db.schemaengine.lease.MetadataLeaseManager;
 import org.apache.iotdb.db.schemaengine.template.ClusterTemplateManager;
@@ -351,6 +352,10 @@ public class TreeDeviceSchemaCacheManager {
       final @Nonnull TimeValuePair[] timeValuePairs,
       final boolean isAligned,
       final IMeasurementSchema[] measurementSchemas) {
+    if (!ClusterPartitionFetcher.getInstance().needLastCache(database)) {
+      return;
+    }
+
     tableDeviceSchemaCache.updateLastCache(
         database, deviceID, measurements, timeValuePairs, isAligned, 
measurementSchemas, false);
   }
@@ -387,6 +392,10 @@ public class TreeDeviceSchemaCacheManager {
    * @param measurementPath the fetched {@link MeasurementPath}
    */
   public void declareLastCache(final String database, final MeasurementPath 
measurementPath) {
+    if (!ClusterPartitionFetcher.getInstance().needLastCache(database)) {
+      return;
+    }
+
     tableDeviceSchemaCache.updateLastCache(
         database,
         measurementPath.getIDeviceID(),
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/metadata/DatabaseSchemaStatement.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/metadata/DatabaseSchemaStatement.java
index e27dde87b41..dc18d560556 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/metadata/DatabaseSchemaStatement.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/metadata/DatabaseSchemaStatement.java
@@ -39,6 +39,8 @@ public class DatabaseSchemaStatement extends Statement 
implements IConfigStateme
   private Integer maxSchemaRegionGroupNum = null;
   private Integer maxDataRegionGroupNum = null;
   private boolean enablePrintExceptionLog = true;
+  private boolean needLastCache = true;
+  private boolean isNeedLastCacheSet = false;
 
   // Deprecated
   private Integer schemaReplicationFactor = null;
@@ -118,6 +120,19 @@ public class DatabaseSchemaStatement extends Statement 
implements IConfigStateme
     this.enablePrintExceptionLog = enablePrintExceptionLog;
   }
 
+  public boolean isNeedLastCache() {
+    return needLastCache;
+  }
+
+  public boolean isSetNeedLastCache() {
+    return isNeedLastCacheSet;
+  }
+
+  public void setNeedLastCache(final boolean needLastCache) {
+    this.needLastCache = needLastCache;
+    this.isNeedLastCacheSet = true;
+  }
+
   @Override
   public <R, C> R accept(final StatementVisitor<R, C> visitor, final C 
context) {
     switch (subType) {
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/metadata/ShowDatabaseStatement.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/metadata/ShowDatabaseStatement.java
index 2367aa0c312..01674805762 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/metadata/ShowDatabaseStatement.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/metadata/ShowDatabaseStatement.java
@@ -104,6 +104,7 @@ public class ShowDatabaseStatement extends ShowStatement 
implements IConfigState
         
builder.getColumnBuilder(6).writeInt(databaseInfo.getMaxSchemaRegionNum());
         builder.getColumnBuilder(7).writeInt(databaseInfo.getDataRegionNum());
         
builder.getColumnBuilder(8).writeInt(databaseInfo.getMaxDataRegionNum());
+        
builder.getColumnBuilder(9).writeBoolean(databaseInfo.isNeedLastCache());
       }
       builder.declarePosition();
     }
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/table/DataNodeTableCache.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/table/DataNodeTableCache.java
index c1bb53a8a90..23daf268206 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/table/DataNodeTableCache.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/table/DataNodeTableCache.java
@@ -41,6 +41,7 @@ import org.apache.iotdb.db.protocol.client.ConfigNodeClient;
 import org.apache.iotdb.db.protocol.client.ConfigNodeClientManager;
 import org.apache.iotdb.db.protocol.client.ConfigNodeInfo;
 import 
org.apache.iotdb.db.queryengine.plan.execution.config.executor.ClusterConfigTaskExecutor;
+import 
org.apache.iotdb.db.queryengine.plan.relational.metadata.fetcher.cache.TableDeviceSchemaCache;
 import org.apache.iotdb.db.schemaengine.lease.MetadataLeaseManager;
 import org.apache.iotdb.rpc.TSStatusCode;
 
@@ -196,6 +197,12 @@ public class DataNodeTableCache implements ITableCache {
                 }
               });
       LOGGER.info(DataNodeSchemaMessages.PRE_UPDATE_TABLE_SUCCESS, database, 
table.getTableName());
+      // Since a pre-updated table can be used for query planning before 
commit-release, stale
+      // last cache should stop serving as soon as need_last_cache turns off.
+      if (!table.getCachedNeedLastCache()) {
+        TableDeviceSchemaCache.getInstance().invalidateLastCache(database, 
table.getTableName());
+      }
+
       if (table instanceof PreDeleteTsTable) {
         if (databaseTableMap.containsKey(database)) {
           databaseTableMap.get(database).remove(table.getTableName());
@@ -280,6 +287,18 @@ public class DataNodeTableCache implements ITableCache {
     return Objects.nonNull(tableVersionPair) ? tableVersionPair.getLeft() : 
null;
   }
 
+  private @Nullable TsTable getTableFromCache(final String database, final 
String tableName) {
+    final Map<String, TsTable> tableMap = databaseTableMap.get(database);
+    return Objects.nonNull(tableMap) ? tableMap.get(tableName) : null;
+  }
+
+  private void invalidateLastCacheIfDisabled(
+      final String database, final String tableName, final TsTable 
currentTable) {
+    if (Objects.nonNull(currentTable) && 
!currentTable.getCachedNeedLastCache()) {
+      TableDeviceSchemaCache.getInstance().invalidateLastCache(database, 
tableName);
+    }
+  }
+
   private void removeTableFromSpecialStatusMap(final String database, final 
String tableName) {
     specialStatusMap.computeIfPresent(
         database,
@@ -329,6 +348,7 @@ public class DataNodeTableCache implements ITableCache {
           databaseTableMap
               .computeIfAbsent(database, k -> new ConcurrentHashMap<>())
               .put(tableName, newTable);
+      invalidateLastCacheIfDisabled(database, tableName, newTable);
       if (LOGGER.isDebugEnabled()) {
         LOGGER.debug(
             DataNodeSchemaMessages.COMMIT_UPDATE_TABLE_SUCCESS_WITH_DETAIL,
@@ -613,6 +633,7 @@ public class DataNodeTableCache implements ITableCache {
                       databaseTableMap
                           .computeIfAbsent(database, k -> new 
ConcurrentHashMap<>())
                           .put(tableName, tsTable);
+                      invalidateLastCacheIfDisabled(database, tableName, 
tsTable);
                     } else if (databaseTableMap.containsKey(database)) {
                       databaseTableMap.get(database).remove(tableName);
                     }
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/table/InformationSchemaUtils.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/table/InformationSchemaUtils.java
index 443352ae919..50d36d5a981 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/table/InformationSchemaUtils.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/table/InformationSchemaUtils.java
@@ -75,10 +75,11 @@ public class InformationSchemaUtils {
     builder.getColumnBuilder(4).appendNull();
     if (details) {
       for (int columnIndex = 5;
-          columnIndex < builder.getValueColumnBuilders().length;
+          columnIndex < builder.getValueColumnBuilders().length - 1;
           columnIndex++) {
         builder.getColumnBuilder(columnIndex).appendNull();
       }
+      builder.getColumnBuilder(builder.getValueColumnBuilders().length - 
1).writeBoolean(false);
     }
     builder.declarePosition();
   }
@@ -125,6 +126,7 @@ public class InformationSchemaUtils {
         builder
             .getColumnBuilder(4)
             .writeBinary(new Binary(TableType.SYSTEM_VIEW.getName(), 
TSFileConfig.STRING_CHARSET));
+        builder.getColumnBuilder(5).writeBoolean(false);
       }
       builder.declarePosition();
     }
diff --git 
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/metadata/cache/TreeDeviceSchemaCacheManagerTest.java
 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/metadata/cache/TreeDeviceSchemaCacheManagerTest.java
index c11fc1865a7..59cdf620561 100644
--- 
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/metadata/cache/TreeDeviceSchemaCacheManagerTest.java
+++ 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/metadata/cache/TreeDeviceSchemaCacheManagerTest.java
@@ -24,8 +24,10 @@ import org.apache.iotdb.commons.path.MeasurementPath;
 import org.apache.iotdb.commons.path.PartialPath;
 import org.apache.iotdb.commons.queryengine.plan.planner.plan.node.PlanNodeId;
 import org.apache.iotdb.commons.schema.template.Template;
+import org.apache.iotdb.confignode.rpc.thrift.TDatabaseSchema;
 import org.apache.iotdb.db.queryengine.common.schematree.ClusterSchemaTree;
 import org.apache.iotdb.db.queryengine.common.schematree.ISchemaTree;
+import 
org.apache.iotdb.db.queryengine.plan.analyze.cache.partition.PartitionCache;
 import 
org.apache.iotdb.db.queryengine.plan.planner.plan.node.write.InsertRowNode;
 import 
org.apache.iotdb.db.queryengine.plan.relational.metadata.fetcher.cache.SchemaCacheEntry;
 import 
org.apache.iotdb.db.queryengine.plan.relational.metadata.fetcher.cache.TableDeviceSchemaCache;
@@ -275,6 +277,33 @@ public class TreeDeviceSchemaCacheManagerTest {
     Assert.assertEquals(0, 
TableDeviceSchemaCache.getInstance().getMemoryUsage());
   }
 
+  @Test
+  public void testLastCacheIsInvalidatedWhenDatabaseNeedLastCacheSetFalse()
+      throws IllegalPathException {
+    final String database = "root.db";
+    final PartialPath device = new PartialPath("root.db.d");
+    final MeasurementSchema s1 = new MeasurementSchema("s1", TSDataType.INT32);
+    final TimeValuePair tv1 = new TimeValuePair(1, new 
TsPrimitiveType.TsInt(1));
+    final MeasurementPath measurementPath = new 
MeasurementPath(device.concatNode("s1"), s1);
+
+    treeDeviceSchemaCacheManager.declareLastCache(database, measurementPath);
+    treeDeviceSchemaCacheManager.updateLastCacheIfExists(
+        database,
+        IDeviceID.Factory.DEFAULT_FACTORY.create(
+            StringArrayDeviceID.splitDeviceIdString(device.getNodes())),
+        new String[] {"s1"},
+        new TimeValuePair[] {tv1},
+        false,
+        new MeasurementSchema[] {s1});
+    Assert.assertEquals(tv1, 
treeDeviceSchemaCacheManager.getLastCache(measurementPath));
+
+    final TDatabaseSchema disabledSchema = new TDatabaseSchema();
+    disabledSchema.setNeedLastCache(false);
+    new 
PartitionCache().updateDatabaseCache(Collections.singletonMap(database, 
disabledSchema));
+
+    
Assert.assertNull(treeDeviceSchemaCacheManager.getLastCache(measurementPath));
+  }
+
   @Test
   public void testUpdateLastCacheLazilyWithAlias() throws IllegalPathException 
{
     final String database = "root.db";
diff --git 
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/analyze/cache/PartitionCacheTest.java
 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/analyze/cache/PartitionCacheTest.java
index e08a2b610c9..6bffb381b1e 100644
--- 
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/analyze/cache/PartitionCacheTest.java
+++ 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/analyze/cache/PartitionCacheTest.java
@@ -29,6 +29,7 @@ import org.apache.iotdb.commons.partition.DataPartition;
 import org.apache.iotdb.commons.partition.DataPartitionQueryParam;
 import org.apache.iotdb.commons.partition.SchemaPartition;
 import org.apache.iotdb.commons.partition.executor.SeriesPartitionExecutor;
+import org.apache.iotdb.confignode.rpc.thrift.TDatabaseSchema;
 import org.apache.iotdb.db.auth.AuthorityChecker;
 import org.apache.iotdb.db.conf.IoTDBConfig;
 import org.apache.iotdb.db.conf.IoTDBDescriptor;
@@ -53,6 +54,7 @@ import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
 public class PartitionCacheTest {
@@ -62,7 +64,7 @@ public class PartitionCacheTest {
       SeriesPartitionExecutor.getSeriesPartitionExecutor(
           config.getSeriesPartitionExecutorClass(), 
config.getSeriesPartitionSlotNum());
 
-  private static final Set<String> storageGroups = new HashSet<>();
+  private static final Set<String> databases = new HashSet<>();
   private static final Map<String, Map<TSeriesPartitionSlot, 
TConsensusGroupId>>
       schemaPartitionTable = new HashMap<>();
   private static final Map<
@@ -85,7 +87,7 @@ public class PartitionCacheTest {
         storageGroupNumber++) {
       // init each database
       String storageGroupName = getDatabaseName(storageGroupNumber);
-      storageGroups.add(storageGroupName);
+      databases.add(storageGroupName);
       if (!schemaPartitionTable.containsKey(storageGroupName)) {
         schemaPartitionTable.put(storageGroupName, new HashMap<>());
       }
@@ -148,7 +150,7 @@ public class PartitionCacheTest {
   @Before
   public void setUp() throws Exception {
     partitionCache = new PartitionCache();
-    partitionCache.updateDatabaseCache(storageGroups);
+    partitionCache.updateDatabaseCache(databases);
     partitionCache.updateSchemaPartitionCache(schemaPartitionTable);
     partitionCache.updateDataPartitionCache(dataPartitionTable);
     partitionCache.updateGroupIdToReplicaSetMap(100, 
consensusGroupIdToRegionReplicaSet);
@@ -243,6 +245,29 @@ public class PartitionCacheTest {
     assertEquals(0, deviceToStorageGroupMap.size());
   }
 
+  @Test
+  public void testNeedLastCacheDefaultsToTrueWhenUnset() {
+    final Map<String, TDatabaseSchema> databaseSchemaMap = new HashMap<>();
+
+    final TDatabaseSchema unsetSchema = new TDatabaseSchema();
+    databaseSchemaMap.put("root.unset", unsetSchema);
+
+    final TDatabaseSchema enabledSchema = new TDatabaseSchema();
+    enabledSchema.setNeedLastCache(true);
+    databaseSchemaMap.put("root.enabled", enabledSchema);
+
+    final TDatabaseSchema disabledSchema = new TDatabaseSchema();
+    disabledSchema.setNeedLastCache(false);
+    databaseSchemaMap.put("root.disabled", disabledSchema);
+
+    partitionCache.updateDatabaseCache(databaseSchemaMap);
+
+    assertTrue(partitionCache.isNeedLastCache("root.unset"));
+    assertTrue(partitionCache.isNeedLastCache("root.enabled"));
+    assertFalse(partitionCache.isNeedLastCache("root.disabled"));
+    assertTrue(partitionCache.isNeedLastCache("root.missing"));
+  }
+
   @Test
   public void testRegionReplicaSetCache() {
     // test update regionReplicaSetCache with small timestamp
diff --git 
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/execution/config/metadata/DatabaseSchemaTaskTest.java
 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/execution/config/metadata/DatabaseSchemaTaskTest.java
new file mode 100644
index 00000000000..41703a45834
--- /dev/null
+++ 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/execution/config/metadata/DatabaseSchemaTaskTest.java
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.iotdb.db.queryengine.plan.execution.config.metadata;
+
+import org.apache.iotdb.commons.path.PartialPath;
+import org.apache.iotdb.confignode.rpc.thrift.TDatabaseSchema;
+import 
org.apache.iotdb.db.queryengine.plan.statement.metadata.DatabaseSchemaStatement;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+public class DatabaseSchemaTaskTest {
+
+  @Test
+  public void testConstructDatabaseSchemaDoesNotSetNeedLastCacheWhenAbsent() 
throws Exception {
+    final DatabaseSchemaStatement statement =
+        new 
DatabaseSchemaStatement(DatabaseSchemaStatement.DatabaseSchemaStatementType.ALTER);
+    statement.setDatabasePath(new PartialPath("root.sg"));
+
+    final TDatabaseSchema databaseSchema = 
DatabaseSchemaTask.constructDatabaseSchema(statement);
+
+    assertFalse(databaseSchema.isSetNeedLastCache());
+  }
+
+  @Test
+  public void testConstructDatabaseSchemaSetsNeedLastCacheWhenPresent() throws 
Exception {
+    final DatabaseSchemaStatement statement =
+        new 
DatabaseSchemaStatement(DatabaseSchemaStatement.DatabaseSchemaStatementType.ALTER);
+    statement.setDatabasePath(new PartialPath("root.sg"));
+    statement.setNeedLastCache(false);
+
+    final TDatabaseSchema databaseSchema = 
DatabaseSchemaTask.constructDatabaseSchema(statement);
+
+    assertTrue(databaseSchema.isSetNeedLastCache());
+    assertEquals(false, databaseSchema.isNeedLastCache());
+  }
+}
diff --git 
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/metadata/fetcher/cache/TableDeviceSchemaCacheTest.java
 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/metadata/fetcher/cache/TableDeviceSchemaCacheTest.java
index e808652a42a..2b8909f3861 100644
--- 
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/metadata/fetcher/cache/TableDeviceSchemaCacheTest.java
+++ 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/metadata/fetcher/cache/TableDeviceSchemaCacheTest.java
@@ -19,15 +19,14 @@
 
 package org.apache.iotdb.db.queryengine.plan.relational.metadata.fetcher.cache;
 
-import org.apache.iotdb.commons.memory.MemoryManager;
 import org.apache.iotdb.commons.schema.column.ColumnHeader;
 import org.apache.iotdb.commons.schema.table.TsTable;
 import org.apache.iotdb.commons.schema.table.column.AttributeColumnSchema;
 import org.apache.iotdb.commons.schema.table.column.FieldColumnSchema;
 import org.apache.iotdb.commons.schema.table.column.TagColumnSchema;
 import org.apache.iotdb.commons.schema.table.column.TimeColumnSchema;
-import org.apache.iotdb.db.conf.DataNodeMemoryConfig;
-import org.apache.iotdb.db.conf.IoTDBDescriptor;
+import org.apache.iotdb.confignode.rpc.thrift.TDatabaseSchema;
+import 
org.apache.iotdb.db.queryengine.plan.analyze.cache.partition.PartitionCache;
 import org.apache.iotdb.db.schemaengine.table.DataNodeTableCache;
 
 import org.apache.tsfile.common.conf.TSFileConfig;
@@ -58,15 +57,11 @@ import static 
org.apache.iotdb.db.queryengine.plan.relational.metadata.fetcher.T
 
 public class TableDeviceSchemaCacheTest {
 
-  private static final DataNodeMemoryConfig memoryConfig =
-      IoTDBDescriptor.getInstance().getMemoryConfig();
-
-  private static long originMemConfig;
-
   private static final String database1 = "sg1";
   private static final String database2 = "sg2";
   private static final String table1 = "t1";
   private static final String table2 = "t2";
+  private static final String tableNeedLastCacheDisabled = 
"t_need_last_cache_disabled";
   private static final String attributeName1 = "type";
   private static final String attributeName2 = "cycle";
   private static final String measurement1 = "s0";
@@ -146,24 +141,45 @@ public class TableDeviceSchemaCacheTest {
     DataNodeTableCache.getInstance().preUpdateTable(database1, testTable2, 
null);
     DataNodeTableCache.getInstance().commitUpdateTable(database1, table2, 
null);
 
-    originMemConfig = 
memoryConfig.getSchemaCacheMemoryManager().getTotalMemorySizeInBytes();
-    changeSchemaCacheMemorySize(1300L);
+    final TsTable testTableNeedLastCacheDisabled = new 
TsTable(tableNeedLastCacheDisabled);
+    columnHeaderList.forEach(
+        columnHeader ->
+            testTableNeedLastCacheDisabled.addColumnSchema(
+                new TagColumnSchema(columnHeader.getColumnName(), 
columnHeader.getColumnType())));
+    testTableNeedLastCacheDisabled.addColumnSchema(
+        new AttributeColumnSchema(attributeName1, TSDataType.STRING));
+    testTableNeedLastCacheDisabled.addColumnSchema(
+        new AttributeColumnSchema(attributeName2, TSDataType.STRING));
+    testTableNeedLastCacheDisabled.addColumnSchema(new 
TimeColumnSchema("time", TSDataType.INT64));
+    testTableNeedLastCacheDisabled.addColumnSchema(
+        new FieldColumnSchema(
+            measurement1, TSDataType.INT32, TSEncoding.RLE, 
CompressionType.GZIP));
+    testTableNeedLastCacheDisabled.addColumnSchema(
+        new FieldColumnSchema(
+            measurement2, TSDataType.INT32, TSEncoding.RLE, 
CompressionType.GZIP));
+    testTableNeedLastCacheDisabled.addColumnSchema(
+        new FieldColumnSchema(
+            measurement3, TSDataType.INT32, TSEncoding.RLE, 
CompressionType.GZIP));
+    testTableNeedLastCacheDisabled.addColumnSchema(
+        new FieldColumnSchema(
+            measurement4, TSDataType.INT32, TSEncoding.RLE, 
CompressionType.GZIP));
+    testTableNeedLastCacheDisabled.addColumnSchema(
+        new FieldColumnSchema(
+            measurement5, TSDataType.INT32, TSEncoding.RLE, 
CompressionType.GZIP));
+    testTableNeedLastCacheDisabled.addColumnSchema(
+        new FieldColumnSchema(
+            measurement6, TSDataType.INT32, TSEncoding.RLE, 
CompressionType.GZIP));
+    testTableNeedLastCacheDisabled.addProp(
+        TsTable.NEED_LAST_CACHE_PROPERTY, Boolean.FALSE.toString());
+    DataNodeTableCache.getInstance()
+        .preUpdateTable(database1, testTableNeedLastCacheDisabled, null);
+    DataNodeTableCache.getInstance().commitUpdateTable(database1, 
tableNeedLastCacheDisabled, null);
   }
 
   @AfterClass
   public static void clearEnvironment() {
     DataNodeTableCache.getInstance().invalid(database1);
     DataNodeTableCache.getInstance().invalid(database2);
-    changeSchemaCacheMemorySize(originMemConfig);
-  }
-
-  private static void changeSchemaCacheMemorySize(long size) {
-    MemoryManager memoryManager = memoryConfig.getSchemaEngineMemoryManager();
-    MemoryManager schemaCacheMemoryManager = 
memoryConfig.getSchemaCacheMemoryManager();
-    schemaCacheMemoryManager.clearAll();
-    memoryManager.releaseChildMemoryManager("schemaCache");
-    schemaCacheMemoryManager = 
memoryManager.getOrCreateMemoryManager("schemaCache", size);
-    memoryConfig.setSchemaCacheMemoryManager(schemaCacheMemoryManager);
   }
 
   @After
@@ -171,9 +187,13 @@ public class TableDeviceSchemaCacheTest {
     TableDeviceSchemaCache.getInstance().invalidateAll();
   }
 
+  private TableDeviceSchemaCache createTestCache() {
+    return TableDeviceSchemaCache.createForTest(1300L);
+  }
+
   @Test
   public void testDeviceCache() {
-    final TableDeviceSchemaCache cache = TableDeviceSchemaCache.getInstance();
+    final TableDeviceSchemaCache cache = createTestCache();
 
     final Map<String, Binary> attributeMap = new HashMap<>();
     attributeMap.put(attributeName1, new Binary("new", 
TSFileConfig.STRING_CHARSET));
@@ -257,7 +277,7 @@ public class TableDeviceSchemaCacheTest {
 
   @Test
   public void testLastCache() {
-    final TableDeviceSchemaCache cache = TableDeviceSchemaCache.getInstance();
+    final TableDeviceSchemaCache cache = createTestCache();
 
     final String[] device0 = new String[] {"hebei", "p_1", "d_0"};
 
@@ -556,7 +576,7 @@ public class TableDeviceSchemaCacheTest {
     final TimeValuePair[] testTimeValuePairs = new TimeValuePair[] {tv3, tv3, 
tv3, tv3};
 
     // Test disable put cache by writing
-    final TableDeviceSchemaCache cache = TableDeviceSchemaCache.getInstance();
+    final TableDeviceSchemaCache cache = createTestCache();
 
     cache.updateLastCacheIfExists(
         database1,
@@ -592,6 +612,124 @@ public class TableDeviceSchemaCacheTest {
         cache.getLastEntry(database1, convertTagValuesToDeviceID(table1, 
device0), "s2"));
   }
 
+  @Test
+  public void testLastCacheIsInvalidatedWhenTableNeedLastCacheTurnsFalse() {
+    final String[] device0 = new String[] {"hebei", "p_1", "d_0"};
+    final IDeviceID deviceID = convertTagValuesToDeviceID(table1, device0);
+    final String[] measurements = new String[] {measurement1};
+    final TimeValuePair[] values =
+        new TimeValuePair[] {new TimeValuePair(1L, new 
TsPrimitiveType.TsInt(1))};
+
+    final TableDeviceSchemaCache cache = TableDeviceSchemaCache.getInstance();
+    updateLastCache4Query(cache, database1, deviceID, measurements, values);
+    Assert.assertEquals(values[0], cache.getLastEntry(database1, deviceID, 
measurement1));
+
+    final TsTable disabledTable =
+        new TsTable(DataNodeTableCache.getInstance().getTable(database1, 
table1));
+    disabledTable.addProp(TsTable.NEED_LAST_CACHE_PROPERTY, 
Boolean.FALSE.toString());
+    DataNodeTableCache.getInstance().preUpdateTable(database1, disabledTable, 
null);
+    DataNodeTableCache.getInstance().commitUpdateTable(database1, table1, 
null);
+
+    try {
+      Assert.assertNull(cache.getLastEntry(database1, deviceID, measurement1));
+    } finally {
+      final TsTable enabledTable = new TsTable(disabledTable);
+      enabledTable.removeProp(TsTable.NEED_LAST_CACHE_PROPERTY);
+      DataNodeTableCache.getInstance().preUpdateTable(database1, enabledTable, 
null);
+      DataNodeTableCache.getInstance().commitUpdateTable(database1, table1, 
null);
+    }
+  }
+
+  @Test
+  public void 
testLastCacheIsInvalidatedWhenTableNeedLastCacheSetFalseWithoutCachedTable() {
+    final String database = "sg_missing_table_cache";
+    final String tableName = "t_missing_table_cache";
+    final String[] device0 = new String[] {"hebei", "p_1", "d_0"};
+    final IDeviceID deviceID = convertTagValuesToDeviceID(tableName, device0);
+    final String[] measurements = new String[] {measurement1};
+    final TimeValuePair[] values =
+        new TimeValuePair[] {new TimeValuePair(1L, new 
TsPrimitiveType.TsInt(1))};
+
+    final TsTable enabledTable =
+        new TsTable(DataNodeTableCache.getInstance().getTable(database1, 
table1));
+    enabledTable.renameTable(tableName);
+    DataNodeTableCache.getInstance().preUpdateTable(database, enabledTable, 
null);
+    DataNodeTableCache.getInstance().commitUpdateTable(database, tableName, 
null);
+
+    final TableDeviceSchemaCache cache = TableDeviceSchemaCache.getInstance();
+    updateLastCache4Query(cache, database, deviceID, measurements, values);
+    Assert.assertEquals(values[0], cache.getLastEntry(database, deviceID, 
measurement1));
+
+    try {
+      DataNodeTableCache.getInstance().invalid(database);
+      final TsTable disabledTable = new TsTable(enabledTable);
+      disabledTable.addProp(TsTable.NEED_LAST_CACHE_PROPERTY, 
Boolean.FALSE.toString());
+      DataNodeTableCache.getInstance().preUpdateTable(database, disabledTable, 
null);
+
+      Assert.assertNull(cache.getLastEntry(database, deviceID, measurement1));
+    } finally {
+      DataNodeTableCache.getInstance().invalid(database);
+    }
+  }
+
+  @Test
+  public void testLastCacheIsInvalidatedWhenDatabaseNeedLastCacheTurnsFalse() {
+    final String[] device0 = new String[] {"hebei", "p_1", "d_0"};
+    final IDeviceID deviceInDatabase1 = convertTagValuesToDeviceID(table1, 
device0);
+    final IDeviceID deviceInDatabase2 = convertTagValuesToDeviceID(table1, 
device0);
+    final String[] measurements = new String[] {measurement1};
+    final TimeValuePair[] values =
+        new TimeValuePair[] {new TimeValuePair(1L, new 
TsPrimitiveType.TsInt(1))};
+
+    final TableDeviceSchemaCache cache = TableDeviceSchemaCache.getInstance();
+    updateLastCache4Query(cache, database1, deviceInDatabase1, measurements, 
values);
+    updateLastCache4Query(cache, database2, deviceInDatabase2, measurements, 
values);
+    Assert.assertEquals(values[0], cache.getLastEntry(database1, 
deviceInDatabase1, measurement1));
+    Assert.assertEquals(values[0], cache.getLastEntry(database2, 
deviceInDatabase2, measurement1));
+
+    final PartitionCache partitionCache = new PartitionCache();
+    try {
+      final TDatabaseSchema enabledSchema = new TDatabaseSchema();
+      enabledSchema.setNeedLastCache(true);
+      partitionCache.updateDatabaseCache(Collections.singletonMap(database1, 
enabledSchema));
+      Assert.assertEquals(
+          values[0], cache.getLastEntry(database1, deviceInDatabase1, 
measurement1));
+
+      final TDatabaseSchema disabledSchema = new TDatabaseSchema();
+      disabledSchema.setNeedLastCache(false);
+      partitionCache.updateDatabaseCache(Collections.singletonMap(database1, 
disabledSchema));
+
+      Assert.assertNull(cache.getLastEntry(database1, deviceInDatabase1, 
measurement1));
+      Assert.assertEquals(
+          values[0], cache.getLastEntry(database2, deviceInDatabase2, 
measurement1));
+    } finally {
+      partitionCache.invalidAllCache();
+    }
+  }
+
+  @Test
+  public void testNeedLastCacheFalseSkipsInitLastCache() {
+    final String[] device0 = new String[] {"hebei", "p_1", "d_0"};
+    final String[] measurements = new String[] {measurement1};
+    final TimeValuePair[] values =
+        new TimeValuePair[] {new TimeValuePair(1L, new 
TsPrimitiveType.TsInt(1))};
+
+    final TableDeviceSchemaCache cache = createTestCache();
+    final IDeviceID disabledDevice =
+        convertTagValuesToDeviceID(tableNeedLastCacheDisabled, device0);
+
+    cache.initOrInvalidateLastCache(database1, disabledDevice, measurements, 
false);
+    cache.updateLastCacheIfExists(database1, disabledDevice, measurements, 
values);
+
+    Assert.assertNull(cache.getLastEntry(database1, disabledDevice, 
measurement1));
+
+    final IDeviceID enabledDevice = convertTagValuesToDeviceID(table1, 
device0);
+    cache.initOrInvalidateLastCache(database1, enabledDevice, measurements, 
false);
+    cache.updateLastCacheIfExists(database1, enabledDevice, measurements, 
values);
+
+    Assert.assertEquals(values[0], cache.getLastEntry(database1, 
enabledDevice, measurement1));
+  }
+
   private void updateLastCache4Query(
       final TableDeviceSchemaCache cache,
       final String database,
diff --git 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/column/ColumnHeaderConstant.java
 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/column/ColumnHeaderConstant.java
index 23ccb5c91db..06c361eba0a 100644
--- 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/column/ColumnHeaderConstant.java
+++ 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/column/ColumnHeaderConstant.java
@@ -259,6 +259,7 @@ public class ColumnHeaderConstant {
       "max_schema_region_group_num";
   public static final String DATA_REGION_GROUP_NUM_TABLE_MODEL = 
"data_region_group_num";
   public static final String MAX_DATA_REGION_GROUP_NUM_TABLE_MODEL = 
"max_data_region_group_num";
+  public static final String NEED_LAST_CACHE_TABLE_MODEL = "need_last_cache";
 
   public static final String REGION_ID_TABLE_MODEL = "region_id";
   public static final String DATANODE_ID_TABLE_MODEL = "datanode_id";
@@ -347,6 +348,7 @@ public class ColumnHeaderConstant {
   public static final String PRIVILEGES = "Privileges";
   public static final String COMMENT = "Comment";
   public static final String TABLE_TYPE = "TableType";
+  public static final String NEED_LAST_CACHE = "NeedLastCache";
 
   public static final String VIEW = "View";
   public static final String CREATE_VIEW = "Create View";
@@ -434,7 +436,8 @@ public class ColumnHeaderConstant {
           new ColumnHeader(SCHEMA_REGION_GROUP_NUM, TSDataType.INT32),
           new ColumnHeader(MAX_SCHEMA_REGION_GROUP_NUM, TSDataType.INT32),
           new ColumnHeader(DATA_REGION_GROUP_NUM, TSDataType.INT32),
-          new ColumnHeader(MAX_DATA_REGION_GROUP_NUM, TSDataType.INT32));
+          new ColumnHeader(MAX_DATA_REGION_GROUP_NUM, TSDataType.INT32),
+          new ColumnHeader(NEED_LAST_CACHE, TSDataType.BOOLEAN));
 
   public static final List<ColumnHeader> showChildPathsColumnHeaders =
       ImmutableList.of(
@@ -758,7 +761,8 @@ public class ColumnHeaderConstant {
           new ColumnHeader(SCHEMA_REGION_GROUP_NUM, TSDataType.INT32),
           new ColumnHeader(MAX_SCHEMA_REGION_GROUP_NUM, TSDataType.INT32),
           new ColumnHeader(DATA_REGION_GROUP_NUM, TSDataType.INT32),
-          new ColumnHeader(MAX_DATA_REGION_GROUP_NUM, TSDataType.INT32));
+          new ColumnHeader(MAX_DATA_REGION_GROUP_NUM, TSDataType.INT32),
+          new ColumnHeader(NEED_LAST_CACHE, TSDataType.BOOLEAN));
 
   public static final List<ColumnHeader> describeTableColumnHeaders =
       ImmutableList.of(
@@ -807,7 +811,8 @@ public class ColumnHeaderConstant {
           new ColumnHeader(COLUMN_TTL, TSDataType.TEXT),
           new ColumnHeader(STATUS, TSDataType.TEXT),
           new ColumnHeader(COMMENT, TSDataType.TEXT),
-          new ColumnHeader(TABLE_TYPE, TSDataType.TEXT));
+          new ColumnHeader(TABLE_TYPE, TSDataType.TEXT),
+          new ColumnHeader(NEED_LAST_CACHE, TSDataType.BOOLEAN));
 
   public static final List<ColumnHeader> 
LIST_USER_OR_ROLE_PRIVILEGES_COLUMN_HEADERS =
       ImmutableList.of(
diff --git 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/table/InformationSchema.java
 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/table/InformationSchema.java
index 645ce6d2b85..048ce8f8763 100644
--- 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/table/InformationSchema.java
+++ 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/table/InformationSchema.java
@@ -115,6 +115,10 @@ public class InformationSchema {
     databaseTable.addColumnSchema(
         new AttributeColumnSchema(
             ColumnHeaderConstant.MAX_DATA_REGION_GROUP_NUM_TABLE_MODEL, 
TSDataType.INT32));
+    databaseTable.addColumnSchema(
+        new AttributeColumnSchema(
+            ColumnHeaderConstant.NEED_LAST_CACHE_TABLE_MODEL, 
TSDataType.BOOLEAN));
+    databaseTable.removeColumnSchema(TsTable.TIME_COLUMN_NAME);
     schemaTables.put(DATABASES, databaseTable);
 
     final TsTable tableTable = new TsTable(TABLES);
@@ -134,6 +138,10 @@ public class InformationSchema {
             ColumnHeaderConstant.COMMENT.toLowerCase(Locale.ENGLISH), 
TSDataType.STRING));
     tableTable.addColumnSchema(
         new AttributeColumnSchema(ColumnHeaderConstant.TABLE_TYPE_TABLE_MODEL, 
TSDataType.STRING));
+    tableTable.addColumnSchema(
+        new AttributeColumnSchema(
+            ColumnHeaderConstant.NEED_LAST_CACHE_TABLE_MODEL, 
TSDataType.BOOLEAN));
+    tableTable.removeColumnSchema(TsTable.TIME_COLUMN_NAME);
     schemaTables.put(TABLES, tableTable);
 
     final TsTable columnTable = new TsTable(COLUMNS);
diff --git 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/table/TreeViewSchema.java
 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/table/TreeViewSchema.java
index 207e54720d7..2acbb993254 100644
--- 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/table/TreeViewSchema.java
+++ 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/table/TreeViewSchema.java
@@ -33,6 +33,8 @@ public class TreeViewSchema {
   public static final String ORIGINAL_NAME = "__original_name";
   public static final String TREE_PATH_PATTERN = "__tree_path_pattern";
   public static final String RESTRICT = "__restrict";
+  public static final String UNSUPPORTED_NEED_LAST_CACHE_PROPERTY =
+      "The tree view does not support need_last_cache property.";
 
   public static boolean isTreeViewTable(final TsTable table) {
     return table.getPropValue(TREE_PATH_PATTERN).isPresent();
diff --git 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/table/TsTable.java
 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/table/TsTable.java
index 5705336824d..14481bfa9bc 100644
--- 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/table/TsTable.java
+++ 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/table/TsTable.java
@@ -41,8 +41,10 @@ import java.io.InputStream;
 import java.io.OutputStream;
 import java.nio.ByteBuffer;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
@@ -63,7 +65,10 @@ public class TsTable {
   public static final String TIME_COLUMN_NAME = "time";
   public static final String COMMENT_KEY = "__comment";
   public static final String TTL_PROPERTY = "ttl";
-  public static final Set<String> TABLE_ALLOWED_PROPERTIES = 
Collections.singleton(TTL_PROPERTY);
+  public static final String NEED_LAST_CACHE_PROPERTY = "need_last_cache";
+  public static final Set<String> TABLE_ALLOWED_PROPERTIES =
+      Collections.unmodifiableSet(
+          new HashSet<>(Arrays.asList(TTL_PROPERTY, 
NEED_LAST_CACHE_PROPERTY)));
   private static final String OBJECT_STRING_ERROR =
       "When there are object fields, the %s %s shall not be '.', '..' or 
contain './', '.\\'.";
   protected String tableName;
@@ -90,6 +95,7 @@ public class TsTable {
 
   // Cache, avoid string parsing
   private transient long ttlValue = Long.MIN_VALUE;
+  private transient Boolean needLastCache = null;
   private transient int tagNums = 0;
   private transient int fieldNum = 0;
 
@@ -348,6 +354,14 @@ public class TsTable {
         : Long.MAX_VALUE;
   }
 
+  public boolean getCachedNeedLastCache() {
+    if (needLastCache == null) {
+      needLastCache =
+          
getPropValue(NEED_LAST_CACHE_PROPERTY).map(Boolean::parseBoolean).orElse(true);
+    }
+    return needLastCache;
+  }
+
   public Map<String, String> getProps() {
     readWriteLock.readLock().lock();
     try {
@@ -383,6 +397,7 @@ public class TsTable {
             props = new HashMap<>();
           }
           props.put(key, value);
+          invalidateCachedPropValue(key);
         });
   }
 
@@ -393,9 +408,18 @@ public class TsTable {
             return;
           }
           props.remove(key);
+          invalidateCachedPropValue(key);
         });
   }
 
+  private void invalidateCachedPropValue(final String key) {
+    if (TTL_PROPERTY.equals(key)) {
+      ttlValue = Long.MIN_VALUE;
+    } else if (NEED_LAST_CACHE_PROPERTY.equals(key)) {
+      needLastCache = null;
+    }
+  }
+
   public void serialize(final OutputStream stream) throws IOException {
     ReadWriteIOUtils.write(tableName, stream);
     ReadWriteIOUtils.write(columnSchemaMap.size(), stream);
diff --git a/iotdb-protocol/thrift-confignode/src/main/thrift/confignode.thrift 
b/iotdb-protocol/thrift-confignode/src/main/thrift/confignode.thrift
index 1111740f759..f0f2292027a 100644
--- a/iotdb-protocol/thrift-confignode/src/main/thrift/confignode.thrift
+++ b/iotdb-protocol/thrift-confignode/src/main/thrift/confignode.thrift
@@ -240,6 +240,7 @@ struct TDatabaseSchema {
     9: optional i32 maxDataRegionGroupNum
     10: optional i64 timePartitionOrigin
     11: optional bool isTableModel
+    12: optional bool needLastCache
 }
 
 // Schema
@@ -753,6 +754,7 @@ struct TDatabaseInfo {
   9: required i32 dataRegionNum
   11: required i32 maxDataRegionNum
   12: optional i64 timePartitionOrigin
+  13: optional bool needLastCache
 }
 
 struct TGetDatabaseReq {
@@ -1309,6 +1311,7 @@ struct TTableInfo {
    3: optional i32 state
    4: optional string comment
    5: optional i32 type
+   6: optional bool needLastCache
 }
 
 struct TCreateTableViewReq {

Reply via email to