You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@doris.apache.org by mo...@apache.org on 2023/06/02 04:33:39 UTC

[doris] branch master updated: [refactor](stats) Persist status of analyze task to FE meta data (#20264)

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

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


The following commit(s) were added to refs/heads/master by this push:
     new e32eba8fdf [refactor](stats) Persist status of analyze task to FE meta data (#20264)
e32eba8fdf is described below

commit e32eba8fdf42ac13aa978e14d3bd2ad6f120294f
Author: AKIRA <33...@users.noreply.github.com>
AuthorDate: Fri Jun 2 13:33:31 2023 +0900

    [refactor](stats) Persist status of analyze task to FE meta data (#20264)
    
    1. In the past, we use a BE table named `analysis_jobs` to persist the status of analyze jobs/tasks, however there are many flaws such as, if BE crashed analyze job/task would failed however the status of analyze job/task couldn't get updated.
    2. Support `DROP ANALYZE JOB [job_id]` to delete analyze job
    3. Support `SHOW ANALYZE TASK STATUS [job_id] ` to  get the task status of specific job
    4. Restrict the execute condition of auto analyze, only when  the  last execution of auto analyze job finished a while ago could be executed again
    5. Support analyze whole DB
---
 docs/en/docs/query-acceleration/statistics.md      |  74 +---
 docs/zh-CN/docs/query-acceleration/statistics.md   |  58 ++-
 .../main/java/org/apache/doris/common/Config.java  |   2 +-
 fe/fe-core/src/main/cup/sql_parser.cup             |  68 +--
 .../org/apache/doris/analysis/AnalyzeDBStmt.java   |  61 +++
 .../{AnalyzeStmt.java => AnalyzeProperties.java}   | 321 +++-----------
 .../org/apache/doris/analysis/AnalyzeStmt.java     | 419 ++----------------
 .../org/apache/doris/analysis/AnalyzeTblStmt.java  | 256 +++++++++++
 .../apache/doris/analysis/DropAnalyzeJobStmt.java  |  34 ++
 .../org/apache/doris/analysis/ShowAnalyzeStmt.java |  75 +---
 .../doris/analysis/ShowAnalyzeTaskStatus.java      |  61 +++
 .../main/java/org/apache/doris/catalog/Env.java    |  14 +-
 .../doris/catalog/InternalSchemaInitializer.java   |  78 +---
 .../java/org/apache/doris/catalog/OlapTable.java   |   8 +-
 .../main/java/org/apache/doris/catalog/Table.java  |   4 +-
 .../java/org/apache/doris/catalog/TableIf.java     |   4 +-
 .../doris/catalog/external/ExternalTable.java      |   4 +-
 .../doris/catalog/external/HMSExternalTable.java   |   4 +-
 .../org/apache/doris/journal/JournalEntity.java    |  22 +
 .../doris/nereids/stats/ExpressionEstimation.java  |   2 +-
 .../apache/doris/persist/AnalyzeDeletionLog.java   |  42 ++
 .../java/org/apache/doris/persist/EditLog.java     |  33 ++
 .../org/apache/doris/persist/OperationType.java    |   9 +
 .../main/java/org/apache/doris/qe/DdlExecutor.java |  13 +-
 .../java/org/apache/doris/qe/SessionVariable.java  |  11 -
 .../java/org/apache/doris/qe/ShowExecutor.java     |  70 +--
 .../java/org/apache/doris/qe/StmtExecutor.java     |   3 +-
 .../{AnalysisTaskInfo.java => AnalysisInfo.java}   | 134 ++++--
 ...skInfoBuilder.java => AnalysisInfoBuilder.java} |  70 +--
 .../apache/doris/statistics/AnalysisManager.java   | 481 ++++++++++++++-------
 .../apache/doris/statistics/BaseAnalysisTask.java  |  12 +-
 .../apache/doris/statistics/ColumnStatistic.java   |  19 +-
 .../apache/doris/statistics/HMSAnalysisTask.java   |   2 +-
 .../org/apache/doris/statistics/HistogramTask.java |   4 +-
 .../apache/doris/statistics/HiveAnalysisTask.java  |   2 +-
 .../doris/statistics/IcebergAnalysisTask.java      |   2 +-
 .../apache/doris/statistics/MVAnalysisTask.java    |   2 +-
 .../apache/doris/statistics/OlapAnalysisTask.java  |   2 +-
 .../doris/statistics/StatisticConstants.java       |   2 +
 .../doris/statistics/StatisticsAutoAnalyzer.java   |  30 +-
 .../apache/doris/statistics/StatisticsCleaner.java |   6 -
 .../doris/statistics/StatisticsRepository.java     | 112 +----
 .../doris/statistics/util/StatisticsUtil.java      |  22 +-
 .../apache/doris/statistics/AnalysisJobTest.java   |  15 +-
 .../doris/statistics/AnalysisTaskExecutorTest.java |  23 +-
 .../apache/doris/statistics/HistogramTaskTest.java |  19 +-
 tools/tpch-tools/conf/doris-cluster.conf           |   4 +-
 47 files changed, 1318 insertions(+), 1395 deletions(-)

diff --git a/docs/en/docs/query-acceleration/statistics.md b/docs/en/docs/query-acceleration/statistics.md
index ad01606306..c9106d9e75 100644
--- a/docs/en/docs/query-acceleration/statistics.md
+++ b/docs/en/docs/query-acceleration/statistics.md
@@ -79,15 +79,8 @@ The user triggers a manual collection job through a statement `ANALYZE` to colle
 Column statistics collection syntax:
 
 ```SQL
-ANALYZE [ SYNC ] TABLE table_name
-    [ (column_name [, ...]) ]    [ [ WITH SYNC ] [ WITH INCREMENTAL ] [ WITH SAMPLE PERCENT | ROWS ] [ WITH PERIOD ] ]    [ PROPERTIES ("key" = "value", ...) ];
-```
-
-Column histogram collection syntax:
-
-```SQL
-ANALYZE [ SYNC ] TABLE table_name
-    [ (column_name [, ...]) ]    UPDATE HISTOGRAM    [ [ WITH SYNC] [ WITH SAMPLE PERCENT | ROWS ][ WITH BUCKETS ] [ WITH PERIOD ] ]    [ PROPERTIES ("key" = "value", ...) ];
+ANALYZE TABLE | DATABASE table_name | db_name
+    [ (column_name [, ...]) ]    [ [ WITH SYNC ] [ WITH INCREMENTAL ] [ WITH SAMPLE PERCENT | ROWS ] [ WITH PERIOD ] [WITH HISTOGRAM]]    [ PROPERTIES ("key" = "value", ...) ];
 ```
 
 Explanation:
@@ -422,7 +415,7 @@ The syntax is as follows:
 
 ```SQL
 SHOW ANALYZE [ table_name | job_id ]
-    [ WHERE [ STATE = [ "PENDING" | "RUNNING" | "FINISHED" | "FAILED" ] ] ]    [ ORDER BY ... ]    [ LIMIT OFFSET ];
+    [ WHERE [ STATE = [ "PENDING" | "RUNNING" | "FINISHED" | "FAILED" ] ] ];
 ```
 
 Explanation:
@@ -450,54 +443,29 @@ Currently `SHOW ANALYZE`, 11 columns are output, as follows:
 
 Example:
 
-- View statistics job information with ID `68603`, using the following syntax:
+- View statistics job information with ID `20038`, using the following syntax:
 
 ```SQL
-mysql> SHOW ANALYZE 68603;
-+--------+--------------+----------------------------+-------------+-----------------+----------+---------------+---------+----------------------+----------+---------------+
-| job_id | catalog_name | db_name                    | tbl_name    | col_name        | job_type | analysis_type | message | last_exec_time_in_ms | state    | schedule_type |
-+--------+--------------+----------------------------+-------------+-----------------+----------+---------------+---------+----------------------+----------+---------------+
-| 68603  | internal     | default_cluster:stats_test | example_tbl |                 | MANUAL   | INDEX         |         | 2023-05-05 17:53:27  | FINISHED | ONCE          |
-| 68603  | internal     | default_cluster:stats_test | example_tbl | last_visit_date | MANUAL   | COLUMN        |         | 2023-05-05 17:53:26  | FINISHED | ONCE          |
-| 68603  | internal     | default_cluster:stats_test | example_tbl | age             | MANUAL   | COLUMN        |         | 2023-05-05 17:53:27  | FINISHED | ONCE          |
-| 68603  | internal     | default_cluster:stats_test | example_tbl | sex             | MANUAL   | COLUMN        |         | 2023-05-05 17:53:26  | FINISHED | ONCE          |
-| 68603  | internal     | default_cluster:stats_test | example_tbl | date            | MANUAL   | COLUMN        |         | 2023-05-05 17:53:27  | FINISHED | ONCE          |
-| 68603  | internal     | default_cluster:stats_test | example_tbl | user_id         | MANUAL   | COLUMN        |         | 2023-05-05 17:53:25  | FINISHED | ONCE          |
-| 68603  | internal     | default_cluster:stats_test | example_tbl | max_dwell_time  | MANUAL   | COLUMN        |         | 2023-05-05 17:53:26  | FINISHED | ONCE          |
-| 68603  | internal     | default_cluster:stats_test | example_tbl | cost            | MANUAL   | COLUMN        |         | 2023-05-05 17:53:27  | FINISHED | ONCE          |
-| 68603  | internal     | default_cluster:stats_test | example_tbl | min_dwell_time  | MANUAL   | COLUMN        |         | 2023-05-05 17:53:24  | FINISHED | ONCE          |
-| 68603  | internal     | default_cluster:stats_test | example_tbl | city            | MANUAL   | COLUMN        |         | 2023-05-05 17:53:25  | FINISHED | ONCE          |
-+--------+--------------+----------------------------+-------------+-----------------+----------+---------------+---------+----------------------+----------+---------------+
+mysql> SHOW ANALYZE 20038 
++--------+--------------+----------------------+----------+-----------------------+----------+---------------+---------+----------------------+----------+---------------+
+| job_id | catalog_name | db_name              | tbl_name | col_name              | job_type | analysis_type | message | last_exec_time_in_ms | state    | schedule_type |
++--------+--------------+----------------------+----------+-----------------------+----------+---------------+---------+----------------------+----------+---------------+
+| 20038  | internal     | default_cluster:test | t3       | [col4,col2,col3,col1] | MANUAL   | FUNDAMENTALS  |         | 2023-06-01 17:22:15  | FINISHED | ONCE          |
++--------+--------------+----------------------+----------+-----------------------+----------+---------------+---------+----------------------+----------+---------------+
+
 ```
 
-- To view `example_tbl` statistics job information for a table, use the following syntax:
+```
+mysql> show analyze task status  20038 ;
++---------+----------+---------+----------------------+----------+
+| task_id | col_name | message | last_exec_time_in_ms | state    |
++---------+----------+---------+----------------------+----------+
+| 20039   | col4     |         | 2023-06-01 17:22:15  | FINISHED |
+| 20040   | col2     |         | 2023-06-01 17:22:15  | FINISHED |
+| 20041   | col3     |         | 2023-06-01 17:22:15  | FINISHED |
+| 20042   | col1     |         | 2023-06-01 17:22:15  | FINISHED |
++---------+----------+---------+----------------------+----------+
 
-```SQL
-mysql> SHOW ANALYZE stats_test.example_tbl;
-+--------+--------------+----------------------------+-------------+-----------------+----------+---------------+---------+----------------------+----------+---------------+
-| job_id | catalog_name | db_name                    | tbl_name    | col_name        | job_type | analysis_type | message | last_exec_time_in_ms | state    | schedule_type |
-+--------+--------------+----------------------------+-------------+-----------------+----------+---------------+---------+----------------------+----------+---------------+
-| 68603  | internal     | default_cluster:stats_test | example_tbl |                 | MANUAL   | INDEX         |         | 2023-05-05 17:53:27  | FINISHED | ONCE          |
-| 68603  | internal     | default_cluster:stats_test | example_tbl | last_visit_date | MANUAL   | COLUMN        |         | 2023-05-05 17:53:26  | FINISHED | ONCE          |
-| 68603  | internal     | default_cluster:stats_test | example_tbl | age             | MANUAL   | COLUMN        |         | 2023-05-05 17:53:27  | FINISHED | ONCE          |
-| 68603  | internal     | default_cluster:stats_test | example_tbl | city            | MANUAL   | COLUMN        |         | 2023-05-05 17:53:25  | FINISHED | ONCE          |
-| 68603  | internal     | default_cluster:stats_test | example_tbl | cost            | MANUAL   | COLUMN        |         | 2023-05-05 17:53:27  | FINISHED | ONCE          |
-| 68603  | internal     | default_cluster:stats_test | example_tbl | min_dwell_time  | MANUAL   | COLUMN        |         | 2023-05-05 17:53:24  | FINISHED | ONCE          |
-| 68603  | internal     | default_cluster:stats_test | example_tbl | date            | MANUAL   | COLUMN        |         | 2023-05-05 17:53:27  | FINISHED | ONCE          |
-| 68603  | internal     | default_cluster:stats_test | example_tbl | user_id         | MANUAL   | COLUMN        |         | 2023-05-05 17:53:25  | FINISHED | ONCE          |
-| 68603  | internal     | default_cluster:stats_test | example_tbl | max_dwell_time  | MANUAL   | COLUMN        |         | 2023-05-05 17:53:26  | FINISHED | ONCE          |
-| 68603  | internal     | default_cluster:stats_test | example_tbl | sex             | MANUAL   | COLUMN        |         | 2023-05-05 17:53:26  | FINISHED | ONCE          |
-| 68678  | internal     | default_cluster:stats_test | example_tbl | user_id         | MANUAL   | HISTOGRAM     |         | 2023-05-05 18:00:11  | FINISHED | ONCE          |
-| 68678  | internal     | default_cluster:stats_test | example_tbl | sex             | MANUAL   | HISTOGRAM     |         | 2023-05-05 18:00:09  | FINISHED | ONCE          |
-| 68678  | internal     | default_cluster:stats_test | example_tbl | last_visit_date | MANUAL   | HISTOGRAM     |         | 2023-05-05 18:00:10  | FINISHED | ONCE          |
-| 68678  | internal     | default_cluster:stats_test | example_tbl | date            | MANUAL   | HISTOGRAM     |         | 2023-05-05 18:00:10  | FINISHED | ONCE          |
-| 68678  | internal     | default_cluster:stats_test | example_tbl | cost            | MANUAL   | HISTOGRAM     |         | 2023-05-05 18:00:10  | FINISHED | ONCE          |
-| 68678  | internal     | default_cluster:stats_test | example_tbl | age             | MANUAL   | HISTOGRAM     |         | 2023-05-05 18:00:10  | FINISHED | ONCE          |
-| 68678  | internal     | default_cluster:stats_test | example_tbl | min_dwell_time  | MANUAL   | HISTOGRAM     |         | 2023-05-05 18:00:10  | FINISHED | ONCE          |
-| 68678  | internal     | default_cluster:stats_test | example_tbl | max_dwell_time  | MANUAL   | HISTOGRAM     |         | 2023-05-05 18:00:09  | FINISHED | ONCE          |
-| 68678  | internal     | default_cluster:stats_test | example_tbl |                 | MANUAL   | HISTOGRAM     |         | 2023-05-05 18:00:11  | FINISHED | ONCE          |
-| 68678  | internal     | default_cluster:stats_test | example_tbl | city            | MANUAL   | HISTOGRAM     |         | 2023-05-05 18:00:11  | FINISHED | ONCE          |
-+--------+--------------+----------------------------+-------------+-----------------+----------+---------------+---------+----------------------+----------+---------------+
 ```
 
 - View all statistics job information, and return the first 3 pieces of information in descending order of the last completion time, using the following syntax:
diff --git a/docs/zh-CN/docs/query-acceleration/statistics.md b/docs/zh-CN/docs/query-acceleration/statistics.md
index 0a8744c114..c0091507b7 100644
--- a/docs/zh-CN/docs/query-acceleration/statistics.md
+++ b/docs/zh-CN/docs/query-acceleration/statistics.md
@@ -79,19 +79,9 @@ Doris 查询优化器使用统计信息来确定查询最有效的执行计划
 列统计信息收集语法:
 
 ```SQL
-ANALYZE [ SYNC ] TABLE table_name
+ANALYZE TABLE | DATABASE table_name | db_name
     [ (column_name [, ...]) ]
-    [ [ WITH SYNC ] [ WITH INCREMENTAL ] [ WITH SAMPLE PERCENT | ROWS ] [ WITH PERIOD ] ]
-    [ PROPERTIES ("key" = "value", ...) ];
-```
-
-列直方图收集语法:
-
-```SQL
-ANALYZE [ SYNC ] TABLE table_name
-    [ (column_name [, ...]) ]
-    UPDATE HISTOGRAM
-    [ [ WITH SYNC] [ WITH SAMPLE PERCENT | ROWS ][ WITH BUCKETS ] [ WITH PERIOD ] ]
+    [ [ WITH SYNC ] [ WITH INCREMENTAL ] [ WITH SAMPLE PERCENT | ROWS ] [ WITH PERIOD ] [WITH HISTOGRAM]]
     [ PROPERTIES ("key" = "value", ...) ];
 ```
 
@@ -456,9 +446,7 @@ mysql> ANALYZE TABLE stats_test.example_tbl UPDATE HISTOGRAM WITH PERIOD 86400;
 
 ```SQL
 SHOW ANALYZE [ table_name | job_id ]
-    [ WHERE [ STATE = [ "PENDING" | "RUNNING" | "FINISHED" | "FAILED" ] ] ]
-    [ ORDER BY ... ]
-    [ LIMIT OFFSET ];
+    [ WHERE [ STATE = [ "PENDING" | "RUNNING" | "FINISHED" | "FAILED" ] ] ];
 ```
 
 其中:
@@ -486,24 +474,32 @@ SHOW ANALYZE [ table_name | job_id ]
 
 示例:
 
-- 查看 ID 为 `68603` 的统计任务信息,使用以下语法:
+- 查看 ID 为 `20038` 的统计任务信息,使用以下语法:
 
 ```SQL
-mysql> SHOW ANALYZE 68603;
-+--------+--------------+----------------------------+-------------+-----------------+----------+---------------+---------+----------------------+----------+---------------+
-| job_id | catalog_name | db_name                    | tbl_name    | col_name        | job_type | analysis_type | message | last_exec_time_in_ms | state    | schedule_type |
-+--------+--------------+----------------------------+-------------+-----------------+----------+---------------+---------+----------------------+----------+---------------+
-| 68603  | internal     | default_cluster:stats_test | example_tbl |                 | MANUAL   | INDEX         |         | 2023-05-05 17:53:27  | FINISHED | ONCE          |
-| 68603  | internal     | default_cluster:stats_test | example_tbl | last_visit_date | MANUAL   | COLUMN        |         | 2023-05-05 17:53:26  | FINISHED | ONCE          |
-| 68603  | internal     | default_cluster:stats_test | example_tbl | age             | MANUAL   | COLUMN        |         | 2023-05-05 17:53:27  | FINISHED | ONCE          |
-| 68603  | internal     | default_cluster:stats_test | example_tbl | sex             | MANUAL   | COLUMN        |         | 2023-05-05 17:53:26  | FINISHED | ONCE          |
-| 68603  | internal     | default_cluster:stats_test | example_tbl | date            | MANUAL   | COLUMN        |         | 2023-05-05 17:53:27  | FINISHED | ONCE          |
-| 68603  | internal     | default_cluster:stats_test | example_tbl | user_id         | MANUAL   | COLUMN        |         | 2023-05-05 17:53:25  | FINISHED | ONCE          |
-| 68603  | internal     | default_cluster:stats_test | example_tbl | max_dwell_time  | MANUAL   | COLUMN        |         | 2023-05-05 17:53:26  | FINISHED | ONCE          |
-| 68603  | internal     | default_cluster:stats_test | example_tbl | cost            | MANUAL   | COLUMN        |         | 2023-05-05 17:53:27  | FINISHED | ONCE          |
-| 68603  | internal     | default_cluster:stats_test | example_tbl | min_dwell_time  | MANUAL   | COLUMN        |         | 2023-05-05 17:53:24  | FINISHED | ONCE          |
-| 68603  | internal     | default_cluster:stats_test | example_tbl | city            | MANUAL   | COLUMN        |         | 2023-05-05 17:53:25  | FINISHED | ONCE          |
-+--------+--------------+----------------------------+-------------+-----------------+----------+---------------+---------+----------------------+----------+---------------+
+mysql> SHOW ANALYZE 20038 
++--------+--------------+----------------------+----------+-----------------------+----------+---------------+---------+----------------------+----------+---------------+
+| job_id | catalog_name | db_name              | tbl_name | col_name              | job_type | analysis_type | message | last_exec_time_in_ms | state    | schedule_type |
++--------+--------------+----------------------+----------+-----------------------+----------+---------------+---------+----------------------+----------+---------------+
+| 20038  | internal     | default_cluster:test | t3       | [col4,col2,col3,col1] | MANUAL   | FUNDAMENTALS  |         | 2023-06-01 17:22:15  | FINISHED | ONCE          |
++--------+--------------+----------------------+----------+-----------------------+----------+---------------+---------+----------------------+----------+---------------+
+
+```
+
+可通过`SHOW ANALYZE TASK STATUS [job_id]`,查看具体每个列统计信息的收集完成情况。
+
+```
+mysql> show analyze task status  20038 ;
++---------+----------+---------+----------------------+----------+
+| task_id | col_name | message | last_exec_time_in_ms | state    |
++---------+----------+---------+----------------------+----------+
+| 20039   | col4     |         | 2023-06-01 17:22:15  | FINISHED |
+| 20040   | col2     |         | 2023-06-01 17:22:15  | FINISHED |
+| 20041   | col3     |         | 2023-06-01 17:22:15  | FINISHED |
+| 20042   | col1     |         | 2023-06-01 17:22:15  | FINISHED |
++---------+----------+---------+----------------------+----------+
+
+
 ```
 
 - 查看 `example_tbl` 表的的统计任务信息,使用以下语法:
diff --git a/fe/fe-common/src/main/java/org/apache/doris/common/Config.java b/fe/fe-common/src/main/java/org/apache/doris/common/Config.java
index d88fcfc8a8..f1ae503ed1 100644
--- a/fe/fe-common/src/main/java/org/apache/doris/common/Config.java
+++ b/fe/fe-common/src/main/java/org/apache/doris/common/Config.java
@@ -1445,7 +1445,7 @@ public class Config extends ConfigBase {
      * the system automatically checks the time interval for statistics
      */
     @ConfField(mutable = true, masterOnly = true)
-    public static int auto_check_statistics_in_sec = 300;
+    public static int auto_check_statistics_in_minutes = 5;
 
     /**
      * If this configuration is enabled, you should also specify the trace_export_url.
diff --git a/fe/fe-core/src/main/cup/sql_parser.cup b/fe/fe-core/src/main/cup/sql_parser.cup
index f6641db081..6542ad40e4 100644
--- a/fe/fe-core/src/main/cup/sql_parser.cup
+++ b/fe/fe-core/src/main/cup/sql_parser.cup
@@ -930,7 +930,6 @@ nonterminal MVRefreshInfo.RefreshMethod opt_refresh_method;
 nonterminal MVRefreshTriggerInfo opt_refresh_trigger;
 nonterminal MVRefreshInfo opt_mv_refersh_info;
 nonterminal PartitionDesc opt_mv_partition;
-nonterminal Boolean opt_sync;
 
 
 precedence nonassoc COMMA;
@@ -2788,7 +2787,7 @@ show_create_reporitory_stmt ::=
 // analyze statment
 analyze_stmt ::=
     // statistics
-    KW_ANALYZE opt_sync:sync KW_TABLE table_name:tbl opt_col_list:cols
+    KW_ANALYZE KW_TABLE table_name:tbl opt_col_list:cols
       opt_with_analysis_properties:withAnalysisProperties opt_properties:properties
     {:
         if (properties == null) {
@@ -2797,22 +2796,31 @@ analyze_stmt ::=
         for (Map<String, String> property : withAnalysisProperties) {
             properties.putAll(property);
         }
-        if (!properties.containsKey("sync")) {
-            properties.put("sync", String.valueOf(sync));
+        // Rule: If no type is specified, see if there is a specified column
+        if (!properties.containsKey("analysis.type")) {
+            properties.put("analysis.type", "FUNDAMENTALS");
+        }
+        AnalyzeProperties analyzeProperties= new AnalyzeProperties(properties);
+        RESULT = new AnalyzeTblStmt(tbl, cols, analyzeProperties);
+    :}
+    | KW_ANALYZE KW_DATABASE ident:ctlName DOT ident:dbName
+          opt_with_analysis_properties:withAnalysisProperties opt_properties:properties
+    {:
+        if (properties == null) {
+            properties = Maps.newHashMap();
+        }
+        for (Map<String, String> property : withAnalysisProperties) {
+            properties.putAll(property);
         }
         // Rule: If no type is specified, see if there is a specified column
         if (!properties.containsKey("analysis.type")) {
-            if ((cols == null)) {
-                properties.put("analysis.type", "INDEX");
-            } else {
-                properties.put("analysis.type", "COLUMN");
-            }
+            properties.put("analysis.type", "FUNDAMENTALS");
         }
-        RESULT = new AnalyzeStmt(tbl, cols, properties);
+        AnalyzeProperties analyzeProperties= new AnalyzeProperties(properties);
+        RESULT = new AnalyzeDBStmt(ctlName, dbName, analyzeProperties);
     :}
-    // histogram
-    | KW_ANALYZE opt_sync:sync KW_TABLE table_name:tbl opt_col_list:cols KW_UPDATE KW_HISTOGRAM
-      opt_with_analysis_properties:withAnalysisProperties opt_properties:properties
+    | KW_ANALYZE KW_DATABASE ident:dbName
+          opt_with_analysis_properties:withAnalysisProperties opt_properties:properties
     {:
         if (properties == null) {
             properties = Maps.newHashMap();
@@ -2820,12 +2828,12 @@ analyze_stmt ::=
         for (Map<String, String> property : withAnalysisProperties) {
             properties.putAll(property);
         }
-        if (!properties.containsKey("sync")) {
-            properties.put("sync", String.valueOf(sync));
+        // Rule: If no type is specified, see if there is a specified column
+        if (!properties.containsKey("analysis.type")) {
+            properties.put("analysis.type", "FUNDAMENTALS");
         }
-        // TODO: Support materialized view
-        properties.put("analysis.type", "HISTOGRAM");
-        RESULT = new AnalyzeStmt(tbl, cols, properties);
+        AnalyzeProperties analyzeProperties= new AnalyzeProperties(properties);
+        RESULT = new AnalyzeDBStmt(null, dbName, analyzeProperties);
     :}
     ;
 
@@ -3011,6 +3019,10 @@ drop_stmt ::=
     {:
         RESULT = new DropStatsStmt(true);
     :}
+    | KW_DROP KW_ANALYZE KW_JOB INTEGER_LITERAL:job_id
+    {:
+        RESULT = new DropAnalyzeJobStmt(job_id);
+    :}
     ;
 
 // Recover statement
@@ -4013,6 +4025,10 @@ show_param ::=
     {:
         RESULT = new ShowAnalyzeStmt(jobId, parser.where, orderByClause, limitClause);
     :}
+    | KW_ANALYZE KW_TASK KW_STATUS INTEGER_LITERAL:jobId
+    {:
+        RESULT = new ShowAnalyzeTaskStatus(jobId);
+    :}
     | KW_CATALOG KW_RECYCLE KW_BIN opt_wild_where
     {:
         RESULT = new ShowCatalogRecycleBinStmt(parser.where);
@@ -5817,6 +5833,12 @@ with_analysis_properties ::=
             put("period.seconds", String.valueOf(periodInSec.intValue()));
         }};
     :}
+    | KW_HISTOGRAM
+    {:
+        RESULT = new HashMap<String, String>() {{
+            put("analysis.type", "HISTOGRAM");
+        }};
+    :}
     ;
 
 opt_with_analysis_properties ::=
@@ -7109,16 +7131,6 @@ type_func_name_keyword ::=
     {: RESULT = id; :}
     ;
 
-opt_sync ::=
-    {:
-        RESULT = false;
-    :}
-    | KW_SYNC
-    {:
-        RESULT = true;
-    :}
-    ;
-
 // Keyword that we allow for identifiers
 keyword ::=
     KW_AFTER:id
diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/AnalyzeDBStmt.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/AnalyzeDBStmt.java
new file mode 100644
index 0000000000..db155f07ae
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/AnalyzeDBStmt.java
@@ -0,0 +1,61 @@
+// 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.doris.analysis;
+
+import org.apache.doris.catalog.DatabaseIf;
+import org.apache.doris.catalog.Env;
+import org.apache.doris.catalog.TableIf;
+import org.apache.doris.cluster.ClusterNamespace;
+import org.apache.doris.common.AnalysisException;
+import org.apache.doris.common.UserException;
+import org.apache.doris.datasource.CatalogIf;
+import org.apache.doris.qe.ConnectContext;
+
+public class AnalyzeDBStmt extends AnalyzeStmt {
+
+    private final String ctlName;
+    private final String dbName;
+
+    private CatalogIf ctlIf;
+
+    private DatabaseIf<TableIf> db;
+
+    public AnalyzeDBStmt(String ctlName, String dbName, AnalyzeProperties analyzeProperties) {
+        super(analyzeProperties);
+        this.ctlName = ctlName;
+        this.dbName = ConnectContext.get().getClusterName() + ClusterNamespace.CLUSTER_DELIMITER + dbName;
+    }
+
+    @Override
+    public void analyze(Analyzer analyzer) throws AnalysisException, UserException {
+        if (ctlName == null) {
+            ctlIf = Env.getCurrentInternalCatalog();
+        } else {
+            ctlIf = Env.getCurrentEnv().getCatalogMgr().getCatalogOrAnalysisException(ctlName);
+        }
+        db = ctlIf.getDbOrAnalysisException(dbName);
+    }
+
+    public CatalogIf getCtlIf() {
+        return ctlIf;
+    }
+
+    public DatabaseIf<TableIf> getDb() {
+        return db;
+    }
+}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/AnalyzeStmt.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/AnalyzeProperties.java
similarity index 53%
copy from fe/fe-core/src/main/java/org/apache/doris/analysis/AnalyzeStmt.java
copy to fe/fe-core/src/main/java/org/apache/doris/analysis/AnalyzeProperties.java
index a8d004f199..ccb122bc26 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/analysis/AnalyzeStmt.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/AnalyzeProperties.java
@@ -17,71 +17,21 @@
 
 package org.apache.doris.analysis;
 
-import org.apache.doris.catalog.Column;
-import org.apache.doris.catalog.Database;
-import org.apache.doris.catalog.DatabaseIf;
-import org.apache.doris.catalog.Env;
-import org.apache.doris.catalog.OlapTable;
-import org.apache.doris.catalog.TableIf;
-import org.apache.doris.catalog.View;
 import org.apache.doris.common.AnalysisException;
-import org.apache.doris.common.Config;
-import org.apache.doris.common.ErrorCode;
-import org.apache.doris.common.ErrorReport;
-import org.apache.doris.common.FeNameFormat;
-import org.apache.doris.common.UserException;
 import org.apache.doris.common.util.PrintableMap;
-import org.apache.doris.datasource.CatalogIf;
-import org.apache.doris.mysql.privilege.PrivPredicate;
-import org.apache.doris.qe.ConnectContext;
-import org.apache.doris.statistics.AnalysisTaskInfo.AnalysisMethod;
-import org.apache.doris.statistics.AnalysisTaskInfo.AnalysisMode;
-import org.apache.doris.statistics.AnalysisTaskInfo.AnalysisType;
-import org.apache.doris.statistics.AnalysisTaskInfo.ScheduleType;
+import org.apache.doris.statistics.AnalysisInfo.AnalysisType;
 
 import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Sets;
 import org.apache.commons.lang3.StringUtils;
 
-import java.util.List;
 import java.util.Map;
 import java.util.Optional;
-import java.util.Set;
 import java.util.concurrent.TimeUnit;
-import java.util.stream.Collectors;
-
-/**
-  * Column Statistics Collection Syntax:
-  *   ANALYZE [ SYNC ] TABLE table_name
-  *   [ (column_name [, ...]) ]
-  *   [ [WITH SYNC] | [WITH INCREMENTAL] | [WITH SAMPLE PERCENT | ROWS ] ]
-  *   [ PROPERTIES ('key' = 'value', ...) ];
-  *
-  * Column histogram collection syntax:
-  *   ANALYZE [ SYNC ] TABLE table_name
-  *   [ (column_name [, ...]) ]
-  *   UPDATE HISTOGRAM
-  *   [ [ WITH SYNC ][ WITH INCREMENTAL ][ WITH SAMPLE PERCENT | ROWS ][ WITH BUCKETS ] ]
-  *   [ PROPERTIES ('key' = 'value', ...) ];
-  *
-  * Illustrate:
-  * - sync:Collect statistics synchronously. Return after collecting.
-  * - incremental:Collect statistics incrementally. Incremental collection of histogram statistics is not supported.
-  * - sample percent | rows:Collect statistics by sampling. Scale and number of rows can be sampled.
-  * - buckets:Specifies the maximum number of buckets generated when collecting histogram statistics.
-  * - table_name: The purpose table for collecting statistics. Can be of the form `db_name.table_name`.
-  * - column_name: The specified destination column must be a column that exists in `table_name`,
- *    and multiple column names are separated by commas.
-  * - properties:Properties used to set statistics tasks. Currently only the following configurations
- *    are supported (equivalent to the with statement)
-  *    - 'sync' = 'true'
-  *    - 'incremental' = 'true'
-  *    - 'sample.percent' = '50'
-  *    - 'sample.rows' = '1000'
-  *    - 'num.buckets' = 10
- */
-public class AnalyzeStmt extends DdlStmt {
-    // The properties passed in by the user through "with" or "properties('K', 'V')"
+
+public class AnalyzeProperties {
+
+    private final Map<String, String> properties;
+
     public static final String PROPERTY_SYNC = "sync";
     public static final String PROPERTY_INCREMENTAL = "incremental";
     public static final String PROPERTY_AUTOMATIC = "automatic";
@@ -102,97 +52,11 @@ public class AnalyzeStmt extends DdlStmt {
             .add(PROPERTY_PERIOD_SECONDS)
             .build();
 
-    private final TableName tableName;
-    private final List<String> columnNames;
-    private final Map<String, String> properties;
-
-    // after analyzed
-    private long dbId;
-    private TableIf table;
-
-    public AnalyzeStmt(TableName tableName,
-            List<String> columnNames,
-            Map<String, String> properties) {
-        this.tableName = tableName;
-        this.columnNames = columnNames;
+    public AnalyzeProperties(Map<String, String> properties) {
         this.properties = properties;
     }
 
-    @Override
-    @SuppressWarnings({"rawtypes"})
-    public void analyze(Analyzer analyzer) throws UserException {
-        if (!Config.enable_stats) {
-            throw new UserException("Analyze function is forbidden, you should add `enable_stats=true`"
-                    + "in your FE conf file");
-        }
-        super.analyze(analyzer);
-
-        tableName.analyze(analyzer);
-
-        String catalogName = tableName.getCtl();
-        String dbName = tableName.getDb();
-        String tblName = tableName.getTbl();
-        CatalogIf catalog = analyzer.getEnv().getCatalogMgr()
-                .getCatalogOrAnalysisException(catalogName);
-        DatabaseIf db = catalog.getDbOrAnalysisException(dbName);
-        dbId = db.getId();
-        table = db.getTableOrAnalysisException(tblName);
-        if (table instanceof View) {
-            throw new AnalysisException("Analyze view is not allowed");
-        }
-        checkAnalyzePriv(dbName, tblName);
-
-        if (columnNames != null && !columnNames.isEmpty()) {
-            table.readLock();
-            try {
-                List<String> baseSchema = table.getBaseSchema(false)
-                        .stream().map(Column::getName).collect(Collectors.toList());
-                Optional<String> optional = columnNames.stream()
-                        .filter(entity -> !baseSchema.contains(entity)).findFirst();
-                if (optional.isPresent()) {
-                    String columnName = optional.get();
-                    ErrorReport.reportAnalysisException(ErrorCode.ERR_WRONG_COLUMN_NAME,
-                            columnName, FeNameFormat.getColumnNameRegex());
-                }
-            } finally {
-                table.readUnlock();
-            }
-        }
-
-        checkProperties();
-
-        // TODO support external table
-        if (properties.containsKey(PROPERTY_SAMPLE_PERCENT)
-                || properties.containsKey(PROPERTY_SAMPLE_ROWS)) {
-            if (!(table instanceof OlapTable)) {
-                throw new AnalysisException("Sampling statistics "
-                        + "collection of external tables is not supported");
-            }
-        }
-    }
-
-    @Override
-    public RedirectStatus getRedirectStatus() {
-        return RedirectStatus.FORWARD_NO_SYNC;
-    }
-
-    private void checkAnalyzePriv(String dbName, String tblName) throws AnalysisException {
-        if (!Env.getCurrentEnv().getAccessManager()
-                .checkTblPriv(ConnectContext.get(), dbName, tblName, PrivPredicate.SELECT)) {
-            ErrorReport.reportAnalysisException(
-                    ErrorCode.ERR_TABLEACCESS_DENIED_ERROR,
-                    "ANALYZE",
-                    ConnectContext.get().getQualifiedUser(),
-                    ConnectContext.get().getRemoteIP(),
-                    dbName + ": " + tblName);
-        }
-    }
-
-    private void checkProperties() throws UserException {
-        if (properties == null || properties.isEmpty()) {
-            throw new AnalysisException("analysis properties should not be empty");
-        }
-
+    public void check() throws AnalysisException {
         String msgTemplate = "%s = %s is invalid property";
         Optional<String> optional = properties.keySet().stream().filter(
                 entity -> !PROPERTIES_SET.contains(entity)).findFirst();
@@ -201,7 +65,6 @@ public class AnalyzeStmt extends DdlStmt {
             String msg = String.format(msgTemplate, optional.get(), properties.get(optional.get()));
             throw new AnalysisException(msg);
         }
-
         checkSampleValue();
         checkPeriodSeconds();
         checkNumBuckets();
@@ -211,6 +74,47 @@ public class AnalyzeStmt extends DdlStmt {
         checkScheduleType(msgTemplate);
     }
 
+    public boolean isSync() {
+        return Boolean.parseBoolean(properties.get(PROPERTY_SYNC));
+    }
+
+    public boolean isIncremental() {
+        return Boolean.parseBoolean(properties.get(PROPERTY_INCREMENTAL));
+    }
+
+    public boolean isAutomatic() {
+        return Boolean.parseBoolean(properties.get(PROPERTY_AUTOMATIC));
+    }
+
+    public int getSamplePercent() {
+        if (!properties.containsKey(PROPERTY_SAMPLE_PERCENT)) {
+            return 0;
+        }
+        return Integer.parseInt(properties.get(PROPERTY_SAMPLE_PERCENT));
+    }
+
+    public int getSampleRows() {
+        if (!properties.containsKey(PROPERTY_SAMPLE_ROWS)) {
+            return 0;
+        }
+        return Integer.parseInt(properties.get(PROPERTY_SAMPLE_ROWS));
+    }
+
+    public int getNumBuckets() {
+        if (!properties.containsKey(PROPERTY_NUM_BUCKETS)) {
+            return 0;
+        }
+        return Integer.parseInt(properties.get(PROPERTY_NUM_BUCKETS));
+    }
+
+    public long getPeriodTimeInMs() {
+        if (!properties.containsKey(PROPERTY_PERIOD_SECONDS)) {
+            return 0;
+        }
+        int minutes = Integer.parseInt(properties.get(PROPERTY_PERIOD_SECONDS));
+        return TimeUnit.SECONDS.toMillis(minutes);
+    }
+
     private void checkPeriodSeconds() throws AnalysisException {
         if (properties.containsKey(PROPERTY_PERIOD_SECONDS)) {
             checkNumericProperty(PROPERTY_PERIOD_SECONDS, properties.get(PROPERTY_PERIOD_SECONDS),
@@ -317,131 +221,26 @@ public class AnalyzeStmt extends DdlStmt {
         }
     }
 
-    public String getCatalogName() {
-        return tableName.getCtl();
-    }
-
-    public long getDbId() {
-        return dbId;
+    public boolean isSample() {
+        return properties.containsKey(PROPERTY_SAMPLE_PERCENT)
+                || properties.containsKey(PROPERTY_SAMPLE_ROWS);
     }
 
-    public String getDBName() {
-        return tableName.getDb();
-    }
-
-    public Database getDb() throws AnalysisException {
-        return analyzer.getEnv().getInternalCatalog().getDbOrAnalysisException(dbId);
-    }
-
-    public TableIf getTable() {
-        return table;
-    }
-
-    public TableName getTblName() {
-        return tableName;
-    }
-
-    public Set<String> getColumnNames() {
-        return columnNames == null ? table.getBaseSchema(false)
-                .stream().map(Column::getName).collect(Collectors.toSet()) : Sets.newHashSet(columnNames);
+    public String toSQL() {
+        StringBuilder sb = new StringBuilder();
+        sb.append("PROPERTIES(");
+        sb.append(new PrintableMap<>(properties, " = ",
+                true,
+                false));
+        sb.append(")");
+        return sb.toString();
     }
 
     public Map<String, String> getProperties() {
         return properties;
     }
 
-    public boolean isSync() {
-        return Boolean.parseBoolean(properties.get(PROPERTY_SYNC));
-    }
-
-    public boolean isIncremental() {
-        return Boolean.parseBoolean(properties.get(PROPERTY_INCREMENTAL));
-    }
-
-    public boolean isAutomatic() {
-        return Boolean.parseBoolean(properties.get(PROPERTY_AUTOMATIC));
-    }
-
-    public int getSamplePercent() {
-        if (!properties.containsKey(PROPERTY_SAMPLE_PERCENT)) {
-            return 0;
-        }
-        return Integer.parseInt(properties.get(PROPERTY_SAMPLE_PERCENT));
-    }
-
-    public int getSampleRows() {
-        if (!properties.containsKey(PROPERTY_SAMPLE_ROWS)) {
-            return 0;
-        }
-        return Integer.parseInt(properties.get(PROPERTY_SAMPLE_ROWS));
-    }
-
-    public int getNumBuckets() {
-        if (!properties.containsKey(PROPERTY_NUM_BUCKETS)) {
-            return 0;
-        }
-        return Integer.parseInt(properties.get(PROPERTY_NUM_BUCKETS));
-    }
-
-    public long getPeriodTimeInMs() {
-        if (!properties.containsKey(PROPERTY_PERIOD_SECONDS)) {
-            return 0;
-        }
-        int minutes = Integer.parseInt(properties.get(PROPERTY_PERIOD_SECONDS));
-        return TimeUnit.SECONDS.toMillis(minutes);
-    }
-
-    public AnalysisMode getAnalysisMode() {
-        return isIncremental() ? AnalysisMode.INCREMENTAL : AnalysisMode.FULL;
-    }
-
     public AnalysisType getAnalysisType() {
         return AnalysisType.valueOf(properties.get(PROPERTY_ANALYSIS_TYPE));
     }
-
-    public AnalysisMethod getAnalysisMethod() {
-        double samplePercent = getSamplePercent();
-        int sampleRows = getSampleRows();
-        return (samplePercent > 0 || sampleRows > 0) ? AnalysisMethod.SAMPLE : AnalysisMethod.FULL;
-    }
-
-    public ScheduleType getScheduleType() {
-        if (isAutomatic()) {
-            return ScheduleType.AUTOMATIC;
-        }
-        return getPeriodTimeInMs() > 0 ? ScheduleType.PERIOD : ScheduleType.ONCE;
-    }
-
-    @Override
-    public String toSql() {
-        StringBuilder sb = new StringBuilder();
-        sb.append("ANALYZE TABLE ");
-
-        if (tableName != null) {
-            sb.append(" ");
-            sb.append(tableName.toSql());
-        }
-
-        if (columnNames != null) {
-            sb.append("(");
-            sb.append(StringUtils.join(columnNames, ","));
-            sb.append(")");
-        }
-
-        if (getAnalysisType().equals(AnalysisType.HISTOGRAM)) {
-            sb.append(" ");
-            sb.append("UPDATE HISTOGRAM");
-        }
-
-        if (properties != null) {
-            sb.append(" ");
-            sb.append("PROPERTIES(");
-            sb.append(new PrintableMap<>(properties, " = ",
-                    true,
-                    false));
-            sb.append(")");
-        }
-
-        return sb.toString();
-    }
 }
diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/AnalyzeStmt.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/AnalyzeStmt.java
index a8d004f199..202a870f12 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/analysis/AnalyzeStmt.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/AnalyzeStmt.java
@@ -17,431 +17,68 @@
 
 package org.apache.doris.analysis;
 
-import org.apache.doris.catalog.Column;
-import org.apache.doris.catalog.Database;
-import org.apache.doris.catalog.DatabaseIf;
-import org.apache.doris.catalog.Env;
-import org.apache.doris.catalog.OlapTable;
-import org.apache.doris.catalog.TableIf;
-import org.apache.doris.catalog.View;
-import org.apache.doris.common.AnalysisException;
-import org.apache.doris.common.Config;
-import org.apache.doris.common.ErrorCode;
-import org.apache.doris.common.ErrorReport;
-import org.apache.doris.common.FeNameFormat;
-import org.apache.doris.common.UserException;
-import org.apache.doris.common.util.PrintableMap;
-import org.apache.doris.datasource.CatalogIf;
-import org.apache.doris.mysql.privilege.PrivPredicate;
-import org.apache.doris.qe.ConnectContext;
-import org.apache.doris.statistics.AnalysisTaskInfo.AnalysisMethod;
-import org.apache.doris.statistics.AnalysisTaskInfo.AnalysisMode;
-import org.apache.doris.statistics.AnalysisTaskInfo.AnalysisType;
-import org.apache.doris.statistics.AnalysisTaskInfo.ScheduleType;
 
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Sets;
-import org.apache.commons.lang3.StringUtils;
+import org.apache.doris.statistics.AnalysisInfo.AnalysisMethod;
+import org.apache.doris.statistics.AnalysisInfo.AnalysisMode;
+import org.apache.doris.statistics.AnalysisInfo.AnalysisType;
+import org.apache.doris.statistics.AnalysisInfo.ScheduleType;
 
-import java.util.List;
 import java.util.Map;
-import java.util.Optional;
-import java.util.Set;
-import java.util.concurrent.TimeUnit;
-import java.util.stream.Collectors;
 
-/**
-  * Column Statistics Collection Syntax:
-  *   ANALYZE [ SYNC ] TABLE table_name
-  *   [ (column_name [, ...]) ]
-  *   [ [WITH SYNC] | [WITH INCREMENTAL] | [WITH SAMPLE PERCENT | ROWS ] ]
-  *   [ PROPERTIES ('key' = 'value', ...) ];
-  *
-  * Column histogram collection syntax:
-  *   ANALYZE [ SYNC ] TABLE table_name
-  *   [ (column_name [, ...]) ]
-  *   UPDATE HISTOGRAM
-  *   [ [ WITH SYNC ][ WITH INCREMENTAL ][ WITH SAMPLE PERCENT | ROWS ][ WITH BUCKETS ] ]
-  *   [ PROPERTIES ('key' = 'value', ...) ];
-  *
-  * Illustrate:
-  * - sync:Collect statistics synchronously. Return after collecting.
-  * - incremental:Collect statistics incrementally. Incremental collection of histogram statistics is not supported.
-  * - sample percent | rows:Collect statistics by sampling. Scale and number of rows can be sampled.
-  * - buckets:Specifies the maximum number of buckets generated when collecting histogram statistics.
-  * - table_name: The purpose table for collecting statistics. Can be of the form `db_name.table_name`.
-  * - column_name: The specified destination column must be a column that exists in `table_name`,
- *    and multiple column names are separated by commas.
-  * - properties:Properties used to set statistics tasks. Currently only the following configurations
- *    are supported (equivalent to the with statement)
-  *    - 'sync' = 'true'
-  *    - 'incremental' = 'true'
-  *    - 'sample.percent' = '50'
-  *    - 'sample.rows' = '1000'
-  *    - 'num.buckets' = 10
- */
 public class AnalyzeStmt extends DdlStmt {
-    // The properties passed in by the user through "with" or "properties('K', 'V')"
-    public static final String PROPERTY_SYNC = "sync";
-    public static final String PROPERTY_INCREMENTAL = "incremental";
-    public static final String PROPERTY_AUTOMATIC = "automatic";
-    public static final String PROPERTY_SAMPLE_PERCENT = "sample.percent";
-    public static final String PROPERTY_SAMPLE_ROWS = "sample.rows";
-    public static final String PROPERTY_NUM_BUCKETS = "num.buckets";
-    public static final String PROPERTY_ANALYSIS_TYPE = "analysis.type";
-    public static final String PROPERTY_PERIOD_SECONDS = "period.seconds";
 
-    private static final ImmutableSet<String> PROPERTIES_SET = new ImmutableSet.Builder<String>()
-            .add(PROPERTY_SYNC)
-            .add(PROPERTY_INCREMENTAL)
-            .add(PROPERTY_AUTOMATIC)
-            .add(PROPERTY_SAMPLE_PERCENT)
-            .add(PROPERTY_SAMPLE_ROWS)
-            .add(PROPERTY_NUM_BUCKETS)
-            .add(PROPERTY_ANALYSIS_TYPE)
-            .add(PROPERTY_PERIOD_SECONDS)
-            .build();
+    protected AnalyzeProperties analyzeProperties;
 
-    private final TableName tableName;
-    private final List<String> columnNames;
-    private final Map<String, String> properties;
-
-    // after analyzed
-    private long dbId;
-    private TableIf table;
-
-    public AnalyzeStmt(TableName tableName,
-            List<String> columnNames,
-            Map<String, String> properties) {
-        this.tableName = tableName;
-        this.columnNames = columnNames;
-        this.properties = properties;
-    }
-
-    @Override
-    @SuppressWarnings({"rawtypes"})
-    public void analyze(Analyzer analyzer) throws UserException {
-        if (!Config.enable_stats) {
-            throw new UserException("Analyze function is forbidden, you should add `enable_stats=true`"
-                    + "in your FE conf file");
-        }
-        super.analyze(analyzer);
-
-        tableName.analyze(analyzer);
-
-        String catalogName = tableName.getCtl();
-        String dbName = tableName.getDb();
-        String tblName = tableName.getTbl();
-        CatalogIf catalog = analyzer.getEnv().getCatalogMgr()
-                .getCatalogOrAnalysisException(catalogName);
-        DatabaseIf db = catalog.getDbOrAnalysisException(dbName);
-        dbId = db.getId();
-        table = db.getTableOrAnalysisException(tblName);
-        if (table instanceof View) {
-            throw new AnalysisException("Analyze view is not allowed");
-        }
-        checkAnalyzePriv(dbName, tblName);
-
-        if (columnNames != null && !columnNames.isEmpty()) {
-            table.readLock();
-            try {
-                List<String> baseSchema = table.getBaseSchema(false)
-                        .stream().map(Column::getName).collect(Collectors.toList());
-                Optional<String> optional = columnNames.stream()
-                        .filter(entity -> !baseSchema.contains(entity)).findFirst();
-                if (optional.isPresent()) {
-                    String columnName = optional.get();
-                    ErrorReport.reportAnalysisException(ErrorCode.ERR_WRONG_COLUMN_NAME,
-                            columnName, FeNameFormat.getColumnNameRegex());
-                }
-            } finally {
-                table.readUnlock();
-            }
-        }
-
-        checkProperties();
-
-        // TODO support external table
-        if (properties.containsKey(PROPERTY_SAMPLE_PERCENT)
-                || properties.containsKey(PROPERTY_SAMPLE_ROWS)) {
-            if (!(table instanceof OlapTable)) {
-                throw new AnalysisException("Sampling statistics "
-                        + "collection of external tables is not supported");
-            }
-        }
-    }
-
-    @Override
-    public RedirectStatus getRedirectStatus() {
-        return RedirectStatus.FORWARD_NO_SYNC;
-    }
-
-    private void checkAnalyzePriv(String dbName, String tblName) throws AnalysisException {
-        if (!Env.getCurrentEnv().getAccessManager()
-                .checkTblPriv(ConnectContext.get(), dbName, tblName, PrivPredicate.SELECT)) {
-            ErrorReport.reportAnalysisException(
-                    ErrorCode.ERR_TABLEACCESS_DENIED_ERROR,
-                    "ANALYZE",
-                    ConnectContext.get().getQualifiedUser(),
-                    ConnectContext.get().getRemoteIP(),
-                    dbName + ": " + tblName);
-        }
-    }
-
-    private void checkProperties() throws UserException {
-        if (properties == null || properties.isEmpty()) {
-            throw new AnalysisException("analysis properties should not be empty");
-        }
-
-        String msgTemplate = "%s = %s is invalid property";
-        Optional<String> optional = properties.keySet().stream().filter(
-                entity -> !PROPERTIES_SET.contains(entity)).findFirst();
-
-        if (optional.isPresent()) {
-            String msg = String.format(msgTemplate, optional.get(), properties.get(optional.get()));
-            throw new AnalysisException(msg);
-        }
-
-        checkSampleValue();
-        checkPeriodSeconds();
-        checkNumBuckets();
-        checkSync(msgTemplate);
-        checkAnalysisMode(msgTemplate);
-        checkAnalysisType(msgTemplate);
-        checkScheduleType(msgTemplate);
-    }
-
-    private void checkPeriodSeconds() throws AnalysisException {
-        if (properties.containsKey(PROPERTY_PERIOD_SECONDS)) {
-            checkNumericProperty(PROPERTY_PERIOD_SECONDS, properties.get(PROPERTY_PERIOD_SECONDS),
-                    1, Integer.MAX_VALUE, true, "needs at least 1 seconds");
-        }
-    }
-
-    private void checkSampleValue() throws AnalysisException {
-        if (properties.containsKey(PROPERTY_SAMPLE_PERCENT)
-                && properties.containsKey(PROPERTY_SAMPLE_ROWS)) {
-            throw new AnalysisException("only one sampling parameter can be specified simultaneously");
-        }
-
-        if (properties.containsKey(PROPERTY_SAMPLE_PERCENT)) {
-            checkNumericProperty(PROPERTY_SAMPLE_PERCENT, properties.get(PROPERTY_SAMPLE_PERCENT),
-                    1, 100, true, "should be >= 1 and <= 100");
-        }
-
-        if (properties.containsKey(PROPERTY_SAMPLE_ROWS)) {
-            checkNumericProperty(PROPERTY_SAMPLE_ROWS, properties.get(PROPERTY_SAMPLE_ROWS),
-                    0, Integer.MAX_VALUE, false, "needs at least 1 row");
-        }
-    }
-
-    private void checkNumBuckets() throws AnalysisException {
-        if (properties.containsKey(PROPERTY_NUM_BUCKETS)) {
-            checkNumericProperty(PROPERTY_NUM_BUCKETS, properties.get(PROPERTY_NUM_BUCKETS),
-                    1, Integer.MAX_VALUE, true, "needs at least 1 buckets");
-        }
-
-        if (properties.containsKey(PROPERTY_NUM_BUCKETS)
-                && AnalysisType.valueOf(properties.get(PROPERTY_ANALYSIS_TYPE)) != AnalysisType.HISTOGRAM) {
-            throw new AnalysisException(PROPERTY_NUM_BUCKETS + " can only be specified when collecting histograms");
-        }
+    public AnalyzeStmt(AnalyzeProperties analyzeProperties) {
+        this.analyzeProperties = analyzeProperties;
     }
 
-    private void checkSync(String msgTemplate) throws AnalysisException {
-        if (properties.containsKey(PROPERTY_SYNC)) {
-            try {
-                Boolean.valueOf(properties.get(PROPERTY_SYNC));
-            } catch (NumberFormatException e) {
-                String msg = String.format(msgTemplate, PROPERTY_SYNC, properties.get(PROPERTY_SYNC));
-                throw new AnalysisException(msg);
-            }
-        }
+    public Map<String, String> getProperties() {
+        return analyzeProperties.getProperties();
     }
 
-    private void checkAnalysisMode(String msgTemplate) throws AnalysisException {
-        if (properties.containsKey(PROPERTY_INCREMENTAL)) {
-            try {
-                Boolean.valueOf(properties.get(PROPERTY_INCREMENTAL));
-            } catch (NumberFormatException e) {
-                String msg = String.format(msgTemplate, PROPERTY_INCREMENTAL, properties.get(PROPERTY_INCREMENTAL));
-                throw new AnalysisException(msg);
-            }
-        }
-        if (properties.containsKey(PROPERTY_INCREMENTAL)
-                && AnalysisType.valueOf(properties.get(PROPERTY_ANALYSIS_TYPE)) == AnalysisType.HISTOGRAM) {
-            throw new AnalysisException(PROPERTY_INCREMENTAL + " analysis of histograms is not supported");
-        }
+    public AnalysisMode getAnalysisMode() {
+        return analyzeProperties.isIncremental() ? AnalysisMode.INCREMENTAL : AnalysisMode.FULL;
     }
 
-    private void checkAnalysisType(String msgTemplate) throws AnalysisException {
-        if (properties.containsKey(PROPERTY_ANALYSIS_TYPE)) {
-            try {
-                AnalysisType.valueOf(properties.get(PROPERTY_ANALYSIS_TYPE));
-            } catch (NumberFormatException e) {
-                String msg = String.format(msgTemplate, PROPERTY_ANALYSIS_TYPE, properties.get(PROPERTY_ANALYSIS_TYPE));
-                throw new AnalysisException(msg);
-            }
-        }
+    public AnalysisType getAnalysisType() {
+        return analyzeProperties.getAnalysisType();
     }
 
-    private void checkScheduleType(String msgTemplate) throws AnalysisException {
-        if (properties.containsKey(PROPERTY_AUTOMATIC)) {
-            try {
-                Boolean.valueOf(properties.get(PROPERTY_AUTOMATIC));
-            } catch (NumberFormatException e) {
-                String msg = String.format(msgTemplate, PROPERTY_AUTOMATIC, properties.get(PROPERTY_AUTOMATIC));
-                throw new AnalysisException(msg);
-            }
-        }
-        if (properties.containsKey(PROPERTY_AUTOMATIC)
-                && properties.containsKey(PROPERTY_INCREMENTAL)) {
-            throw new AnalysisException(PROPERTY_INCREMENTAL + " is invalid when analyze automatically statistics");
-        }
-        if (properties.containsKey(PROPERTY_AUTOMATIC)
-                && properties.containsKey(PROPERTY_PERIOD_SECONDS)) {
-            throw new AnalysisException(PROPERTY_PERIOD_SECONDS + " is invalid when analyze automatically statistics");
-        }
+    public AnalysisMethod getAnalysisMethod() {
+        double samplePercent = analyzeProperties.getSamplePercent();
+        int sampleRows = analyzeProperties.getSampleRows();
+        return (samplePercent > 0 || sampleRows > 0) ? AnalysisMethod.SAMPLE : AnalysisMethod.FULL;
     }
 
-    private void checkNumericProperty(String key, String value, int lowerBound, int upperBound,
-            boolean includeBoundary, String errorMsg) throws AnalysisException {
-        if (!StringUtils.isNumeric(value)) {
-            String msg = String.format("%s = %s is an invalid property.", key, value);
-            throw new AnalysisException(msg);
-        }
-        int intValue = Integer.parseInt(value);
-        boolean isOutOfBounds = (includeBoundary && (intValue < lowerBound || intValue > upperBound))
-                || (!includeBoundary && (intValue <= lowerBound || intValue >= upperBound));
-        if (isOutOfBounds) {
-            throw new AnalysisException(key + " " + errorMsg);
+    public ScheduleType getScheduleType() {
+        if (analyzeProperties.isAutomatic()) {
+            return ScheduleType.AUTOMATIC;
         }
-    }
-
-    public String getCatalogName() {
-        return tableName.getCtl();
-    }
-
-    public long getDbId() {
-        return dbId;
-    }
-
-    public String getDBName() {
-        return tableName.getDb();
-    }
-
-    public Database getDb() throws AnalysisException {
-        return analyzer.getEnv().getInternalCatalog().getDbOrAnalysisException(dbId);
-    }
-
-    public TableIf getTable() {
-        return table;
-    }
-
-    public TableName getTblName() {
-        return tableName;
-    }
-
-    public Set<String> getColumnNames() {
-        return columnNames == null ? table.getBaseSchema(false)
-                .stream().map(Column::getName).collect(Collectors.toSet()) : Sets.newHashSet(columnNames);
-    }
-
-    public Map<String, String> getProperties() {
-        return properties;
+        return analyzeProperties.getPeriodTimeInMs() > 0 ? ScheduleType.PERIOD : ScheduleType.ONCE;
     }
 
     public boolean isSync() {
-        return Boolean.parseBoolean(properties.get(PROPERTY_SYNC));
-    }
-
-    public boolean isIncremental() {
-        return Boolean.parseBoolean(properties.get(PROPERTY_INCREMENTAL));
-    }
-
-    public boolean isAutomatic() {
-        return Boolean.parseBoolean(properties.get(PROPERTY_AUTOMATIC));
+        return analyzeProperties.isSync();
     }
 
     public int getSamplePercent() {
-        if (!properties.containsKey(PROPERTY_SAMPLE_PERCENT)) {
-            return 0;
-        }
-        return Integer.parseInt(properties.get(PROPERTY_SAMPLE_PERCENT));
+        return analyzeProperties.getSamplePercent();
     }
 
     public int getSampleRows() {
-        if (!properties.containsKey(PROPERTY_SAMPLE_ROWS)) {
-            return 0;
-        }
-        return Integer.parseInt(properties.get(PROPERTY_SAMPLE_ROWS));
+        return analyzeProperties.getSampleRows();
     }
 
     public int getNumBuckets() {
-        if (!properties.containsKey(PROPERTY_NUM_BUCKETS)) {
-            return 0;
-        }
-        return Integer.parseInt(properties.get(PROPERTY_NUM_BUCKETS));
+        return analyzeProperties.getNumBuckets();
     }
 
     public long getPeriodTimeInMs() {
-        if (!properties.containsKey(PROPERTY_PERIOD_SECONDS)) {
-            return 0;
-        }
-        int minutes = Integer.parseInt(properties.get(PROPERTY_PERIOD_SECONDS));
-        return TimeUnit.SECONDS.toMillis(minutes);
-    }
-
-    public AnalysisMode getAnalysisMode() {
-        return isIncremental() ? AnalysisMode.INCREMENTAL : AnalysisMode.FULL;
-    }
-
-    public AnalysisType getAnalysisType() {
-        return AnalysisType.valueOf(properties.get(PROPERTY_ANALYSIS_TYPE));
-    }
-
-    public AnalysisMethod getAnalysisMethod() {
-        double samplePercent = getSamplePercent();
-        int sampleRows = getSampleRows();
-        return (samplePercent > 0 || sampleRows > 0) ? AnalysisMethod.SAMPLE : AnalysisMethod.FULL;
-    }
-
-    public ScheduleType getScheduleType() {
-        if (isAutomatic()) {
-            return ScheduleType.AUTOMATIC;
-        }
-        return getPeriodTimeInMs() > 0 ? ScheduleType.PERIOD : ScheduleType.ONCE;
+        return analyzeProperties.getPeriodTimeInMs();
     }
 
-    @Override
-    public String toSql() {
-        StringBuilder sb = new StringBuilder();
-        sb.append("ANALYZE TABLE ");
-
-        if (tableName != null) {
-            sb.append(" ");
-            sb.append(tableName.toSql());
-        }
-
-        if (columnNames != null) {
-            sb.append("(");
-            sb.append(StringUtils.join(columnNames, ","));
-            sb.append(")");
-        }
-
-        if (getAnalysisType().equals(AnalysisType.HISTOGRAM)) {
-            sb.append(" ");
-            sb.append("UPDATE HISTOGRAM");
-        }
-
-        if (properties != null) {
-            sb.append(" ");
-            sb.append("PROPERTIES(");
-            sb.append(new PrintableMap<>(properties, " = ",
-                    true,
-                    false));
-            sb.append(")");
-        }
-
-        return sb.toString();
+    public AnalyzeProperties getAnalyzeProperties() {
+        return analyzeProperties;
     }
 }
diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/AnalyzeTblStmt.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/AnalyzeTblStmt.java
new file mode 100644
index 0000000000..c200d1974e
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/AnalyzeTblStmt.java
@@ -0,0 +1,256 @@
+// 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.doris.analysis;
+
+import org.apache.doris.catalog.Column;
+import org.apache.doris.catalog.Database;
+import org.apache.doris.catalog.DatabaseIf;
+import org.apache.doris.catalog.Env;
+import org.apache.doris.catalog.OlapTable;
+import org.apache.doris.catalog.TableIf;
+import org.apache.doris.catalog.View;
+import org.apache.doris.common.AnalysisException;
+import org.apache.doris.common.Config;
+import org.apache.doris.common.ErrorCode;
+import org.apache.doris.common.ErrorReport;
+import org.apache.doris.common.FeNameFormat;
+import org.apache.doris.common.UserException;
+import org.apache.doris.datasource.CatalogIf;
+import org.apache.doris.mysql.privilege.PrivPredicate;
+import org.apache.doris.qe.ConnectContext;
+import org.apache.doris.statistics.AnalysisInfo.AnalysisType;
+import org.apache.doris.statistics.ColumnStatistic;
+
+import com.google.common.collect.Sets;
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.List;
+import java.util.Optional;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+/**
+ * Column Statistics Collection Syntax:
+ * ANALYZE [ SYNC ] TABLE table_name
+ * [ (column_name [, ...]) ]
+ * [ [WITH SYNC] | [WITH INCREMENTAL] | [WITH SAMPLE PERCENT | ROWS ] ]
+ * [ PROPERTIES ('key' = 'value', ...) ];
+ * <p>
+ * Column histogram collection syntax:
+ * ANALYZE [ SYNC ] TABLE table_name
+ * [ (column_name [, ...]) ]
+ * UPDATE HISTOGRAM
+ * [ [ WITH SYNC ][ WITH INCREMENTAL ][ WITH SAMPLE PERCENT | ROWS ][ WITH BUCKETS ] ]
+ * [ PROPERTIES ('key' = 'value', ...) ];
+ * <p>
+ * Illustrate:
+ * - sync:Collect statistics synchronously. Return after collecting.
+ * - incremental:Collect statistics incrementally. Incremental collection of histogram statistics is not supported.
+ * - sample percent | rows:Collect statistics by sampling. Scale and number of rows can be sampled.
+ * - buckets:Specifies the maximum number of buckets generated when collecting histogram statistics.
+ * - table_name: The purpose table for collecting statistics. Can be of the form `db_name.table_name`.
+ * - column_name: The specified destination column must be a column that exists in `table_name`,
+ * and multiple column names are separated by commas.
+ * - properties:Properties used to set statistics tasks. Currently only the following configurations
+ * are supported (equivalent to the with statement)
+ * - 'sync' = 'true'
+ * - 'incremental' = 'true'
+ * - 'sample.percent' = '50'
+ * - 'sample.rows' = '1000'
+ * - 'num.buckets' = 10
+ */
+public class AnalyzeTblStmt extends AnalyzeStmt {
+    // The properties passed in by the user through "with" or "properties('K', 'V')"
+
+    private final TableName tableName;
+    private List<String> columnNames;
+
+    // after analyzed
+    private long dbId;
+    private TableIf table;
+
+    public AnalyzeTblStmt(TableName tableName,
+            List<String> columnNames,
+            AnalyzeProperties properties) {
+        super(properties);
+        this.tableName = tableName;
+        this.columnNames = columnNames;
+        this.analyzeProperties = properties;
+    }
+
+    public AnalyzeTblStmt(AnalyzeProperties analyzeProperties, TableName tableName, List<String> columnNames, long dbId,
+            TableIf table) {
+        super(analyzeProperties);
+        this.tableName = tableName;
+        this.columnNames = columnNames;
+        this.dbId = dbId;
+        this.table = table;
+    }
+
+    @Override
+    @SuppressWarnings({"rawtypes"})
+    public void analyze(Analyzer analyzer) throws UserException {
+        if (!Config.enable_stats) {
+            throw new UserException("Analyze function is forbidden, you should add `enable_stats=true`"
+                    + "in your FE conf file");
+        }
+        super.analyze(analyzer);
+
+        tableName.analyze(analyzer);
+
+        String catalogName = tableName.getCtl();
+        String dbName = tableName.getDb();
+        String tblName = tableName.getTbl();
+        CatalogIf catalog = analyzer.getEnv().getCatalogMgr()
+                .getCatalogOrAnalysisException(catalogName);
+        DatabaseIf db = catalog.getDbOrAnalysisException(dbName);
+        dbId = db.getId();
+        table = db.getTableOrAnalysisException(tblName);
+        check();
+    }
+
+    public void check() throws AnalysisException {
+        if (table instanceof View) {
+            throw new AnalysisException("Analyze view is not allowed");
+        }
+        checkAnalyzePriv(tableName.getDb(), tableName.getTbl());
+        if (columnNames == null) {
+            columnNames = table.getBaseSchema(false)
+                    .stream().map(Column::getName).collect(Collectors.toList());
+        }
+        table.readLock();
+        try {
+            List<String> baseSchema = table.getBaseSchema(false)
+                    .stream().map(Column::getName).collect(Collectors.toList());
+            Optional<String> optional = columnNames.stream()
+                    .filter(entity -> !baseSchema.contains(entity)).findFirst();
+            if (optional.isPresent()) {
+                String columnName = optional.get();
+                ErrorReport.reportAnalysisException(ErrorCode.ERR_WRONG_COLUMN_NAME,
+                        columnName, FeNameFormat.getColumnNameRegex());
+            }
+        } finally {
+            table.readUnlock();
+        }
+        checkColumn();
+        analyzeProperties.check();
+
+        // TODO support external table
+        if (analyzeProperties.isSample()) {
+            if (!(table instanceof OlapTable)) {
+                throw new AnalysisException("Sampling statistics "
+                        + "collection of external tables is not supported");
+            }
+        }
+    }
+
+    private void checkColumn() throws AnalysisException {
+        table.readLock();
+        try {
+            for (String colName : columnNames) {
+                Column column = table.getColumn(colName);
+                if (column == null) {
+                    ErrorReport.reportAnalysisException(ErrorCode.ERR_WRONG_COLUMN_NAME,
+                            colName, FeNameFormat.getColumnNameRegex());
+                }
+                if (ColumnStatistic.UNSUPPORTED_TYPE.contains(column.getType())) {
+                    throw new AnalysisException(String.format("Column[%s] with type[%s] is not supported to analyze",
+                            colName, column.getType().toString()));
+                }
+            }
+        } finally {
+            table.readUnlock();
+        }
+
+    }
+
+    public String getCatalogName() {
+        return tableName.getCtl();
+    }
+
+    public long getDbId() {
+        return dbId;
+    }
+
+    public String getDBName() {
+        return tableName.getDb();
+    }
+
+    public TableIf getTable() {
+        return table;
+    }
+
+    public TableName getTblName() {
+        return tableName;
+    }
+
+    public Set<String> getColumnNames() {
+        return columnNames == null ? table.getBaseSchema(false)
+                .stream().map(Column::getName).collect(Collectors.toSet()) : Sets.newHashSet(columnNames);
+    }
+
+    @Override
+    public RedirectStatus getRedirectStatus() {
+        return RedirectStatus.FORWARD_NO_SYNC;
+    }
+
+    private void checkAnalyzePriv(String dbName, String tblName) throws AnalysisException {
+        if (!Env.getCurrentEnv().getAccessManager()
+                .checkTblPriv(ConnectContext.get(), dbName, tblName, PrivPredicate.SELECT)) {
+            ErrorReport.reportAnalysisException(
+                    ErrorCode.ERR_TABLEACCESS_DENIED_ERROR,
+                    "ANALYZE",
+                    ConnectContext.get().getQualifiedUser(),
+                    ConnectContext.get().getRemoteIP(),
+                    dbName + ": " + tblName);
+        }
+    }
+
+    @Override
+    public String toSql() {
+        StringBuilder sb = new StringBuilder();
+        sb.append("ANALYZE TABLE ");
+
+        if (tableName != null) {
+            sb.append(" ");
+            sb.append(tableName.toSql());
+        }
+
+        if (columnNames != null) {
+            sb.append("(");
+            sb.append(StringUtils.join(columnNames, ","));
+            sb.append(")");
+        }
+
+        if (getAnalysisType().equals(AnalysisType.HISTOGRAM)) {
+            sb.append(" ");
+            sb.append("UPDATE HISTOGRAM");
+        }
+
+        if (analyzeProperties != null) {
+            sb.append(" ");
+            sb.append(analyzeProperties.toSQL());
+        }
+
+        return sb.toString();
+    }
+
+    public Database getDb() throws AnalysisException {
+        return analyzer.getEnv().getInternalCatalog().getDbOrAnalysisException(dbId);
+    }
+}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/DropAnalyzeJobStmt.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/DropAnalyzeJobStmt.java
new file mode 100644
index 0000000000..34a7c875ed
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/DropAnalyzeJobStmt.java
@@ -0,0 +1,34 @@
+// 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.doris.analysis;
+
+/**
+ * DROP ANALYZE JOB [JOB_ID]
+ */
+public class DropAnalyzeJobStmt extends DdlStmt {
+
+    private final long jobId;
+
+    public DropAnalyzeJobStmt(long jobId) {
+        this.jobId = jobId;
+    }
+
+    public long getJobId() {
+        return jobId;
+    }
+}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/ShowAnalyzeStmt.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/ShowAnalyzeStmt.java
index b91e171a03..73bf77b23c 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/analysis/ShowAnalyzeStmt.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/ShowAnalyzeStmt.java
@@ -67,17 +67,11 @@ public class ShowAnalyzeStmt extends ShowStmt {
             .add("schedule_type")
             .build();
 
-    private Long jobId;
+    private long jobId;
     private TableName dbTableName;
     private Expr whereClause;
     private LimitElement limitElement;
     private List<OrderByElement> orderByElements;
-
-    // after analyzed
-    private String catalogName;
-    private String dbName;
-    private String tblName;
-
     private String stateValue;
     private ArrayList<OrderByPair> orderByPairs;
 
@@ -94,10 +88,11 @@ public class ShowAnalyzeStmt extends ShowStmt {
         this.limitElement = limitElement;
     }
 
-    public ShowAnalyzeStmt(Long jobId,
+    public ShowAnalyzeStmt(long jobId,
             Expr whereClause,
             List<OrderByElement> orderByElements,
             LimitElement limitElement) {
+        Preconditions.checkArgument(jobId > 0, "JobId must greater than 0.");
         this.jobId = jobId;
         this.dbTableName = null;
         this.whereClause = whereClause;
@@ -105,32 +100,10 @@ public class ShowAnalyzeStmt extends ShowStmt {
         this.limitElement = limitElement;
     }
 
-    public ImmutableList<String> getTitleNames() {
-        return TITLE_NAMES;
-    }
-
-    public Long getJobId() {
+    public long getJobId() {
         return jobId;
     }
 
-    public String getCatalogName() {
-        Preconditions.checkArgument(isAnalyzed(),
-                "The catalogName must be obtained after the parsing is complete");
-        return catalogName;
-    }
-
-    public String getDbName() {
-        Preconditions.checkArgument(isAnalyzed(),
-                "The dbName must be obtained after the parsing is complete");
-        return dbName;
-    }
-
-    public String getTblName() {
-        Preconditions.checkArgument(isAnalyzed(),
-                "The tblName must be obtained after the parsing is complete");
-        return tblName;
-    }
-
     public String getStateValue() {
         Preconditions.checkArgument(isAnalyzed(),
                 "The stateValue must be obtained after the parsing is complete");
@@ -143,37 +116,11 @@ public class ShowAnalyzeStmt extends ShowStmt {
         return orderByPairs;
     }
 
-    public String getWhereClause() {
+    public Expr getWhereClause() {
         Preconditions.checkArgument(isAnalyzed(),
                 "The whereClause must be obtained after the parsing is complete");
 
-        StringBuilder clauseBuilder = new StringBuilder();
-
-        if (jobId != null) {
-            clauseBuilder.append("job_Id = ").append(jobId);
-        }
-
-        if (!Strings.isNullOrEmpty(catalogName)) {
-            clauseBuilder.append(clauseBuilder.length() > 0 ? " AND " : "")
-                    .append("catalog_name = \"").append(catalogName).append("\"");
-        }
-
-        if (!Strings.isNullOrEmpty(dbName)) {
-            clauseBuilder.append(clauseBuilder.length() > 0 ? " AND " : "")
-                    .append("db_name = \"").append(dbName).append("\"");
-        }
-
-        if (!Strings.isNullOrEmpty(tblName)) {
-            clauseBuilder.append(clauseBuilder.length() > 0 ? " AND " : "")
-                    .append("tbl_name = \"").append(tblName).append("\"");
-        }
-
-        if (!Strings.isNullOrEmpty(stateValue)) {
-            clauseBuilder.append(clauseBuilder.length() > 0 ? " AND " : "")
-                    .append("state = \"").append(stateValue).append("\"");
-        }
-
-        return clauseBuilder.toString();
+        return whereClause;
     }
 
     public long getLimit() {
@@ -190,15 +137,11 @@ public class ShowAnalyzeStmt extends ShowStmt {
                     + "in your FE conf file");
         }
         super.analyze(analyzer);
-        catalogName = analyzer.getEnv().getInternalCatalog().getName();
-
         if (dbTableName != null) {
             dbTableName.analyze(analyzer);
             String dbName = dbTableName.getDb();
             String tblName = dbTableName.getTbl();
             checkShowAnalyzePriv(dbName, tblName);
-            this.dbName = dbName;
-            this.tblName = tblName;
         }
 
         // analyze where clause if not null
@@ -318,7 +261,7 @@ public class ShowAnalyzeStmt extends ShowStmt {
         StringBuilder sb = new StringBuilder();
         sb.append("SHOW ANALYZE");
 
-        if (jobId != null) {
+        if (jobId != 0) {
             sb.append(" ");
             sb.append(jobId);
         }
@@ -361,4 +304,8 @@ public class ShowAnalyzeStmt extends ShowStmt {
     public String toString() {
         return toSql();
     }
+
+    public TableName getDbTableName() {
+        return dbTableName;
+    }
 }
diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/ShowAnalyzeTaskStatus.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/ShowAnalyzeTaskStatus.java
new file mode 100644
index 0000000000..03d304f393
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/ShowAnalyzeTaskStatus.java
@@ -0,0 +1,61 @@
+// 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.doris.analysis;
+
+import org.apache.doris.catalog.Column;
+import org.apache.doris.catalog.ScalarType;
+import org.apache.doris.common.Config;
+import org.apache.doris.common.UserException;
+import org.apache.doris.qe.ShowResultSetMetaData;
+
+/**
+ * SHOW ANALYZE TASK STATUS [JOB_ID]
+ */
+public class ShowAnalyzeTaskStatus extends ShowStmt {
+
+    private static final ShowResultSetMetaData ROW_META_DATA =
+            ShowResultSetMetaData.builder()
+                    .addColumn(new Column("task_id", ScalarType.createVarchar(100)))
+                    .addColumn(new Column("col_name", ScalarType.createVarchar(1000)))
+                    .addColumn(new Column("message", ScalarType.createVarchar(1000)))
+                    .addColumn(new Column("last_exec_time_in_ms", ScalarType.createVarchar(1000)))
+                    .addColumn(new Column("state", ScalarType.createVarchar(1000))).build();
+
+    private final long jobId;
+
+    public ShowAnalyzeTaskStatus(long jobId) {
+        this.jobId = jobId;
+    }
+
+    @Override
+    public void analyze(Analyzer analyzer) throws UserException {
+        if (!Config.enable_stats) {
+            throw new UserException("Analyze function is forbidden, you should add `enable_stats=true`"
+                    + "in your FE conf file");
+        }
+    }
+
+    @Override
+    public ShowResultSetMetaData getMetaData() {
+        return ROW_META_DATA;
+    }
+
+    public long getJobId() {
+        return jobId;
+    }
+}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/catalog/Env.java b/fe/fe-core/src/main/java/org/apache/doris/catalog/Env.java
index a4276464d9..a4622e0ad5 100755
--- a/fe/fe-core/src/main/java/org/apache/doris/catalog/Env.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/catalog/Env.java
@@ -38,7 +38,7 @@ import org.apache.doris.analysis.AlterMaterializedViewStmt;
 import org.apache.doris.analysis.AlterSystemStmt;
 import org.apache.doris.analysis.AlterTableStmt;
 import org.apache.doris.analysis.AlterViewStmt;
-import org.apache.doris.analysis.AnalyzeStmt;
+import org.apache.doris.analysis.AnalyzeTblStmt;
 import org.apache.doris.analysis.BackupStmt;
 import org.apache.doris.analysis.CancelAlterSystemStmt;
 import org.apache.doris.analysis.CancelAlterTableStmt;
@@ -657,11 +657,9 @@ public class Env {
         this.policyMgr = new PolicyMgr();
         this.mtmvJobManager = new MTMVJobManager();
         this.extMetaCacheMgr = new ExternalMetaCacheMgr();
-        if (Config.enable_stats && !isCheckpointCatalog) {
-            this.analysisManager = new AnalysisManager();
-            this.statisticsCleaner = new StatisticsCleaner();
-            this.statisticsAutoAnalyzer = new StatisticsAutoAnalyzer();
-        }
+        this.analysisManager = new AnalysisManager();
+        this.statisticsCleaner = new StatisticsCleaner();
+        this.statisticsAutoAnalyzer = new StatisticsAutoAnalyzer();
         this.globalFunctionMgr = new GlobalFunctionMgr();
         this.workloadGroupMgr = new WorkloadGroupMgr();
         this.queryStats = new QueryStats();
@@ -5311,8 +5309,8 @@ public class Env {
     //  1. handle partition level analysis statement properly
     //  2. support sample job
     //  3. support period job
-    public void createAnalysisJob(AnalyzeStmt analyzeStmt) throws DdlException {
-        analysisManager.createAnalysisJob(analyzeStmt);
+    public void createAnalysisJob(AnalyzeTblStmt analyzeTblStmt) throws DdlException {
+        analysisManager.createAnalysisJob(analyzeTblStmt);
     }
 
     public AnalysisManager getAnalysisManager() {
diff --git a/fe/fe-core/src/main/java/org/apache/doris/catalog/InternalSchemaInitializer.java b/fe/fe-core/src/main/java/org/apache/doris/catalog/InternalSchemaInitializer.java
index 3abaa3b8e6..c5a3197dee 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/catalog/InternalSchemaInitializer.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/catalog/InternalSchemaInitializer.java
@@ -21,7 +21,6 @@ import org.apache.doris.analysis.ColumnDef;
 import org.apache.doris.analysis.CreateDbStmt;
 import org.apache.doris.analysis.CreateTableStmt;
 import org.apache.doris.analysis.DistributionDesc;
-import org.apache.doris.analysis.DropTableStmt;
 import org.apache.doris.analysis.HashDistributionDesc;
 import org.apache.doris.analysis.KeysDesc;
 import org.apache.doris.analysis.TableName;
@@ -51,18 +50,9 @@ import java.util.stream.Collectors;
 
 public class InternalSchemaInitializer extends Thread {
 
-    private static final Logger LOG = LogManager.getLogger(InternalSchemaInitializer.class);
-
-    /**
-     * If internal table creation failed, will retry after below seconds.
-     */
     public static final int TABLE_CREATION_RETRY_INTERVAL_IN_SECONDS = 5;
 
-    /**
-     * Used when an internal table schema changes.
-     * TODO remove this code after the table structure is stable
-     */
-    private boolean isSchemaChanged = false;
+    private static final Logger LOG = LogManager.getLogger(InternalSchemaInitializer.class);
 
     public void run() {
         if (FeConstants.disableInternalSchemaDb) {
@@ -91,7 +81,6 @@ public class InternalSchemaInitializer extends Thread {
         Env.getCurrentEnv().getInternalCatalog().createTable(buildAnalysisTblStmt());
         Env.getCurrentEnv().getInternalCatalog().createTable(buildStatisticsTblStmt());
         Env.getCurrentEnv().getInternalCatalog().createTable(buildHistogramTblStmt());
-        Env.getCurrentEnv().getInternalCatalog().createTable(buildAnalysisJobTblStmt());
     }
 
     @VisibleForTesting
@@ -215,59 +204,6 @@ public class InternalSchemaInitializer extends Thread {
         return createTableStmt;
     }
 
-    @VisibleForTesting
-    public CreateTableStmt buildAnalysisJobTblStmt() throws UserException {
-        TableName tableName = new TableName("",
-                FeConstants.INTERNAL_DB_NAME, StatisticConstants.ANALYSIS_JOB_TABLE);
-        List<ColumnDef> columnDefs = new ArrayList<>();
-        columnDefs.add(new ColumnDef("job_id", TypeDef.create(PrimitiveType.BIGINT)));
-        columnDefs.add(new ColumnDef("task_id", TypeDef.create(PrimitiveType.BIGINT)));
-        columnDefs.add(new ColumnDef("catalog_name", TypeDef.createVarchar(1024)));
-        columnDefs.add(new ColumnDef("db_name", TypeDef.createVarchar(1024)));
-        columnDefs.add(new ColumnDef("tbl_name", TypeDef.createVarchar(1024)));
-        columnDefs.add(new ColumnDef("col_name", TypeDef.createVarchar(1024)));
-        columnDefs.add(new ColumnDef("index_id", TypeDef.create(PrimitiveType.BIGINT)));
-        columnDefs.add(new ColumnDef("col_partitions", TypeDef.createVarchar(ScalarType.MAX_VARCHAR_LENGTH)));
-        columnDefs.add(new ColumnDef("job_type", TypeDef.createVarchar(32)));
-        columnDefs.add(new ColumnDef("analysis_type", TypeDef.createVarchar(32)));
-        columnDefs.add(new ColumnDef("analysis_mode", TypeDef.createVarchar(32)));
-        columnDefs.add(new ColumnDef("analysis_method", TypeDef.createVarchar(32)));
-        columnDefs.add(new ColumnDef("schedule_type", TypeDef.createVarchar(32)));
-        columnDefs.add(new ColumnDef("state", TypeDef.createVarchar(32)));
-        columnDefs.add(new ColumnDef("sample_percent", TypeDef.create(PrimitiveType.BIGINT)));
-        columnDefs.add(new ColumnDef("sample_rows", TypeDef.create(PrimitiveType.BIGINT)));
-        columnDefs.add(new ColumnDef("max_bucket_num", TypeDef.create(PrimitiveType.BIGINT)));
-        columnDefs.add(new ColumnDef("period_time_in_ms", TypeDef.create(PrimitiveType.BIGINT)));
-        columnDefs.add(new ColumnDef("last_exec_time_in_ms", TypeDef.create(PrimitiveType.BIGINT)));
-        columnDefs.add(new ColumnDef("message", TypeDef.createVarchar(1024)));
-        // TODO remove this code after the table structure is stable
-        if (!isSchemaChanged && isTableChanged(tableName, columnDefs)) {
-            isSchemaChanged = true;
-            DropTableStmt dropTableStmt = new DropTableStmt(true, tableName, true);
-            StatisticsUtil.analyze(dropTableStmt);
-            Env.getCurrentEnv().getInternalCatalog().dropTable(dropTableStmt);
-        }
-        String engineName = "olap";
-        ArrayList<String> uniqueKeys = Lists.newArrayList("job_id", "task_id",
-                "catalog_name", "db_name", "tbl_name", "col_name", "index_id");
-        KeysDesc keysDesc = new KeysDesc(KeysType.UNIQUE_KEYS, uniqueKeys);
-
-        DistributionDesc distributionDesc = new HashDistributionDesc(
-                StatisticConstants.STATISTIC_TABLE_BUCKET_COUNT,
-                Lists.newArrayList("job_id", "task_id"));
-        Map<String, String> properties = new HashMap<String, String>() {
-            {
-                put("replication_num", String.valueOf(Config.statistic_internal_table_replica_num));
-            }
-        };
-        CreateTableStmt createTableStmt = new CreateTableStmt(true, false,
-                tableName, columnDefs, engineName, keysDesc, null, distributionDesc,
-                properties, null, "Doris internal statistics table, don't modify it", null);
-        // createTableStmt.setClusterName(SystemInfoService.DEFAULT_CLUSTER);
-        StatisticsUtil.analyze(createTableStmt);
-        return createTableStmt;
-    }
-
     private boolean created() {
         Optional<Database> optionalDatabase =
                 Env.getCurrentEnv().getInternalCatalog()
@@ -276,17 +212,9 @@ public class InternalSchemaInitializer extends Thread {
             return false;
         }
         Database db = optionalDatabase.get();
-        // TODO remove this code after the table structure is stable
-        try {
-            buildAnalysisJobTblStmt();
-        } catch (UserException ignored) {
-            // CHECKSTYLE IGNORE THIS LINE
-        }
-        return !isSchemaChanged
-                && db.getTable(StatisticConstants.ANALYSIS_TBL_NAME).isPresent()
+        return db.getTable(StatisticConstants.ANALYSIS_TBL_NAME).isPresent()
                 && db.getTable(StatisticConstants.STATISTIC_TBL_NAME).isPresent()
-                && db.getTable(StatisticConstants.HISTOGRAM_TBL_NAME).isPresent()
-                && db.getTable(StatisticConstants.ANALYSIS_JOB_TABLE).isPresent();
+                && db.getTable(StatisticConstants.HISTOGRAM_TBL_NAME).isPresent();
     }
 
     /**
diff --git a/fe/fe-core/src/main/java/org/apache/doris/catalog/OlapTable.java b/fe/fe-core/src/main/java/org/apache/doris/catalog/OlapTable.java
index dfeff80478..025795f87d 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/catalog/OlapTable.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/catalog/OlapTable.java
@@ -48,8 +48,8 @@ import org.apache.doris.common.util.PropertyAnalyzer;
 import org.apache.doris.common.util.Util;
 import org.apache.doris.qe.OriginStatement;
 import org.apache.doris.resource.Tag;
-import org.apache.doris.statistics.AnalysisTaskInfo;
-import org.apache.doris.statistics.AnalysisTaskInfo.AnalysisType;
+import org.apache.doris.statistics.AnalysisInfo;
+import org.apache.doris.statistics.AnalysisInfo.AnalysisType;
 import org.apache.doris.statistics.BaseAnalysisTask;
 import org.apache.doris.statistics.HistogramTask;
 import org.apache.doris.statistics.MVAnalysisTask;
@@ -1071,11 +1071,11 @@ public class OlapTable extends Table {
     }
 
     @Override
-    public BaseAnalysisTask createAnalysisTask(AnalysisTaskInfo info) {
+    public BaseAnalysisTask createAnalysisTask(AnalysisInfo info) {
         if (info.analysisType.equals(AnalysisType.HISTOGRAM)) {
             return new HistogramTask(info);
         }
-        if (info.analysisType.equals(AnalysisType.COLUMN)) {
+        if (info.analysisType.equals(AnalysisType.FUNDAMENTALS)) {
             return new OlapAnalysisTask(info);
         }
         return new MVAnalysisTask(info);
diff --git a/fe/fe-core/src/main/java/org/apache/doris/catalog/Table.java b/fe/fe-core/src/main/java/org/apache/doris/catalog/Table.java
index 4595f0fc9f..0c3c7d1795 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/catalog/Table.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/catalog/Table.java
@@ -27,7 +27,7 @@ import org.apache.doris.common.util.QueryableReentrantReadWriteLock;
 import org.apache.doris.common.util.SqlUtils;
 import org.apache.doris.common.util.Util;
 import org.apache.doris.external.hudi.HudiTable;
-import org.apache.doris.statistics.AnalysisTaskInfo;
+import org.apache.doris.statistics.AnalysisInfo;
 import org.apache.doris.statistics.BaseAnalysisTask;
 import org.apache.doris.thrift.TTableDescriptor;
 
@@ -521,7 +521,7 @@ public abstract class Table extends MetaObject implements Writable, TableIf {
     }
 
     @Override
-    public BaseAnalysisTask createAnalysisTask(AnalysisTaskInfo info) {
+    public BaseAnalysisTask createAnalysisTask(AnalysisInfo info) {
         throw new NotImplementedException("createAnalysisTask not implemented");
     }
 
diff --git a/fe/fe-core/src/main/java/org/apache/doris/catalog/TableIf.java b/fe/fe-core/src/main/java/org/apache/doris/catalog/TableIf.java
index 86545fa4d3..c79acc79df 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/catalog/TableIf.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/catalog/TableIf.java
@@ -20,7 +20,7 @@ package org.apache.doris.catalog;
 import org.apache.doris.alter.AlterCancelException;
 import org.apache.doris.common.DdlException;
 import org.apache.doris.common.MetaNotFoundException;
-import org.apache.doris.statistics.AnalysisTaskInfo;
+import org.apache.doris.statistics.AnalysisInfo;
 import org.apache.doris.statistics.BaseAnalysisTask;
 import org.apache.doris.thrift.TTableDescriptor;
 
@@ -124,7 +124,7 @@ public interface TableIf {
 
     TTableDescriptor toThrift();
 
-    BaseAnalysisTask createAnalysisTask(AnalysisTaskInfo info);
+    BaseAnalysisTask createAnalysisTask(AnalysisInfo info);
 
     long estimatedRowCount();
 
diff --git a/fe/fe-core/src/main/java/org/apache/doris/catalog/external/ExternalTable.java b/fe/fe-core/src/main/java/org/apache/doris/catalog/external/ExternalTable.java
index 7a8ff075e5..45f1425764 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/catalog/external/ExternalTable.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/catalog/external/ExternalTable.java
@@ -31,7 +31,7 @@ import org.apache.doris.datasource.ExternalCatalog;
 import org.apache.doris.datasource.ExternalSchemaCache;
 import org.apache.doris.persist.gson.GsonPostProcessable;
 import org.apache.doris.persist.gson.GsonUtils;
-import org.apache.doris.statistics.AnalysisTaskInfo;
+import org.apache.doris.statistics.AnalysisInfo;
 import org.apache.doris.statistics.BaseAnalysisTask;
 import org.apache.doris.thrift.TTableDescriptor;
 
@@ -308,7 +308,7 @@ public class ExternalTable implements TableIf, Writable, GsonPostProcessable {
     }
 
     @Override
-    public BaseAnalysisTask createAnalysisTask(AnalysisTaskInfo info) {
+    public BaseAnalysisTask createAnalysisTask(AnalysisInfo info) {
         throw new NotImplementedException("createAnalysisTask not implemented");
     }
 
diff --git a/fe/fe-core/src/main/java/org/apache/doris/catalog/external/HMSExternalTable.java b/fe/fe-core/src/main/java/org/apache/doris/catalog/external/HMSExternalTable.java
index 48f0e8a2c7..af032d4ae2 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/catalog/external/HMSExternalTable.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/catalog/external/HMSExternalTable.java
@@ -24,7 +24,7 @@ import org.apache.doris.catalog.Type;
 import org.apache.doris.common.Config;
 import org.apache.doris.datasource.HMSExternalCatalog;
 import org.apache.doris.datasource.hive.PooledHiveMetaStoreClient;
-import org.apache.doris.statistics.AnalysisTaskInfo;
+import org.apache.doris.statistics.AnalysisInfo;
 import org.apache.doris.statistics.BaseAnalysisTask;
 import org.apache.doris.statistics.ColumnStatistic;
 import org.apache.doris.statistics.HiveAnalysisTask;
@@ -285,7 +285,7 @@ public class HMSExternalTable extends ExternalTable {
     }
 
     @Override
-    public BaseAnalysisTask createAnalysisTask(AnalysisTaskInfo info) {
+    public BaseAnalysisTask createAnalysisTask(AnalysisInfo info) {
         makeSureInitialized();
         switch (dlaType) {
             case HIVE:
diff --git a/fe/fe-core/src/main/java/org/apache/doris/journal/JournalEntity.java b/fe/fe-core/src/main/java/org/apache/doris/journal/JournalEntity.java
index 00906c2c8f..37a7f1a1a6 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/journal/JournalEntity.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/journal/JournalEntity.java
@@ -66,6 +66,7 @@ import org.apache.doris.persist.AlterMultiMaterializedView;
 import org.apache.doris.persist.AlterRoutineLoadJobOperationLog;
 import org.apache.doris.persist.AlterUserOperationLog;
 import org.apache.doris.persist.AlterViewInfo;
+import org.apache.doris.persist.AnalyzeDeletionLog;
 import org.apache.doris.persist.BackendReplicasInfo;
 import org.apache.doris.persist.BackendTabletsInfo;
 import org.apache.doris.persist.BatchDropInfo;
@@ -114,6 +115,7 @@ import org.apache.doris.policy.DropPolicyLog;
 import org.apache.doris.policy.Policy;
 import org.apache.doris.policy.StoragePolicy;
 import org.apache.doris.resource.workloadgroup.WorkloadGroup;
+import org.apache.doris.statistics.AnalysisInfo;
 import org.apache.doris.system.Backend;
 import org.apache.doris.system.Frontend;
 import org.apache.doris.transaction.TransactionState;
@@ -795,6 +797,26 @@ public class JournalEntity implements Writable {
                 isRead = true;
                 break;
             }
+            case OperationType.OP_CREATE_ANALYSIS_JOB: {
+                data = AnalysisInfo.read(in);
+                isRead = true;
+                break;
+            }
+            case OperationType.OP_CREATE_ANALYSIS_TASK: {
+                data = AnalysisInfo.read(in);
+                isRead = true;
+                break;
+            }
+            case OperationType.OP_DELETE_ANALYSIS_JOB: {
+                data = AnalyzeDeletionLog.read(in);
+                isRead = true;
+                break;
+            }
+            case OperationType.OP_DELETE_ANALYSIS_TASK: {
+                data = AnalyzeDeletionLog.read(in);
+                isRead = true;
+                break;
+            }
             default: {
                 IOException e = new IOException();
                 LOG.error("UNKNOWN Operation Type {}", opCode, e);
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/stats/ExpressionEstimation.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/stats/ExpressionEstimation.java
index 782609afd5..d5449987cf 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/stats/ExpressionEstimation.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/stats/ExpressionEstimation.java
@@ -150,7 +150,7 @@ public class ExpressionEstimation extends ExpressionVisitor<ColumnStatistic, Sta
 
     @Override
     public ColumnStatistic visitLiteral(Literal literal, Statistics context) {
-        if (ColumnStatistic.MAX_MIN_UNSUPPORTED_TYPE.contains(literal.getDataType().toCatalogDataType())) {
+        if (ColumnStatistic.UNSUPPORTED_TYPE.contains(literal.getDataType().toCatalogDataType())) {
             return ColumnStatistic.UNKNOWN;
         }
         double literalVal = literal.getDouble();
diff --git a/fe/fe-core/src/main/java/org/apache/doris/persist/AnalyzeDeletionLog.java b/fe/fe-core/src/main/java/org/apache/doris/persist/AnalyzeDeletionLog.java
new file mode 100644
index 0000000000..7535aeb29b
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/persist/AnalyzeDeletionLog.java
@@ -0,0 +1,42 @@
+// 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.doris.persist;
+
+import org.apache.doris.common.io.Writable;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+
+public class AnalyzeDeletionLog implements Writable {
+
+    public final long id;
+
+    public AnalyzeDeletionLog(long id) {
+        this.id = id;
+    }
+
+    @Override
+    public void write(DataOutput out) throws IOException {
+        out.writeLong(id);
+    }
+
+    public static AnalyzeDeletionLog read(DataInput dataInput) throws IOException {
+        return new AnalyzeDeletionLog(dataInput.readLong());
+    }
+}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/persist/EditLog.java b/fe/fe-core/src/main/java/org/apache/doris/persist/EditLog.java
index 5cbb47b93e..c64882632f 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/persist/EditLog.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/persist/EditLog.java
@@ -80,6 +80,7 @@ import org.apache.doris.policy.DropPolicyLog;
 import org.apache.doris.policy.Policy;
 import org.apache.doris.policy.StoragePolicy;
 import org.apache.doris.resource.workloadgroup.WorkloadGroup;
+import org.apache.doris.statistics.AnalysisInfo;
 import org.apache.doris.system.Backend;
 import org.apache.doris.system.Frontend;
 import org.apache.doris.transaction.TransactionState;
@@ -1010,6 +1011,22 @@ public class EditLog {
                     // Do nothing.
                     break;
                 }
+                case OperationType.OP_CREATE_ANALYSIS_JOB: {
+                    env.getAnalysisManager().replayCreateAnalysisJob((AnalysisInfo) journal.getData());
+                    break;
+                }
+                case OperationType.OP_CREATE_ANALYSIS_TASK: {
+                    env.getAnalysisManager().replayCreateAnalysisTask((AnalysisInfo) journal.getData());
+                    break;
+                }
+                case OperationType.OP_DELETE_ANALYSIS_JOB: {
+                    env.getAnalysisManager().replayDeleteAnalysisJob((AnalyzeDeletionLog) journal.getData());
+                    break;
+                }
+                case OperationType.OP_DELETE_ANALYSIS_TASK: {
+                    env.getAnalysisManager().replayDeleteAnalysisTask((AnalyzeDeletionLog) journal.getData());
+                    break;
+                }
                 default: {
                     IOException e = new IOException();
                     LOG.error("UNKNOWN Operation Type {}", opCode, e);
@@ -1760,4 +1777,20 @@ public class EditLog {
     public void logCleanQueryStats(CleanQueryStatsInfo log) {
         logEdit(OperationType.OP_CLEAN_QUERY_STATS, log);
     }
+
+    public void logCreateAnalysisTasks(AnalysisInfo log) {
+        logEdit(OperationType.OP_CREATE_ANALYSIS_TASK, log);
+    }
+
+    public void logCreateAnalysisJob(AnalysisInfo log) {
+        logEdit(OperationType.OP_CREATE_ANALYSIS_JOB, log);
+    }
+
+    public void logDeleteAnalysisJob(AnalyzeDeletionLog log) {
+        logEdit(OperationType.OP_DELETE_ANALYSIS_JOB, log);
+    }
+
+    public void logDeleteAnalysisTask(AnalyzeDeletionLog log) {
+        logEdit(OperationType.OP_DELETE_ANALYSIS_TASK, log);
+    }
 }
diff --git a/fe/fe-core/src/main/java/org/apache/doris/persist/OperationType.java b/fe/fe-core/src/main/java/org/apache/doris/persist/OperationType.java
index 8261cb94d0..32f7d958e8 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/persist/OperationType.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/persist/OperationType.java
@@ -295,6 +295,15 @@ public class OperationType {
     // update binlog config
     public static final short OP_UPDATE_BINLOG_CONFIG = 425;
 
+    public static final short OP_CREATE_ANALYSIS_TASK = 430;
+
+    public static final short OP_DELETE_ANALYSIS_TASK = 431;
+
+    public static final short OP_CREATE_ANALYSIS_JOB = 432;
+
+    public static final short OP_DELETE_ANALYSIS_JOB = 433;
+
+
     /**
      * Get opcode name by op code.
      **/
diff --git a/fe/fe-core/src/main/java/org/apache/doris/qe/DdlExecutor.java b/fe/fe-core/src/main/java/org/apache/doris/qe/DdlExecutor.java
index 4106830d08..2b55729128 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/qe/DdlExecutor.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/qe/DdlExecutor.java
@@ -43,7 +43,8 @@ import org.apache.doris.analysis.AlterTableStmt;
 import org.apache.doris.analysis.AlterUserStmt;
 import org.apache.doris.analysis.AlterViewStmt;
 import org.apache.doris.analysis.AlterWorkloadGroupStmt;
-import org.apache.doris.analysis.AnalyzeStmt;
+import org.apache.doris.analysis.AnalyzeDBStmt;
+import org.apache.doris.analysis.AnalyzeTblStmt;
 import org.apache.doris.analysis.BackupStmt;
 import org.apache.doris.analysis.CancelAlterSystemStmt;
 import org.apache.doris.analysis.CancelAlterTableStmt;
@@ -75,6 +76,7 @@ import org.apache.doris.analysis.CreateViewStmt;
 import org.apache.doris.analysis.CreateWorkloadGroupStmt;
 import org.apache.doris.analysis.DdlStmt;
 import org.apache.doris.analysis.DeleteStmt;
+import org.apache.doris.analysis.DropAnalyzeJobStmt;
 import org.apache.doris.analysis.DropCatalogStmt;
 import org.apache.doris.analysis.DropDbStmt;
 import org.apache.doris.analysis.DropEncryptKeyStmt;
@@ -295,8 +297,8 @@ public class DdlExecutor {
             env.getRefreshManager().handleRefreshTable((RefreshTableStmt) ddlStmt);
         } else if (ddlStmt instanceof RefreshDbStmt) {
             env.getRefreshManager().handleRefreshDb((RefreshDbStmt) ddlStmt);
-        } else if (ddlStmt instanceof AnalyzeStmt) {
-            env.createAnalysisJob((AnalyzeStmt) ddlStmt);
+        } else if (ddlStmt instanceof AnalyzeTblStmt) {
+            env.createAnalysisJob((AnalyzeTblStmt) ddlStmt);
         } else if (ddlStmt instanceof AlterResourceStmt) {
             env.getResourceMgr().alterResource((AlterResourceStmt) ddlStmt);
         } else if (ddlStmt instanceof AlterWorkloadGroupStmt) {
@@ -335,6 +337,8 @@ public class DdlExecutor {
             env.getAnalysisManager().dropStats((DropStatsStmt) ddlStmt);
         } else if (ddlStmt instanceof KillAnalysisJobStmt) {
             env.getAnalysisManager().handleKillAnalyzeStmt((KillAnalysisJobStmt) ddlStmt);
+        } else if (ddlStmt instanceof AnalyzeDBStmt) {
+            env.getAnalysisManager().createAnalysisJobs((AnalyzeDBStmt) ddlStmt);
         } else if (ddlStmt instanceof CleanQueryStatsStmt) {
             CleanQueryStatsStmt stmt = (CleanQueryStatsStmt) ddlStmt;
             CleanQueryStatsInfo cleanQueryStatsInfo = null;
@@ -355,6 +359,9 @@ public class DdlExecutor {
                     throw new DdlException("Unknown scope: " + stmt.getScope());
             }
             env.cleanQueryStats(cleanQueryStatsInfo);
+        } else if (ddlStmt instanceof DropAnalyzeJobStmt) {
+            DropAnalyzeJobStmt analyzeJobStmt = (DropAnalyzeJobStmt) ddlStmt;
+            Env.getCurrentEnv().getAnalysisManager().dropAnalyzeJob(analyzeJobStmt);
         } else {
             LOG.warn("Unkown statement " + ddlStmt.getClass());
             throw new DdlException("Unknown statement.");
diff --git a/fe/fe-core/src/main/java/org/apache/doris/qe/SessionVariable.java b/fe/fe-core/src/main/java/org/apache/doris/qe/SessionVariable.java
index da62ddef9f..fe76449a1e 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/qe/SessionVariable.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/qe/SessionVariable.java
@@ -807,13 +807,6 @@ public class SessionVariable implements Serializable, Writable {
     @VariableMgr.VarAttr(name = ENABLE_CBO_STATISTICS)
     public boolean enableCboStatistics = false;
 
-    /**
-     * If true, when synchronously collecting statistics, the information of
-     * the statistics job will be saved, currently mainly used for p0 test
-     */
-    @VariableMgr.VarAttr(name = ENABLE_SAVE_STATISTICS_SYNC_JOB)
-    public boolean enableSaveStatisticsSyncJob = false;
-
     @VariableMgr.VarAttr(name = ENABLE_ELIMINATE_SORT_NODE)
     public boolean enableEliminateSortNode = true;
 
@@ -1588,10 +1581,6 @@ public class SessionVariable implements Serializable, Writable {
         return enableCboStatistics;
     }
 
-    public boolean isEnableSaveStatisticsSyncJob() {
-        return enableSaveStatisticsSyncJob;
-    }
-
     public long getFileSplitSize() {
         return fileSplitSize;
     }
diff --git a/fe/fe-core/src/main/java/org/apache/doris/qe/ShowExecutor.java b/fe/fe-core/src/main/java/org/apache/doris/qe/ShowExecutor.java
index 093722ff66..8b508b2cd7 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/qe/ShowExecutor.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/qe/ShowExecutor.java
@@ -28,6 +28,7 @@ import org.apache.doris.analysis.HelpStmt;
 import org.apache.doris.analysis.PartitionNames;
 import org.apache.doris.analysis.ShowAlterStmt;
 import org.apache.doris.analysis.ShowAnalyzeStmt;
+import org.apache.doris.analysis.ShowAnalyzeTaskStatus;
 import org.apache.doris.analysis.ShowAuthorStmt;
 import org.apache.doris.analysis.ShowBackendsStmt;
 import org.apache.doris.analysis.ShowBackupStmt;
@@ -187,6 +188,7 @@ import org.apache.doris.mtmv.MTMVJobManager;
 import org.apache.doris.mtmv.metadata.MTMVJob;
 import org.apache.doris.mtmv.metadata.MTMVTask;
 import org.apache.doris.mysql.privilege.PrivPredicate;
+import org.apache.doris.statistics.AnalysisInfo;
 import org.apache.doris.statistics.ColumnStatistic;
 import org.apache.doris.statistics.Histogram;
 import org.apache.doris.statistics.StatisticsRepository;
@@ -221,6 +223,9 @@ import java.io.InputStreamReader;
 import java.net.MalformedURLException;
 import java.net.URL;
 import java.net.URLConnection;
+import java.time.Instant;
+import java.time.LocalDateTime;
+import java.time.ZoneId;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
@@ -416,6 +421,8 @@ public class ShowExecutor {
             handleShowTypeCastStmt();
         } else if (stmt instanceof ShowBuildIndexStmt) {
             handleShowBuildIndexStmt();
+        } else if (stmt instanceof ShowAnalyzeTaskStatus) {
+            handleShowAnalyzeTaskStatus();
         } else {
             handleEmtpy();
         }
@@ -2505,36 +2512,26 @@ public class ShowExecutor {
 
     private void handleShowAnalyze() {
         ShowAnalyzeStmt showStmt = (ShowAnalyzeStmt) stmt;
-
-        List<List<Comparable>> results;
+        List<AnalysisInfo> results = Env.getCurrentEnv().getAnalysisManager()
+                .showAnalysisJob(showStmt);
         List<List<String>> resultRows = Lists.newArrayList();
-
-        try {
-            results = Env.getCurrentEnv().getAnalysisManager()
-                    .showAnalysisJob(showStmt);
-        } catch (DdlException e) {
-            resultSet = new ShowResultSet(showStmt.getMetaData(), resultRows);
-            return;
-        }
-
-        // order the result
-        ListComparator<List<Comparable>> comparator;
-        List<OrderByPair> orderByPairs = showStmt.getOrderByPairs();
-        if (orderByPairs == null) {
-            // sort by id asc
-            comparator = new ListComparator<>(0);
-        } else {
-            OrderByPair[] orderByPairArr = new OrderByPair[orderByPairs.size()];
-            comparator = new ListComparator<>(orderByPairs.toArray(orderByPairArr));
-        }
-        results.sort(comparator);
-
-        // convert to result and return it
-        for (List<Comparable> result : results) {
-            List<String> row = result.stream().map(Object::toString).collect(Collectors.toList());
+        for (AnalysisInfo analysisInfo : results) {
+            List<String> row = new ArrayList<>();
+            row.add(String.valueOf(analysisInfo.jobId));
+            row.add(analysisInfo.catalogName);
+            row.add(analysisInfo.dbName);
+            row.add(analysisInfo.tblName);
+            row.add(analysisInfo.colName);
+            row.add(analysisInfo.jobType.toString());
+            row.add(analysisInfo.analysisType.toString());
+            row.add(analysisInfo.message);
+            row.add(TimeUtils.DATETIME_FORMAT.format(
+                    LocalDateTime.ofInstant(Instant.ofEpochMilli(analysisInfo.lastExecTimeInMs),
+                            ZoneId.systemDefault())));
+            row.add(analysisInfo.state.toString());
+            row.add(analysisInfo.scheduleType.toString());
             resultRows.add(row);
         }
-
         resultSet = new ShowResultSet(showStmt.getMetaData(), resultRows);
     }
 
@@ -2719,5 +2716,24 @@ public class ShowExecutor {
                     showStmt.getOrderPairs(), showStmt.getLimitElement()).getRows();
         resultSet = new ShowResultSet(showStmt.getMetaData(), rows);
     }
+
+    private void handleShowAnalyzeTaskStatus() {
+        ShowAnalyzeTaskStatus showStmt = (ShowAnalyzeTaskStatus) stmt;
+        List<AnalysisInfo> analysisInfos = Env.getCurrentEnv().getAnalysisManager().findTasks(showStmt.getJobId());
+        List<List<String>> rows = new ArrayList<>();
+        for (AnalysisInfo analysisInfo : analysisInfos) {
+            List<String> row = new ArrayList<>();
+            row.add(String.valueOf(analysisInfo.taskId));
+            row.add(analysisInfo.colName);
+            row.add(analysisInfo.message);
+            row.add(TimeUtils.DATETIME_FORMAT.format(
+                    LocalDateTime.ofInstant(Instant.ofEpochMilli(analysisInfo.lastExecTimeInMs),
+                            ZoneId.systemDefault())));
+            row.add(analysisInfo.state.toString());
+            rows.add(row);
+        }
+        resultSet = new ShowResultSet(showStmt.getMetaData(), rows);
+    }
+
 }
 
diff --git a/fe/fe-core/src/main/java/org/apache/doris/qe/StmtExecutor.java b/fe/fe-core/src/main/java/org/apache/doris/qe/StmtExecutor.java
index a759d4de0f..e3f76c649e 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/qe/StmtExecutor.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/qe/StmtExecutor.java
@@ -21,6 +21,7 @@ import org.apache.doris.analysis.AddPartitionLikeClause;
 import org.apache.doris.analysis.AlterClause;
 import org.apache.doris.analysis.AlterTableStmt;
 import org.apache.doris.analysis.AnalyzeStmt;
+import org.apache.doris.analysis.AnalyzeTblStmt;
 import org.apache.doris.analysis.Analyzer;
 import org.apache.doris.analysis.ArrayLiteral;
 import org.apache.doris.analysis.CreateTableAsSelectStmt;
@@ -1135,7 +1136,7 @@ public class StmtExecutor {
         if (mysqlLoadId != null) {
             Env.getCurrentEnv().getLoadManager().getMysqlLoadManager().cancelMySqlLoad(mysqlLoadId);
         }
-        if (parsedStmt instanceof AnalyzeStmt) {
+        if (parsedStmt instanceof AnalyzeTblStmt) {
             Env.getCurrentEnv().getAnalysisManager().cancelSyncTask(context);
         }
     }
diff --git a/fe/fe-core/src/main/java/org/apache/doris/statistics/AnalysisTaskInfo.java b/fe/fe-core/src/main/java/org/apache/doris/statistics/AnalysisInfo.java
similarity index 57%
rename from fe/fe-core/src/main/java/org/apache/doris/statistics/AnalysisTaskInfo.java
rename to fe/fe-core/src/main/java/org/apache/doris/statistics/AnalysisInfo.java
index 2860a472c6..dea2155199 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/statistics/AnalysisTaskInfo.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/statistics/AnalysisInfo.java
@@ -17,6 +17,8 @@
 
 package org.apache.doris.statistics;
 
+import org.apache.doris.common.io.Text;
+import org.apache.doris.common.io.Writable;
 import org.apache.doris.statistics.util.InternalQueryResult.ResultRow;
 import org.apache.doris.statistics.util.StatisticsUtil;
 
@@ -25,14 +27,20 @@ import com.google.gson.reflect.TypeToken;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
 
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
 import java.lang.reflect.Type;
+import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Map;
+import java.util.Map.Entry;
 import java.util.Set;
 import java.util.StringJoiner;
 
-public class AnalysisTaskInfo {
+public class AnalysisInfo implements Writable {
 
-    private static final Logger LOG = LogManager.getLogger(AnalysisTaskInfo.class);
+    private static final Logger LOG = LogManager.getLogger(AnalysisInfo.class);
 
     public enum AnalysisMode {
         INCREMENTAL,
@@ -45,7 +53,7 @@ public class AnalysisTaskInfo {
     }
 
     public enum AnalysisType {
-        COLUMN,
+        FUNDAMENTALS,
         INDEX,
         HISTOGRAM
     }
@@ -77,7 +85,7 @@ public class AnalysisTaskInfo {
 
     public final String colName;
 
-    public final Long indexId;
+    public final long indexId;
 
     public final JobType jobType;
 
@@ -108,7 +116,7 @@ public class AnalysisTaskInfo {
     // This kind of task is mainly to collect the number of rows of a table.
     public boolean externalTableLevelTask;
 
-    public AnalysisTaskInfo(long jobId, long taskId, String catalogName, String dbName, String tblName,
+    public AnalysisInfo(long jobId, long taskId, String catalogName, String dbName, String tblName,
             Map<String, Set<String>> colToPartitions, String colName, Long indexId, JobType jobType,
             AnalysisMode analysisMode, AnalysisMethod analysisMethod, AnalysisType analysisType,
             int samplePercent, int sampleRows, int maxBucketNum, long periodTimeInMs, String message,
@@ -179,51 +187,51 @@ public class AnalysisTaskInfo {
     }
 
     // TODO: use thrift
-    public static AnalysisTaskInfo fromResultRow(ResultRow resultRow) {
+    public static AnalysisInfo fromResultRow(ResultRow resultRow) {
         try {
-            AnalysisTaskInfoBuilder analysisTaskInfoBuilder = new AnalysisTaskInfoBuilder();
+            AnalysisInfoBuilder analysisInfoBuilder = new AnalysisInfoBuilder();
             long jobId = Long.parseLong(resultRow.getColumnValue("job_id"));
-            analysisTaskInfoBuilder.setJobId(jobId);
+            analysisInfoBuilder.setJobId(jobId);
             long taskId = Long.parseLong(resultRow.getColumnValue("task_id"));
-            analysisTaskInfoBuilder.setTaskId(taskId);
+            analysisInfoBuilder.setTaskId(taskId);
             String catalogName = resultRow.getColumnValue("catalog_name");
-            analysisTaskInfoBuilder.setCatalogName(catalogName);
+            analysisInfoBuilder.setCatalogName(catalogName);
             String dbName = resultRow.getColumnValue("db_name");
-            analysisTaskInfoBuilder.setDbName(dbName);
+            analysisInfoBuilder.setDbName(dbName);
             String tblName = resultRow.getColumnValue("tbl_name");
-            analysisTaskInfoBuilder.setTblName(tblName);
+            analysisInfoBuilder.setTblName(tblName);
             String colName = resultRow.getColumnValue("col_name");
-            analysisTaskInfoBuilder.setColName(colName);
+            analysisInfoBuilder.setColName(colName);
             long indexId = Long.parseLong(resultRow.getColumnValue("index_id"));
-            analysisTaskInfoBuilder.setIndexId(indexId);
+            analysisInfoBuilder.setIndexId(indexId);
             String partitionNames = resultRow.getColumnValue("col_partitions");
             Map<String, Set<String>> colToPartitions = getColToPartition(partitionNames);
-            analysisTaskInfoBuilder.setColToPartitions(colToPartitions);
+            analysisInfoBuilder.setColToPartitions(colToPartitions);
             String jobType = resultRow.getColumnValue("job_type");
-            analysisTaskInfoBuilder.setJobType(JobType.valueOf(jobType));
+            analysisInfoBuilder.setJobType(JobType.valueOf(jobType));
             String analysisType = resultRow.getColumnValue("analysis_type");
-            analysisTaskInfoBuilder.setAnalysisType(AnalysisType.valueOf(analysisType));
+            analysisInfoBuilder.setAnalysisType(AnalysisType.valueOf(analysisType));
             String analysisMode = resultRow.getColumnValue("analysis_mode");
-            analysisTaskInfoBuilder.setAnalysisMode(AnalysisMode.valueOf(analysisMode));
+            analysisInfoBuilder.setAnalysisMode(AnalysisMode.valueOf(analysisMode));
             String analysisMethod = resultRow.getColumnValue("analysis_method");
-            analysisTaskInfoBuilder.setAnalysisMethod(AnalysisMethod.valueOf(analysisMethod));
+            analysisInfoBuilder.setAnalysisMethod(AnalysisMethod.valueOf(analysisMethod));
             String scheduleType = resultRow.getColumnValue("schedule_type");
-            analysisTaskInfoBuilder.setScheduleType(ScheduleType.valueOf(scheduleType));
+            analysisInfoBuilder.setScheduleType(ScheduleType.valueOf(scheduleType));
             String state = resultRow.getColumnValue("state");
-            analysisTaskInfoBuilder.setState(AnalysisState.valueOf(state));
+            analysisInfoBuilder.setState(AnalysisState.valueOf(state));
             String samplePercent = resultRow.getColumnValue("sample_percent");
-            analysisTaskInfoBuilder.setSamplePercent(StatisticsUtil.convertStrToInt(samplePercent));
+            analysisInfoBuilder.setSamplePercent(StatisticsUtil.convertStrToInt(samplePercent));
             String sampleRows = resultRow.getColumnValue("sample_rows");
-            analysisTaskInfoBuilder.setSampleRows(StatisticsUtil.convertStrToInt(sampleRows));
+            analysisInfoBuilder.setSampleRows(StatisticsUtil.convertStrToInt(sampleRows));
             String maxBucketNum = resultRow.getColumnValue("max_bucket_num");
-            analysisTaskInfoBuilder.setMaxBucketNum(StatisticsUtil.convertStrToInt(maxBucketNum));
+            analysisInfoBuilder.setMaxBucketNum(StatisticsUtil.convertStrToInt(maxBucketNum));
             String periodTimeInMs = resultRow.getColumnValue("period_time_in_ms");
-            analysisTaskInfoBuilder.setPeriodTimeInMs(StatisticsUtil.convertStrToInt(periodTimeInMs));
+            analysisInfoBuilder.setPeriodTimeInMs(StatisticsUtil.convertStrToInt(periodTimeInMs));
             String lastExecTimeInMs = resultRow.getColumnValue("last_exec_time_in_ms");
-            analysisTaskInfoBuilder.setLastExecTimeInMs(StatisticsUtil.convertStrToLong(lastExecTimeInMs));
+            analysisInfoBuilder.setLastExecTimeInMs(StatisticsUtil.convertStrToLong(lastExecTimeInMs));
             String message = resultRow.getColumnValue("message");
-            analysisTaskInfoBuilder.setMessage(message);
-            return analysisTaskInfoBuilder.build();
+            analysisInfoBuilder.setMessage(message);
+            return analysisInfoBuilder.build();
         } catch (Exception e) {
             LOG.warn("Failed to deserialize analysis task info.", e);
             return null;
@@ -246,4 +254,74 @@ public class AnalysisTaskInfo {
         Type type = new TypeToken<Map<String, Set<String>>>() {}.getType();
         return gson.fromJson(colToPartitionStr, type);
     }
+
+    @Override
+    public void write(DataOutput out) throws IOException {
+        out.writeLong(jobId);
+        out.writeLong(taskId);
+        Text.writeString(out, catalogName);
+        Text.writeString(out, dbName);
+        Text.writeString(out, tblName);
+        out.writeInt(colToPartitions.size());
+        for (Entry<String, Set<String>> entry : colToPartitions.entrySet()) {
+            Text.writeString(out, entry.getKey());
+            out.writeInt(entry.getValue().size());
+            for (String part : entry.getValue()) {
+                Text.writeString(out, part);
+            }
+        }
+        Text.writeString(out, colName);
+        out.writeLong(indexId);
+        Text.writeString(out, jobType.toString());
+        Text.writeString(out, analysisMode.toString());
+        Text.writeString(out, analysisMethod.toString());
+        Text.writeString(out, analysisType.toString());
+        out.writeInt(samplePercent);
+        out.writeInt(sampleRows);
+        out.writeInt(maxBucketNum);
+        out.writeLong(periodTimeInMs);
+        out.writeLong(lastExecTimeInMs);
+        Text.writeString(out, state.toString());
+        Text.writeString(out, scheduleType.toString());
+        Text.writeString(out, message);
+        out.writeBoolean(externalTableLevelTask);
+    }
+
+    public static AnalysisInfo read(DataInput dataInput) throws IOException {
+        AnalysisInfoBuilder analysisInfoBuilder = new AnalysisInfoBuilder();
+        analysisInfoBuilder.setJobId(dataInput.readLong());
+        long taskId = dataInput.readLong();
+        analysisInfoBuilder.setTaskId(taskId);
+        analysisInfoBuilder.setCatalogName(Text.readString(dataInput));
+        analysisInfoBuilder.setDbName(Text.readString(dataInput));
+        analysisInfoBuilder.setTblName(Text.readString(dataInput));
+        int size = dataInput.readInt();
+        Map<String, Set<String>> colToPartitions = new HashMap<>();
+        for (int i = 0; i < size; i++) {
+            String k = Text.readString(dataInput);
+            int partSize = dataInput.readInt();
+            Set<String> parts = new HashSet<>();
+            for (int j = 0; j < partSize; j++) {
+                parts.add(Text.readString(dataInput));
+            }
+            colToPartitions.put(k, parts);
+        }
+        analysisInfoBuilder.setColToPartitions(colToPartitions);
+        analysisInfoBuilder.setColName(Text.readString(dataInput));
+        analysisInfoBuilder.setIndexId(dataInput.readLong());
+        analysisInfoBuilder.setJobType(JobType.valueOf(Text.readString(dataInput)));
+        analysisInfoBuilder.setAnalysisMode(AnalysisMode.valueOf(Text.readString(dataInput)));
+        analysisInfoBuilder.setAnalysisMethod(AnalysisMethod.valueOf(Text.readString(dataInput)));
+        analysisInfoBuilder.setAnalysisType(AnalysisType.valueOf(Text.readString(dataInput)));
+        analysisInfoBuilder.setSamplePercent(dataInput.readInt());
+        analysisInfoBuilder.setSampleRows(dataInput.readInt());
+        analysisInfoBuilder.setMaxBucketNum(dataInput.readInt());
+        analysisInfoBuilder.setPeriodTimeInMs(dataInput.readLong());
+        analysisInfoBuilder.setLastExecTimeInMs(dataInput.readLong());
+        analysisInfoBuilder.setState(AnalysisState.valueOf(Text.readString(dataInput)));
+        analysisInfoBuilder.setScheduleType(ScheduleType.valueOf(Text.readString(dataInput)));
+        analysisInfoBuilder.setMessage(Text.readString(dataInput));
+        analysisInfoBuilder.setExternalTableLevelTask(dataInput.readBoolean());
+        return analysisInfoBuilder.build();
+    }
 }
diff --git a/fe/fe-core/src/main/java/org/apache/doris/statistics/AnalysisTaskInfoBuilder.java b/fe/fe-core/src/main/java/org/apache/doris/statistics/AnalysisInfoBuilder.java
similarity index 68%
rename from fe/fe-core/src/main/java/org/apache/doris/statistics/AnalysisTaskInfoBuilder.java
rename to fe/fe-core/src/main/java/org/apache/doris/statistics/AnalysisInfoBuilder.java
index acaae0baab..c47b1dc7ab 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/statistics/AnalysisTaskInfoBuilder.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/statistics/AnalysisInfoBuilder.java
@@ -17,16 +17,16 @@
 
 package org.apache.doris.statistics;
 
-import org.apache.doris.statistics.AnalysisTaskInfo.AnalysisMethod;
-import org.apache.doris.statistics.AnalysisTaskInfo.AnalysisMode;
-import org.apache.doris.statistics.AnalysisTaskInfo.AnalysisType;
-import org.apache.doris.statistics.AnalysisTaskInfo.JobType;
-import org.apache.doris.statistics.AnalysisTaskInfo.ScheduleType;
+import org.apache.doris.statistics.AnalysisInfo.AnalysisMethod;
+import org.apache.doris.statistics.AnalysisInfo.AnalysisMode;
+import org.apache.doris.statistics.AnalysisInfo.AnalysisType;
+import org.apache.doris.statistics.AnalysisInfo.JobType;
+import org.apache.doris.statistics.AnalysisInfo.ScheduleType;
 
 import java.util.Map;
 import java.util.Set;
 
-public class AnalysisTaskInfoBuilder {
+public class AnalysisInfoBuilder {
     private long jobId;
     private long taskId;
     private String catalogName;
@@ -34,7 +34,7 @@ public class AnalysisTaskInfoBuilder {
     private String tblName;
     private Map<String, Set<String>> colToPartitions;
     private String colName;
-    private Long indexId;
+    private long indexId = -1L;
     private JobType jobType;
     private AnalysisMode analysisMode;
     private AnalysisMethod analysisMethod;
@@ -46,13 +46,13 @@ public class AnalysisTaskInfoBuilder {
     private long lastExecTimeInMs;
     private AnalysisState state;
     private ScheduleType scheduleType;
-    private String message;
+    private String message = "";
     private boolean externalTableLevelTask;
 
-    public AnalysisTaskInfoBuilder() {
+    public AnalysisInfoBuilder() {
     }
 
-    public AnalysisTaskInfoBuilder(AnalysisTaskInfo info) {
+    public AnalysisInfoBuilder(AnalysisInfo info) {
         jobId = info.jobId;
         taskId = info.taskId;
         catalogName = info.catalogName;
@@ -75,120 +75,120 @@ public class AnalysisTaskInfoBuilder {
         scheduleType = info.scheduleType;
     }
 
-    public AnalysisTaskInfoBuilder setJobId(long jobId) {
+    public AnalysisInfoBuilder setJobId(long jobId) {
         this.jobId = jobId;
         return this;
     }
 
-    public AnalysisTaskInfoBuilder setTaskId(long taskId) {
+    public AnalysisInfoBuilder setTaskId(long taskId) {
         this.taskId = taskId;
         return this;
     }
 
-    public AnalysisTaskInfoBuilder setCatalogName(String catalogName) {
+    public AnalysisInfoBuilder setCatalogName(String catalogName) {
         this.catalogName = catalogName;
         return this;
     }
 
-    public AnalysisTaskInfoBuilder setDbName(String dbName) {
+    public AnalysisInfoBuilder setDbName(String dbName) {
         this.dbName = dbName;
         return this;
     }
 
-    public AnalysisTaskInfoBuilder setTblName(String tblName) {
+    public AnalysisInfoBuilder setTblName(String tblName) {
         this.tblName = tblName;
         return this;
     }
 
-    public AnalysisTaskInfoBuilder setColToPartitions(Map<String, Set<String>> colToPartitions) {
+    public AnalysisInfoBuilder setColToPartitions(Map<String, Set<String>> colToPartitions) {
         this.colToPartitions = colToPartitions;
         return this;
     }
 
-    public AnalysisTaskInfoBuilder setColName(String colName) {
+    public AnalysisInfoBuilder setColName(String colName) {
         this.colName = colName;
         return this;
     }
 
-    public AnalysisTaskInfoBuilder setIndexId(Long indexId) {
+    public AnalysisInfoBuilder setIndexId(Long indexId) {
         this.indexId = indexId;
         return this;
     }
 
-    public AnalysisTaskInfoBuilder setJobType(JobType jobType) {
+    public AnalysisInfoBuilder setJobType(JobType jobType) {
         this.jobType = jobType;
         return this;
     }
 
-    public AnalysisTaskInfoBuilder setAnalysisMode(AnalysisMode analysisMode) {
+    public AnalysisInfoBuilder setAnalysisMode(AnalysisMode analysisMode) {
         this.analysisMode = analysisMode;
         return this;
     }
 
-    public AnalysisTaskInfoBuilder setAnalysisMethod(AnalysisMethod analysisMethod) {
+    public AnalysisInfoBuilder setAnalysisMethod(AnalysisMethod analysisMethod) {
         this.analysisMethod = analysisMethod;
         return this;
     }
 
-    public AnalysisTaskInfoBuilder setAnalysisType(AnalysisType analysisType) {
+    public AnalysisInfoBuilder setAnalysisType(AnalysisType analysisType) {
         this.analysisType = analysisType;
         return this;
     }
 
-    public AnalysisTaskInfoBuilder setMaxBucketNum(int maxBucketNum) {
+    public AnalysisInfoBuilder setMaxBucketNum(int maxBucketNum) {
         this.maxBucketNum = maxBucketNum;
         return this;
     }
 
-    public AnalysisTaskInfoBuilder setSamplePercent(int samplePercent) {
+    public AnalysisInfoBuilder setSamplePercent(int samplePercent) {
         this.samplePercent = samplePercent;
         return this;
     }
 
-    public AnalysisTaskInfoBuilder setSampleRows(int sampleRows) {
+    public AnalysisInfoBuilder setSampleRows(int sampleRows) {
         this.sampleRows = sampleRows;
         return this;
     }
 
-    public AnalysisTaskInfoBuilder setPeriodTimeInMs(long periodTimeInMs) {
+    public AnalysisInfoBuilder setPeriodTimeInMs(long periodTimeInMs) {
         this.periodTimeInMs = periodTimeInMs;
         return this;
     }
 
-    public AnalysisTaskInfoBuilder setMessage(String message) {
+    public AnalysisInfoBuilder setMessage(String message) {
         this.message = message;
         return this;
     }
 
-    public AnalysisTaskInfoBuilder setLastExecTimeInMs(long lastExecTimeInMs) {
+    public AnalysisInfoBuilder setLastExecTimeInMs(long lastExecTimeInMs) {
         this.lastExecTimeInMs = lastExecTimeInMs;
         return this;
     }
 
-    public AnalysisTaskInfoBuilder setState(AnalysisState state) {
+    public AnalysisInfoBuilder setState(AnalysisState state) {
         this.state = state;
         return this;
     }
 
-    public AnalysisTaskInfoBuilder setScheduleType(ScheduleType scheduleType) {
+    public AnalysisInfoBuilder setScheduleType(ScheduleType scheduleType) {
         this.scheduleType = scheduleType;
         return this;
     }
 
-    public AnalysisTaskInfoBuilder setExternalTableLevelTask(boolean isTableLevel) {
+    public AnalysisInfoBuilder setExternalTableLevelTask(boolean isTableLevel) {
         this.externalTableLevelTask = isTableLevel;
         return this;
     }
 
-    public AnalysisTaskInfo build() {
-        return new AnalysisTaskInfo(jobId, taskId, catalogName, dbName, tblName, colToPartitions,
+    public AnalysisInfo build() {
+        return new AnalysisInfo(jobId, taskId, catalogName, dbName, tblName, colToPartitions,
                 colName, indexId, jobType, analysisMode, analysisMethod, analysisType, samplePercent,
                 sampleRows, maxBucketNum, periodTimeInMs, message, lastExecTimeInMs, state, scheduleType,
                 externalTableLevelTask);
     }
 
-    public AnalysisTaskInfoBuilder copy() {
-        return new AnalysisTaskInfoBuilder()
+    public AnalysisInfoBuilder copy() {
+        return new AnalysisInfoBuilder()
                 .setJobId(jobId)
                 .setTaskId(taskId)
                 .setCatalogName(catalogName)
diff --git a/fe/fe-core/src/main/java/org/apache/doris/statistics/AnalysisManager.java b/fe/fe-core/src/main/java/org/apache/doris/statistics/AnalysisManager.java
index f62a6e6c22..d48eed9618 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/statistics/AnalysisManager.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/statistics/AnalysisManager.java
@@ -17,7 +17,9 @@
 
 package org.apache.doris.statistics;
 
-import org.apache.doris.analysis.AnalyzeStmt;
+import org.apache.doris.analysis.AnalyzeDBStmt;
+import org.apache.doris.analysis.AnalyzeTblStmt;
+import org.apache.doris.analysis.DropAnalyzeJobStmt;
 import org.apache.doris.analysis.DropStatsStmt;
 import org.apache.doris.analysis.KillAnalysisJobStmt;
 import org.apache.doris.analysis.ShowAnalyzeStmt;
@@ -31,95 +33,168 @@ import org.apache.doris.catalog.Partition;
 import org.apache.doris.catalog.ScalarType;
 import org.apache.doris.catalog.TableIf;
 import org.apache.doris.catalog.TableIf.TableType;
+import org.apache.doris.common.AnalysisException;
+import org.apache.doris.common.Config;
 import org.apache.doris.common.DdlException;
 import org.apache.doris.common.FeConstants;
-import org.apache.doris.common.util.TimeUtils;
+import org.apache.doris.common.util.Daemon;
 import org.apache.doris.datasource.CatalogIf;
 import org.apache.doris.mysql.privilege.PrivPredicate;
+import org.apache.doris.persist.AnalyzeDeletionLog;
 import org.apache.doris.qe.ConnectContext;
 import org.apache.doris.qe.ShowResultSet;
 import org.apache.doris.qe.ShowResultSetMetaData;
-import org.apache.doris.statistics.AnalysisTaskInfo.AnalysisMethod;
-import org.apache.doris.statistics.AnalysisTaskInfo.AnalysisMode;
-import org.apache.doris.statistics.AnalysisTaskInfo.AnalysisType;
-import org.apache.doris.statistics.AnalysisTaskInfo.JobType;
-import org.apache.doris.statistics.AnalysisTaskInfo.ScheduleType;
-import org.apache.doris.statistics.util.InternalQueryResult.ResultRow;
+import org.apache.doris.statistics.AnalysisInfo.AnalysisMethod;
+import org.apache.doris.statistics.AnalysisInfo.AnalysisMode;
+import org.apache.doris.statistics.AnalysisInfo.AnalysisType;
+import org.apache.doris.statistics.AnalysisInfo.JobType;
+import org.apache.doris.statistics.AnalysisInfo.ScheduleType;
 import org.apache.doris.statistics.util.StatisticsUtil;
 
 import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.commons.text.StringSubstitutor;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
+import org.jetbrains.annotations.Nullable;
 
-import java.time.Instant;
-import java.time.LocalDateTime;
-import java.time.ZoneId;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.Comparator;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Set;
+import java.util.StringJoiner;
+import java.util.TreeMap;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.TimeUnit;
+import java.util.function.Function;
+import java.util.function.Predicate;
 import java.util.stream.Collectors;
 
-public class AnalysisManager {
+public class AnalysisManager extends Daemon {
 
-    public final AnalysisTaskScheduler taskScheduler;
+    public AnalysisTaskScheduler taskScheduler;
 
     private static final Logger LOG = LogManager.getLogger(AnalysisManager.class);
 
-    private static final String UPDATE_JOB_STATE_SQL_TEMPLATE = "UPDATE "
-            + FeConstants.INTERNAL_DB_NAME + "." + StatisticConstants.ANALYSIS_JOB_TABLE + " "
-            + "SET state = '${jobState}' ${message} ${updateExecTime} "
-            + "WHERE job_id = ${jobId} and (task_id=${taskId} || ${isAllTask})";
+    private ConcurrentMap<Long, Map<Long, BaseAnalysisTask>> analysisJobIdToTaskMap = new ConcurrentHashMap<>();
 
-    private static final String SHOW_JOB_STATE_SQL_TEMPLATE = "SELECT "
-            + "job_id, catalog_name, db_name, tbl_name, col_name, job_type, "
-            + "analysis_type, message, last_exec_time_in_ms, state, schedule_type "
-            + "FROM " + FeConstants.INTERNAL_DB_NAME + "." + StatisticConstants.ANALYSIS_JOB_TABLE;
+    private StatisticsCache statisticsCache;
 
-    // The time field that needs to be displayed
-    private static final String LAST_EXEC_TIME_IN_MS = "last_exec_time_in_ms";
+    private AnalysisTaskExecutor taskExecutor;
 
-    private final ConcurrentMap<Long, Map<Long, BaseAnalysisTask>> analysisJobIdToTaskMap;
+    private final Map<Long, AnalysisInfo> analysisTaskInfoMap = Collections.synchronizedMap(new TreeMap<>());
+    private final Map<Long, AnalysisInfo> analysisJobInfoMap = Collections.synchronizedMap(new TreeMap<>());
 
-    private StatisticsCache statisticsCache;
+    private final ConcurrentMap<ConnectContext, SyncTaskCollection> ctxToSyncTask = new ConcurrentHashMap<>();
 
-    private final AnalysisTaskExecutor taskExecutor;
+    public AnalysisManager() {
+        super(TimeUnit.SECONDS.toMillis(StatisticConstants.ANALYZE_MANAGER_INTERVAL_IN_SECS));
+        if (!Env.isCheckpointThread()) {
+            this.taskScheduler = new AnalysisTaskScheduler();
+            this.taskExecutor = new AnalysisTaskExecutor(taskScheduler);
+            this.statisticsCache = new StatisticsCache();
+            taskExecutor.start();
+        }
+    }
 
-    private ConcurrentMap<ConnectContext, SyncTaskCollection> ctxToSyncTask = new ConcurrentHashMap<>();
+    @Override
+    protected void runOneCycle() {
+        clear();
+    }
 
-    public AnalysisManager() {
-        analysisJobIdToTaskMap = new ConcurrentHashMap<>();
-        this.taskScheduler = new AnalysisTaskScheduler();
-        taskExecutor = new AnalysisTaskExecutor(taskScheduler);
-        this.statisticsCache = new StatisticsCache();
-        taskExecutor.start();
+    private void clear() {
+        clearMeta(analysisJobInfoMap, (a) ->
+                        a.scheduleType.equals(ScheduleType.ONCE)
+                                && System.currentTimeMillis() - a.lastExecTimeInMs
+                                > TimeUnit.DAYS.toMillis(StatisticConstants.ANALYSIS_JOB_INFO_EXPIRATION_TIME_IN_DAYS),
+                (id) -> {
+                    Env.getCurrentEnv().getEditLog().logDeleteAnalysisJob(new AnalyzeDeletionLog(id));
+                    return null;
+                });
+        clearMeta(analysisTaskInfoMap, (a) -> System.currentTimeMillis() - a.lastExecTimeInMs
+                        > TimeUnit.DAYS.toMillis(StatisticConstants.ANALYSIS_JOB_INFO_EXPIRATION_TIME_IN_DAYS),
+                (id) -> {
+                    Env.getCurrentEnv().getEditLog().logDeleteAnalysisTask(new AnalyzeDeletionLog(id));
+                    return null;
+                });
+    }
+
+    private void clearMeta(Map<Long, AnalysisInfo> infoMap, Predicate<AnalysisInfo> isExpired,
+            Function<Long, Void> writeLog) {
+        synchronized (infoMap) {
+            List<Long> expired = new ArrayList<>();
+            for (Entry<Long, AnalysisInfo> entry : infoMap.entrySet()) {
+                if (isExpired.test(entry.getValue())) {
+                    expired.add(entry.getKey());
+                }
+            }
+            for (Long k : expired) {
+                infoMap.remove(k);
+                writeLog.apply(k);
+            }
+        }
     }
 
     public StatisticsCache getStatisticsCache() {
         return statisticsCache;
     }
 
+    public void createAnalysisJobs(AnalyzeDBStmt analyzeDBStmt) throws DdlException {
+        DatabaseIf<TableIf> db = analyzeDBStmt.getDb();
+        List<TableIf> tbls = db.getTables();
+        List<AnalysisInfo> analysisInfos = new ArrayList<>();
+        db.readLock();
+        try {
+            List<AnalyzeTblStmt> analyzeStmts = new ArrayList<>();
+            for (TableIf table : tbls) {
+                TableName tableName = new TableName(analyzeDBStmt.getCtlIf().getName(), db.getFullName(),
+                        table.getName());
+                AnalyzeTblStmt analyzeTblStmt = new AnalyzeTblStmt(analyzeDBStmt.getAnalyzeProperties(), tableName,
+                        table.getBaseSchema().stream().map(
+                                Column::getName).collect(
+                                Collectors.toList()), db.getId(), table);
+                try {
+                    analyzeTblStmt.check();
+                } catch (AnalysisException analysisException) {
+                    throw new DdlException(analysisException.getMessage(), analysisException);
+                }
+                analyzeStmts.add(analyzeTblStmt);
+            }
+            for (AnalyzeTblStmt analyzeTblStmt : analyzeStmts) {
+                analysisInfos.add(buildAndAssignJob(analyzeTblStmt));
+            }
+            sendJobId(analysisInfos);
+        } finally {
+            db.readUnlock();
+        }
+
+    }
+
     // Each analyze stmt corresponding to an analysis job.
-    public void createAnalysisJob(AnalyzeStmt stmt) throws DdlException {
+    public void createAnalysisJob(AnalyzeTblStmt stmt) throws DdlException {
+        AnalysisInfo jobInfo = buildAndAssignJob(stmt);
+        if (jobInfo == null) {
+            return;
+        }
+        sendJobId(ImmutableList.of(jobInfo));
+    }
+
+    @Nullable
+    private AnalysisInfo buildAndAssignJob(AnalyzeTblStmt stmt) throws DdlException {
         if (!StatisticsUtil.statsTblAvailable() && !FeConstants.runningUnitTest) {
             throw new DdlException("Stats table not available, please make sure your cluster status is normal");
         }
 
-        AnalysisTaskInfo jobInfo = buildAnalysisJobInfo(stmt);
+        AnalysisInfo jobInfo = buildAnalysisJobInfo(stmt);
         if (jobInfo.colToPartitions.isEmpty()) {
             // No statistics need to be collected or updated
-            return;
+            return null;
         }
 
         boolean isSync = stmt.isSync();
@@ -128,8 +203,7 @@ public class AnalysisManager {
         createTaskForMVIdx(jobInfo, analysisTaskInfos, isSync);
         createTaskForExternalTable(jobInfo, analysisTaskInfos, isSync);
 
-        ConnectContext ctx = ConnectContext.get();
-        if (!isSync || ctx.getSessionVariable().enableSaveStatisticsSyncJob) {
+        if (!isSync) {
             persistAnalysisJob(jobInfo);
             analysisJobIdToTaskMap.put(jobInfo.jobId, analysisTaskInfos);
         }
@@ -142,16 +216,16 @@ public class AnalysisManager {
 
         if (isSync) {
             syncExecute(analysisTaskInfos.values());
-            return;
+            return null;
         }
 
         analysisTaskInfos.values().forEach(taskScheduler::schedule);
-        sendJobId(jobInfo.jobId);
+        return jobInfo;
     }
 
     // Analysis job created by the system
-    public void createAnalysisJob(AnalysisTaskInfo info) throws DdlException {
-        AnalysisTaskInfo jobInfo = buildAnalysisJobInfo(info);
+    public void createAnalysisJob(AnalysisInfo info) throws DdlException {
+        AnalysisInfo jobInfo = buildAnalysisJobInfo(info);
         if (jobInfo.colToPartitions.isEmpty()) {
             // No statistics need to be collected or updated
             return;
@@ -173,14 +247,24 @@ public class AnalysisManager {
         analysisTaskInfos.values().forEach(taskScheduler::schedule);
     }
 
-    private void sendJobId(long jobId) {
+    private void sendJobId(List<AnalysisInfo> analysisInfos) {
         List<Column> columns = new ArrayList<>();
+        columns.add(new Column("Catalog_Name", ScalarType.createVarchar(1024)));
+        columns.add(new Column("DB_Name", ScalarType.createVarchar(1024)));
+        columns.add(new Column("Table_Name", ScalarType.createVarchar(1024)));
+        columns.add(new Column("Columns", ScalarType.createVarchar(1024)));
         columns.add(new Column("Job_Id", ScalarType.createVarchar(19)));
         ShowResultSetMetaData commonResultSetMetaData = new ShowResultSetMetaData(columns);
         List<List<String>> resultRows = new ArrayList<>();
-        List<String> row = new ArrayList<>();
-        row.add(String.valueOf(jobId));
-        resultRows.add(row);
+        for (AnalysisInfo analysisInfo : analysisInfos) {
+            List<String> row = new ArrayList<>();
+            row.add(analysisInfo.catalogName);
+            row.add(analysisInfo.dbName);
+            row.add(analysisInfo.tblName);
+            row.add(analysisInfo.colName);
+            row.add(String.valueOf(analysisInfo.jobId));
+            resultRows.add(row);
+        }
         ShowResultSet commonResultSet = new ShowResultSet(commonResultSetMetaData, resultRows);
         try {
             ConnectContext.get().getExecutor().sendResultSet(commonResultSet);
@@ -204,7 +288,7 @@ public class AnalysisManager {
      * TODO Supports incremental collection of statistics from materialized views
      */
     private Map<String, Set<String>> validateAndGetPartitions(TableIf table, Set<String> columnNames,
-            AnalysisType analysisType,  AnalysisMode analysisMode) throws DdlException {
+            AnalysisType analysisType, AnalysisMode analysisMode) throws DdlException {
         long tableId = table.getId();
         Set<String> partitionNames = table.getPartitionNames();
 
@@ -241,7 +325,7 @@ public class AnalysisManager {
             StatisticsRepository.dropStatistics(invalidPartIds);
         }
 
-        if (analysisMode == AnalysisMode.INCREMENTAL && analysisType == AnalysisType.COLUMN) {
+        if (analysisMode == AnalysisMode.INCREMENTAL && analysisType == AnalysisType.FUNDAMENTALS) {
             existColAndPartsForStats.values().forEach(partIds -> partIds.removeAll(invalidPartIds));
             // In incremental collection mode, just collect the uncollected partition statistics
             existColAndPartsForStats.forEach((columnName, partitionIds) -> {
@@ -263,8 +347,8 @@ public class AnalysisManager {
         return columnToPartitions;
     }
 
-    private AnalysisTaskInfo buildAnalysisJobInfo(AnalyzeStmt stmt) throws DdlException {
-        AnalysisTaskInfoBuilder taskInfoBuilder = new AnalysisTaskInfoBuilder();
+    private AnalysisInfo buildAnalysisJobInfo(AnalyzeTblStmt stmt) throws DdlException {
+        AnalysisInfoBuilder taskInfoBuilder = new AnalysisInfoBuilder();
         long jobId = Env.getCurrentEnv().getNextId();
         String catalogName = stmt.getCatalogName();
         String db = stmt.getDBName();
@@ -284,6 +368,11 @@ public class AnalysisManager {
         taskInfoBuilder.setCatalogName(catalogName);
         taskInfoBuilder.setDbName(db);
         taskInfoBuilder.setTblName(tblName);
+        StringJoiner stringJoiner = new StringJoiner(",", "[", "]");
+        for (String colName : columnNames) {
+            stringJoiner.add(colName);
+        }
+        taskInfoBuilder.setColName(stringJoiner.toString());
         taskInfoBuilder.setJobType(JobType.MANUAL);
         taskInfoBuilder.setState(AnalysisState.PENDING);
         taskInfoBuilder.setAnalysisType(analysisType);
@@ -316,8 +405,8 @@ public class AnalysisManager {
         return taskInfoBuilder.build();
     }
 
-    private AnalysisTaskInfo buildAnalysisJobInfo(AnalysisTaskInfo jobInfo) {
-        AnalysisTaskInfoBuilder taskInfoBuilder = new AnalysisTaskInfoBuilder();
+    private AnalysisInfo buildAnalysisJobInfo(AnalysisInfo jobInfo) {
+        AnalysisInfoBuilder taskInfoBuilder = new AnalysisInfoBuilder();
         taskInfoBuilder.setJobId(jobInfo.jobId);
         taskInfoBuilder.setCatalogName(jobInfo.catalogName);
         taskInfoBuilder.setDbName(jobInfo.dbName);
@@ -345,20 +434,16 @@ public class AnalysisManager {
         return taskInfoBuilder.build();
     }
 
-    private void persistAnalysisJob(AnalysisTaskInfo jobInfo) throws DdlException {
+    private void persistAnalysisJob(AnalysisInfo jobInfo) throws DdlException {
         if (jobInfo.scheduleType == ScheduleType.PERIOD && jobInfo.lastExecTimeInMs > 0) {
             return;
         }
-        try {
-            AnalysisTaskInfoBuilder jobInfoBuilder = new AnalysisTaskInfoBuilder(jobInfo);
-            AnalysisTaskInfo analysisTaskInfo = jobInfoBuilder.setTaskId(-1).build();
-            StatisticsRepository.persistAnalysisTask(analysisTaskInfo);
-        } catch (Throwable t) {
-            throw new DdlException(t.getMessage(), t);
-        }
+        AnalysisInfoBuilder jobInfoBuilder = new AnalysisInfoBuilder(jobInfo);
+        AnalysisInfo analysisInfo = jobInfoBuilder.setTaskId(-1).build();
+        logCreateAnalysisJob(analysisInfo);
     }
 
-    private void createTaskForMVIdx(AnalysisTaskInfo jobInfo, Map<Long, BaseAnalysisTask> analysisTasks,
+    private void createTaskForMVIdx(AnalysisInfo jobInfo, Map<Long, BaseAnalysisTask> analysisTasks,
             boolean isSync) throws DdlException {
         TableIf table;
         try {
@@ -384,53 +469,59 @@ public class AnalysisManager {
                 }
                 long indexId = meta.getIndexId();
                 long taskId = Env.getCurrentEnv().getNextId();
-                AnalysisTaskInfoBuilder indexTaskInfoBuilder = new AnalysisTaskInfoBuilder(jobInfo);
-                AnalysisTaskInfo analysisTaskInfo = indexTaskInfoBuilder.setIndexId(indexId)
+                AnalysisInfoBuilder indexTaskInfoBuilder = new AnalysisInfoBuilder(jobInfo);
+                AnalysisInfo analysisInfo = indexTaskInfoBuilder.setIndexId(indexId)
                         .setTaskId(taskId).build();
-                analysisTasks.put(taskId, createTask(analysisTaskInfo));
-                if (isSync && !ConnectContext.get().getSessionVariable().enableSaveStatisticsSyncJob) {
+                if (isSync) {
                     return;
                 }
-                try {
-                    StatisticsRepository.persistAnalysisTask(analysisTaskInfo);
-                } catch (Exception e) {
-                    throw new DdlException("Failed to create analysis task", e);
-                }
+                analysisTasks.put(taskId, createTask(analysisInfo));
+                logCreateAnalysisJob(analysisInfo);
             }
         } finally {
             olapTable.readUnlock();
         }
     }
 
-    private void createTaskForEachColumns(AnalysisTaskInfo jobInfo, Map<Long, BaseAnalysisTask> analysisTasks,
+    private void createTaskForEachColumns(AnalysisInfo jobInfo, Map<Long, BaseAnalysisTask> analysisTasks,
             boolean isSync) throws DdlException {
         Map<String, Set<String>> columnToPartitions = jobInfo.colToPartitions;
         for (Entry<String, Set<String>> entry : columnToPartitions.entrySet()) {
             long indexId = -1;
             long taskId = Env.getCurrentEnv().getNextId();
             String colName = entry.getKey();
-            AnalysisTaskInfoBuilder colTaskInfoBuilder = new AnalysisTaskInfoBuilder(jobInfo);
+            AnalysisInfoBuilder colTaskInfoBuilder = new AnalysisInfoBuilder(jobInfo);
             if (jobInfo.analysisType != AnalysisType.HISTOGRAM) {
-                colTaskInfoBuilder.setAnalysisType(AnalysisType.COLUMN);
+                colTaskInfoBuilder.setAnalysisType(AnalysisType.FUNDAMENTALS);
                 colTaskInfoBuilder.setColToPartitions(Collections.singletonMap(colName, entry.getValue()));
             }
-            AnalysisTaskInfo analysisTaskInfo = colTaskInfoBuilder.setColName(colName).setIndexId(indexId)
+            AnalysisInfo analysisInfo = colTaskInfoBuilder.setColName(colName).setIndexId(indexId)
                     .setTaskId(taskId).build();
-            analysisTasks.put(taskId, createTask(analysisTaskInfo));
-            if (isSync && !ConnectContext.get().getSessionVariable().enableSaveStatisticsSyncJob) {
+            analysisTasks.put(taskId, createTask(analysisInfo));
+            if (isSync) {
                 continue;
             }
             try {
-                StatisticsRepository.persistAnalysisTask(analysisTaskInfo);
+                logCreateAnalysisTask(analysisInfo);
             } catch (Exception e) {
                 throw new DdlException("Failed to create analysis task", e);
             }
         }
     }
 
-    private void createTaskForExternalTable(AnalysisTaskInfo jobInfo,
-                                            Map<Long, BaseAnalysisTask> analysisTasks,
-                                            boolean isSync) throws DdlException {
+    private void logCreateAnalysisTask(AnalysisInfo analysisInfo) {
+        Env.getCurrentEnv().getEditLog().logCreateAnalysisTasks(analysisInfo);
+        analysisTaskInfoMap.put(analysisInfo.taskId, analysisInfo);
+    }
+
+    private void logCreateAnalysisJob(AnalysisInfo analysisJob) {
+        Env.getCurrentEnv().getEditLog().logCreateAnalysisJob(analysisJob);
+        analysisJobInfoMap.put(analysisJob.jobId, analysisJob);
+    }
+
+    private void createTaskForExternalTable(AnalysisInfo jobInfo,
+            Map<Long, BaseAnalysisTask> analysisTasks,
+            boolean isSync) throws DdlException {
         TableIf table;
         try {
             table = StatisticsUtil.findTable(jobInfo.catalogName, jobInfo.dbName, jobInfo.tblName);
@@ -441,50 +532,58 @@ public class AnalysisManager {
         if (jobInfo.analysisType == AnalysisType.HISTOGRAM || table.getType() != TableType.HMS_EXTERNAL_TABLE) {
             return;
         }
-        AnalysisTaskInfoBuilder colTaskInfoBuilder = new AnalysisTaskInfoBuilder(jobInfo);
+        AnalysisInfoBuilder colTaskInfoBuilder = new AnalysisInfoBuilder(jobInfo);
         long taskId = Env.getCurrentEnv().getNextId();
-        AnalysisTaskInfo analysisTaskInfo = colTaskInfoBuilder.setIndexId(-1L)
+        AnalysisInfo analysisInfo = colTaskInfoBuilder.setIndexId(-1L)
                 .setTaskId(taskId).setExternalTableLevelTask(true).build();
-        analysisTasks.put(taskId, createTask(analysisTaskInfo));
+        analysisTasks.put(taskId, createTask(analysisInfo));
         try {
-            StatisticsRepository.persistAnalysisTask(analysisTaskInfo);
+            logCreateAnalysisJob(analysisInfo);
         } catch (Exception e) {
             throw new DdlException("Failed to create analysis task", e);
         }
     }
 
-    public void updateTaskStatus(AnalysisTaskInfo info, AnalysisState jobState, String message, long time) {
+    public void updateTaskStatus(AnalysisInfo info, AnalysisState jobState, String message, long time) {
         if (analysisJobIdToTaskMap.get(info.jobId) == null) {
             return;
         }
-        Map<String, String> params = new HashMap<>();
-        params.put("jobState", jobState.toString());
-        params.put("message", StringUtils.isNotEmpty(message) ? String.format(", message = '%s'", message) : "");
-        params.put("updateExecTime", time == -1 ? "" : ", last_exec_time_in_ms=" + time);
-        params.put("jobId", String.valueOf(info.jobId));
-        params.put("taskId", String.valueOf(info.taskId));
-        params.put("isAllTask", "false");
-        try {
-            StatisticsUtil.execUpdate(new StringSubstitutor(params).replace(UPDATE_JOB_STATE_SQL_TEMPLATE));
-        } catch (Exception e) {
-            LOG.warn(String.format("Failed to update state for task: %d, %d", info.jobId, info.taskId), e);
-        } finally {
-            info.state = jobState;
-            if (analysisJobIdToTaskMap.get(info.jobId).values()
-                    .stream().allMatch(t -> t.info.state != null
-                            && t.info.state != AnalysisState.PENDING && t.info.state != AnalysisState.RUNNING)) {
-                analysisJobIdToTaskMap.remove(info.jobId);
-                params.put("taskId", String.valueOf(-1));
-                try {
-                    StatisticsUtil.execUpdate(new StringSubstitutor(params).replace(UPDATE_JOB_STATE_SQL_TEMPLATE));
-                } catch (Exception e) {
-                    LOG.warn(String.format("Failed to update state for job: %s", info.jobId), e);
-                }
+        info.state = jobState;
+        info.message = message;
+        info.lastExecTimeInMs = time;
+        logCreateAnalysisTask(info);
+
+        AnalysisInfo job = analysisJobInfoMap.get(info.jobId);
+        job.lastExecTimeInMs = time;
+        if (info.state.equals(AnalysisState.RUNNING) && !job.state.equals(AnalysisState.PENDING)) {
+            job.state = AnalysisState.RUNNING;
+            Env.getCurrentEnv().getEditLog().logCreateAnalysisTasks(job);
+        }
+        boolean allFinished = true;
+        boolean hasFailure = false;
+        for (BaseAnalysisTask task : analysisJobIdToTaskMap.get(info.jobId).values()) {
+            AnalysisInfo taskInfo = task.info;
+            if (taskInfo.state.equals(AnalysisState.RUNNING) || taskInfo.state.equals(AnalysisState.PENDING)) {
+                allFinished = false;
+                break;
+            }
+            if (taskInfo.state.equals(AnalysisState.FAILED)) {
+                hasFailure = true;
             }
         }
+        if (allFinished) {
+            if (hasFailure) {
+                job.state = AnalysisState.FAILED;
+                logCreateAnalysisJob(job);
+            } else {
+                job.state = AnalysisState.FINISHED;
+                logCreateAnalysisJob(job);
+            }
+            analysisJobIdToTaskMap.remove(job.jobId);
+        }
     }
 
-    private void updateTableStats(AnalysisTaskInfo jobInfo) throws Throwable {
+    private void updateTableStats(AnalysisInfo jobInfo) throws Throwable {
         Map<String, String> params = buildTableStatsParams(jobInfo);
         TableIf tbl = StatisticsUtil.findTable(jobInfo.catalogName,
                 jobInfo.dbName, jobInfo.tblName);
@@ -499,11 +598,11 @@ public class AnalysisManager {
     }
 
     @SuppressWarnings("rawtypes")
-    private Map<String, String> buildTableStatsParams(AnalysisTaskInfo jobInfo) throws Throwable {
+    private Map<String, String> buildTableStatsParams(AnalysisInfo jobInfo) throws Throwable {
         CatalogIf catalog = StatisticsUtil.findCatalog(jobInfo.catalogName);
         DatabaseIf db = StatisticsUtil.findDatabase(jobInfo.catalogName, jobInfo.dbName);
         TableIf tbl = StatisticsUtil.findTable(jobInfo.catalogName, jobInfo.dbName, jobInfo.tblName);
-        String indexId = jobInfo.indexId == null ? "-1" : String.valueOf(jobInfo.indexId);
+        String indexId = String.valueOf(jobInfo.indexId);
         String id = StatisticsUtil.constructId(tbl.getId(), indexId);
         Map<String, String> commonParams = new HashMap<>();
         commonParams.put("id", id);
@@ -533,32 +632,16 @@ public class AnalysisManager {
         StatisticsRepository.persistTableStats(tblParams);
     }
 
-    public List<List<Comparable>> showAnalysisJob(ShowAnalyzeStmt stmt) throws DdlException {
-        String whereClause = stmt.getWhereClause();
-        long limit = stmt.getLimit();
-        String executeSql = SHOW_JOB_STATE_SQL_TEMPLATE
-                + (whereClause.isEmpty() ? "" : " WHERE " + whereClause)
-                + (limit == -1L ? "" : " LIMIT " + limit);
-
-        List<List<Comparable>> results = Lists.newArrayList();
-        ImmutableList<String> titleNames = stmt.getTitleNames();
-        List<ResultRow> resultRows = StatisticsUtil.execStatisticQuery(executeSql);
-
-        for (ResultRow resultRow : resultRows) {
-            List<Comparable> result = Lists.newArrayList();
-            for (String column : titleNames) {
-                String value = resultRow.getColumnValue(column);
-                if (LAST_EXEC_TIME_IN_MS.equals(column)) {
-                    long timeMillis = Long.parseLong(value);
-                    value = TimeUtils.DATETIME_FORMAT.format(
-                            LocalDateTime.ofInstant(Instant.ofEpochMilli(timeMillis), ZoneId.systemDefault()));
-                }
-                result.add(value);
-            }
-            results.add(result);
-        }
-
-        return results;
+    public List<AnalysisInfo> showAnalysisJob(ShowAnalyzeStmt stmt) {
+        String state = stmt.getStateValue();
+        TableName tblName = stmt.getDbTableName();
+        return analysisJobInfoMap.values().stream()
+                .filter(a -> stmt.getJobId() == 0 || a.jobId == stmt.getJobId())
+                .filter(a -> state == null || a.state.equals(AnalysisState.valueOf(state)))
+                .filter(a -> tblName == null || a.catalogName.equals(tblName.getCtl())
+                        && a.dbName.equals(tblName.getDb()) && a.tblName.equals(tblName.getTbl()))
+                .sorted(Comparator.comparingLong(a -> a.jobId))
+                .collect(Collectors.toList());
     }
 
     private void syncExecute(Collection<BaseAnalysisTask> tasks) {
@@ -586,37 +669,36 @@ public class AnalysisManager {
     }
 
     public void handleKillAnalyzeStmt(KillAnalysisJobStmt killAnalysisJobStmt) throws DdlException {
-        Map<Long, BaseAnalysisTask> analysisTaskInfoMap = analysisJobIdToTaskMap.remove(killAnalysisJobStmt.jobId);
-        if (analysisTaskInfoMap == null) {
+        Map<Long, BaseAnalysisTask> analysisTaskMap = analysisJobIdToTaskMap.remove(killAnalysisJobStmt.jobId);
+        if (analysisTaskMap == null) {
             throw new DdlException("Job not exists or already finished");
         }
-        BaseAnalysisTask anyTask = analysisTaskInfoMap.values().stream().findFirst().orElse(null);
+        BaseAnalysisTask anyTask = analysisTaskMap.values().stream().findFirst().orElse(null);
         if (anyTask == null) {
             return;
         }
         checkPriv(anyTask);
-        for (BaseAnalysisTask taskInfo : analysisTaskInfoMap.values()) {
+        logKilled(analysisJobInfoMap.get(anyTask.getJobId()));
+        for (BaseAnalysisTask taskInfo : analysisTaskMap.values()) {
             taskInfo.markAsKilled();
+            logKilled(taskInfo.info);
         }
-        Map<String, String> params = new HashMap<>();
-        params.put("jobState", AnalysisState.FAILED.toString());
-        params.put("message", ", message = 'Killed by user : " + ConnectContext.get().getQualifiedUser() + "'");
-        params.put("updateExecTime", ", last_exec_time_in_ms=" + System.currentTimeMillis());
-        params.put("jobId", String.valueOf(killAnalysisJobStmt.jobId));
-        params.put("taskId", "'-1'");
-        params.put("isAllTask", "true");
-        try {
-            StatisticsUtil.execUpdate(new StringSubstitutor(params).replace(UPDATE_JOB_STATE_SQL_TEMPLATE));
-        } catch (Exception e) {
-            LOG.warn("Failed to update status", e);
-        }
+    }
+
+    private void logKilled(AnalysisInfo info) {
+        info.state = AnalysisState.FAILED;
+        info.message = "Killed by user: " + ConnectContext.get().getQualifiedUser();
+        info.lastExecTimeInMs = System.currentTimeMillis();
+        Env.getCurrentEnv().getEditLog().logCreateAnalysisTasks(info);
     }
 
     private void checkPriv(BaseAnalysisTask analysisTask) {
-        String dbName = analysisTask.db.getFullName();
-        String tblName = analysisTask.tbl.getName();
+        checkPriv(analysisTask.info);
+    }
+
+    private void checkPriv(AnalysisInfo analysisInfo) {
         if (!Env.getCurrentEnv().getAccessManager()
-                .checkTblPriv(ConnectContext.get(), dbName, tblName, PrivPredicate.SELECT)) {
+                .checkTblPriv(ConnectContext.get(), analysisInfo.dbName, analysisInfo.tblName, PrivPredicate.SELECT)) {
             throw new RuntimeException("You need at least SELECT PRIV to corresponding table to kill this analyze"
                     + " job");
         }
@@ -629,17 +711,33 @@ public class AnalysisManager {
         }
     }
 
-    private BaseAnalysisTask createTask(AnalysisTaskInfo analysisTaskInfo) throws DdlException {
+    private BaseAnalysisTask createTask(AnalysisInfo analysisInfo) throws DdlException {
         try {
-            TableIf table = StatisticsUtil.findTable(analysisTaskInfo.catalogName,
-                    analysisTaskInfo.dbName, analysisTaskInfo.tblName);
-            return table.createAnalysisTask(analysisTaskInfo);
+            TableIf table = StatisticsUtil.findTable(analysisInfo.catalogName,
+                    analysisInfo.dbName, analysisInfo.tblName);
+            return table.createAnalysisTask(analysisInfo);
         } catch (Throwable t) {
             LOG.warn("Failed to find table", t);
-            throw new DdlException("Error when trying to find table", t);
+            throw new DdlException("Failed to create task", t);
         }
     }
 
+    public void replayCreateAnalysisJob(AnalysisInfo taskInfo) {
+        this.analysisJobInfoMap.put(taskInfo.jobId, taskInfo);
+    }
+
+    public void replayCreateAnalysisTask(AnalysisInfo jobInfo) {
+        this.analysisTaskInfoMap.put(jobInfo.taskId, jobInfo);
+    }
+
+    public void replayDeleteAnalysisJob(AnalyzeDeletionLog log) {
+        this.analysisJobInfoMap.remove(log.id);
+    }
+
+    public void replayDeleteAnalysisTask(AnalyzeDeletionLog log) {
+        this.analysisTaskInfoMap.remove(log.id);
+    }
+
     private static class SyncTaskCollection {
         public volatile boolean cancelled;
 
@@ -675,10 +773,57 @@ public class AnalysisManager {
         }
 
         private void updateSyncTaskStatus(BaseAnalysisTask task, AnalysisState state) {
-            if (ConnectContext.get().getSessionVariable().enableSaveStatisticsSyncJob) {
-                Env.getCurrentEnv().getAnalysisManager()
-                        .updateTaskStatus(task.info, state, "", System.currentTimeMillis());
-            }
+            Env.getCurrentEnv().getAnalysisManager()
+                    .updateTaskStatus(task.info, state, "", System.currentTimeMillis());
         }
     }
+
+    public List<AnalysisInfo> findAutomaticAnalysisJobs() {
+        synchronized (analysisJobInfoMap) {
+            return analysisJobInfoMap.values().stream()
+                    .filter(a ->
+                            a.scheduleType.equals(ScheduleType.AUTOMATIC)
+                                    && (!(a.state.equals(AnalysisState.RUNNING)
+                                    || a.state.equals(AnalysisState.PENDING)))
+                                    && System.currentTimeMillis() - a.lastExecTimeInMs
+                                    > TimeUnit.MINUTES.toMillis(Config.auto_check_statistics_in_minutes))
+                    .collect(Collectors.toList());
+        }
+    }
+
+    public List<AnalysisInfo> findPeriodicJobs() {
+        synchronized (analysisJobInfoMap) {
+            return analysisJobInfoMap.values().stream()
+                    .filter(a -> a.scheduleType.equals(ScheduleType.PERIOD)
+                            && (a.state.equals(AnalysisState.FINISHED))
+                            && System.currentTimeMillis() - a.lastExecTimeInMs > a.periodTimeInMs)
+                    .collect(Collectors.toList());
+        }
+    }
+
+    public List<AnalysisInfo> findTasks(long jobId) {
+        synchronized (analysisTaskInfoMap) {
+            return analysisTaskInfoMap.values().stream().filter(i -> i.jobId == jobId).collect(Collectors.toList());
+        }
+    }
+
+    public void removeAll(List<AnalysisInfo> analysisInfos) {
+        for (AnalysisInfo analysisInfo : analysisInfos) {
+            analysisTaskInfoMap.remove(analysisInfo.taskId);
+        }
+    }
+
+    public void dropAnalyzeJob(DropAnalyzeJobStmt analyzeJobStmt) throws DdlException {
+        AnalysisInfo jobInfo = analysisJobInfoMap.get(analyzeJobStmt.getJobId());
+        if (jobInfo == null) {
+            throw new DdlException(String.format("Analyze job [%d] not exists", jobInfo.jobId));
+        }
+        checkPriv(jobInfo);
+        long jobId = analyzeJobStmt.getJobId();
+        AnalyzeDeletionLog analyzeDeletionLog = new AnalyzeDeletionLog(jobId);
+        Env.getCurrentEnv().getEditLog().logDeleteAnalysisJob(analyzeDeletionLog);
+        replayDeleteAnalysisJob(analyzeDeletionLog);
+        removeAll(findTasks(jobId));
+    }
+
 }
diff --git a/fe/fe-core/src/main/java/org/apache/doris/statistics/BaseAnalysisTask.java b/fe/fe-core/src/main/java/org/apache/doris/statistics/BaseAnalysisTask.java
index b1ccbf68b5..1fc97c10dc 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/statistics/BaseAnalysisTask.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/statistics/BaseAnalysisTask.java
@@ -24,8 +24,8 @@ import org.apache.doris.catalog.PrimitiveType;
 import org.apache.doris.catalog.TableIf;
 import org.apache.doris.datasource.CatalogIf;
 import org.apache.doris.qe.StmtExecutor;
-import org.apache.doris.statistics.AnalysisTaskInfo.AnalysisMethod;
-import org.apache.doris.statistics.AnalysisTaskInfo.AnalysisType;
+import org.apache.doris.statistics.AnalysisInfo.AnalysisMethod;
+import org.apache.doris.statistics.AnalysisInfo.AnalysisType;
 
 import com.google.common.annotations.VisibleForTesting;
 import org.apache.logging.log4j.LogManager;
@@ -87,7 +87,7 @@ public abstract class BaseAnalysisTask {
             + "     ${internalDB}.${columnStatTbl}.part_id IS NOT NULL"
             + "     ) t1, \n";
 
-    protected AnalysisTaskInfo info;
+    protected AnalysisInfo info;
 
     protected CatalogIf catalog;
 
@@ -108,7 +108,7 @@ public abstract class BaseAnalysisTask {
 
     }
 
-    public BaseAnalysisTask(AnalysisTaskInfo info) {
+    public BaseAnalysisTask(AnalysisInfo info) {
         this.info = info;
         init(info);
     }
@@ -122,7 +122,7 @@ public abstract class BaseAnalysisTask {
         unsupportedType.add(PrimitiveType.STRUCT);
     }
 
-    private void init(AnalysisTaskInfo info) {
+    private void init(AnalysisInfo info) {
         initUnsupportedType();
         catalog = Env.getCurrentEnv().getCatalogMgr().getCatalog(info.catalogName);
         if (catalog == null) {
@@ -146,7 +146,7 @@ public abstract class BaseAnalysisTask {
         if (info.externalTableLevelTask) {
             return;
         }
-        if (info.analysisType != null && (info.analysisType.equals(AnalysisType.COLUMN)
+        if (info.analysisType != null && (info.analysisType.equals(AnalysisType.FUNDAMENTALS)
                 || info.analysisType.equals(AnalysisType.HISTOGRAM))) {
             col = tbl.getColumn(info.colName);
             if (col == null) {
diff --git a/fe/fe-core/src/main/java/org/apache/doris/statistics/ColumnStatistic.java b/fe/fe-core/src/main/java/org/apache/doris/statistics/ColumnStatistic.java
index ff218d6f30..46dd8fa4a5 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/statistics/ColumnStatistic.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/statistics/ColumnStatistic.java
@@ -52,14 +52,21 @@ public class ColumnStatistic {
             .setSelectivity(0)
             .build();
 
-    public static final Set<Type> MAX_MIN_UNSUPPORTED_TYPE = new HashSet<>();
+    public static final Set<Type> UNSUPPORTED_TYPE = new HashSet<>();
 
     static {
-        MAX_MIN_UNSUPPORTED_TYPE.add(Type.HLL);
-        MAX_MIN_UNSUPPORTED_TYPE.add(Type.BITMAP);
-        MAX_MIN_UNSUPPORTED_TYPE.add(Type.ARRAY);
-        MAX_MIN_UNSUPPORTED_TYPE.add(Type.STRUCT);
-        MAX_MIN_UNSUPPORTED_TYPE.add(Type.MAP);
+        UNSUPPORTED_TYPE.add(Type.HLL);
+        UNSUPPORTED_TYPE.add(Type.BITMAP);
+        UNSUPPORTED_TYPE.add(Type.ARRAY);
+        UNSUPPORTED_TYPE.add(Type.STRUCT);
+        UNSUPPORTED_TYPE.add(Type.MAP);
+        UNSUPPORTED_TYPE.add(Type.QUANTILE_STATE);
+        UNSUPPORTED_TYPE.add(Type.AGG_STATE);
+        UNSUPPORTED_TYPE.add(Type.JSONB);
+        UNSUPPORTED_TYPE.add(Type.VARIANT);
+        UNSUPPORTED_TYPE.add(Type.TIME);
+        UNSUPPORTED_TYPE.add(Type.TIMEV2);
+        UNSUPPORTED_TYPE.add(Type.LAMBDA_FUNCTION);
     }
 
     public final double count;
diff --git a/fe/fe-core/src/main/java/org/apache/doris/statistics/HMSAnalysisTask.java b/fe/fe-core/src/main/java/org/apache/doris/statistics/HMSAnalysisTask.java
index bb3c073002..b5bee03f0b 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/statistics/HMSAnalysisTask.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/statistics/HMSAnalysisTask.java
@@ -26,7 +26,7 @@ public class HMSAnalysisTask extends BaseAnalysisTask {
 
     protected HMSExternalTable table;
 
-    public HMSAnalysisTask(AnalysisTaskInfo info) {
+    public HMSAnalysisTask(AnalysisInfo info) {
         super(info);
         table = (HMSExternalTable) tbl;
     }
diff --git a/fe/fe-core/src/main/java/org/apache/doris/statistics/HistogramTask.java b/fe/fe-core/src/main/java/org/apache/doris/statistics/HistogramTask.java
index e8186fff25..fdadff6c05 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/statistics/HistogramTask.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/statistics/HistogramTask.java
@@ -19,7 +19,7 @@ package org.apache.doris.statistics;
 
 import org.apache.doris.catalog.Env;
 import org.apache.doris.common.FeConstants;
-import org.apache.doris.statistics.AnalysisTaskInfo.AnalysisMethod;
+import org.apache.doris.statistics.AnalysisInfo.AnalysisMethod;
 import org.apache.doris.statistics.util.StatisticsUtil;
 
 import com.google.common.annotations.VisibleForTesting;
@@ -53,7 +53,7 @@ public class HistogramTask extends BaseAnalysisTask {
         super();
     }
 
-    public HistogramTask(AnalysisTaskInfo info) {
+    public HistogramTask(AnalysisInfo info) {
         super(info);
     }
 
diff --git a/fe/fe-core/src/main/java/org/apache/doris/statistics/HiveAnalysisTask.java b/fe/fe-core/src/main/java/org/apache/doris/statistics/HiveAnalysisTask.java
index d9469c0024..0e358857ca 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/statistics/HiveAnalysisTask.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/statistics/HiveAnalysisTask.java
@@ -84,7 +84,7 @@ public class HiveAnalysisTask extends HMSAnalysisTask {
 
     private final boolean isTableLevelTask;
 
-    public HiveAnalysisTask(AnalysisTaskInfo info) {
+    public HiveAnalysisTask(AnalysisInfo info) {
         super(info);
         isTableLevelTask = info.externalTableLevelTask;
     }
diff --git a/fe/fe-core/src/main/java/org/apache/doris/statistics/IcebergAnalysisTask.java b/fe/fe-core/src/main/java/org/apache/doris/statistics/IcebergAnalysisTask.java
index 7246c3e717..105ef758f0 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/statistics/IcebergAnalysisTask.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/statistics/IcebergAnalysisTask.java
@@ -45,7 +45,7 @@ public class IcebergAnalysisTask extends HMSAnalysisTask {
     private long dataSize = 0;
     private long numNulls = 0;
 
-    public IcebergAnalysisTask(AnalysisTaskInfo info) {
+    public IcebergAnalysisTask(AnalysisInfo info) {
         super(info);
     }
 
diff --git a/fe/fe-core/src/main/java/org/apache/doris/statistics/MVAnalysisTask.java b/fe/fe-core/src/main/java/org/apache/doris/statistics/MVAnalysisTask.java
index a3bac1bbc8..701f3109b8 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/statistics/MVAnalysisTask.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/statistics/MVAnalysisTask.java
@@ -62,7 +62,7 @@ public class MVAnalysisTask extends BaseAnalysisTask {
 
     private OlapTable olapTable;
 
-    public MVAnalysisTask(AnalysisTaskInfo info) {
+    public MVAnalysisTask(AnalysisInfo info) {
         super(info);
         init();
     }
diff --git a/fe/fe-core/src/main/java/org/apache/doris/statistics/OlapAnalysisTask.java b/fe/fe-core/src/main/java/org/apache/doris/statistics/OlapAnalysisTask.java
index ec46300dd6..a65553a838 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/statistics/OlapAnalysisTask.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/statistics/OlapAnalysisTask.java
@@ -53,7 +53,7 @@ public class OlapAnalysisTask extends BaseAnalysisTask {
         super();
     }
 
-    public OlapAnalysisTask(AnalysisTaskInfo info) {
+    public OlapAnalysisTask(AnalysisInfo info) {
         super(info);
     }
 
diff --git a/fe/fe-core/src/main/java/org/apache/doris/statistics/StatisticConstants.java b/fe/fe-core/src/main/java/org/apache/doris/statistics/StatisticConstants.java
index 8b358bf74d..93072c750f 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/statistics/StatisticConstants.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/statistics/StatisticConstants.java
@@ -72,4 +72,6 @@ public class StatisticConstants {
      */
     public static final int TABLE_STATS_HEALTH_THRESHOLD = 80;
 
+    public static final int ANALYZE_MANAGER_INTERVAL_IN_SECS = 60;
+
 }
diff --git a/fe/fe-core/src/main/java/org/apache/doris/statistics/StatisticsAutoAnalyzer.java b/fe/fe-core/src/main/java/org/apache/doris/statistics/StatisticsAutoAnalyzer.java
index 5cf291de4b..8128d3a7d3 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/statistics/StatisticsAutoAnalyzer.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/statistics/StatisticsAutoAnalyzer.java
@@ -25,13 +25,11 @@ import org.apache.doris.catalog.TableIf;
 import org.apache.doris.common.Config;
 import org.apache.doris.common.DdlException;
 import org.apache.doris.common.util.MasterDaemon;
-import org.apache.doris.statistics.util.InternalQueryResult.ResultRow;
 import org.apache.doris.statistics.util.StatisticsUtil;
 
 import com.google.common.collect.Maps;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
-import org.apache.thrift.TException;
 
 import java.util.Collection;
 import java.util.HashSet;
@@ -47,7 +45,7 @@ public class StatisticsAutoAnalyzer extends MasterDaemon {
     private static final Logger LOG = LogManager.getLogger(StatisticsAutoAnalyzer.class);
 
     public StatisticsAutoAnalyzer() {
-        super("Automatic Analyzer", TimeUnit.SECONDS.toMillis(Config.auto_check_statistics_in_sec));
+        super("Automatic Analyzer", TimeUnit.MINUTES.toMillis(Config.auto_check_statistics_in_minutes));
     }
 
     @Override
@@ -69,31 +67,23 @@ public class StatisticsAutoAnalyzer extends MasterDaemon {
     }
 
     private void analyzePeriodically() {
-        List<ResultRow> resultRows = StatisticsRepository.fetchPeriodicAnalysisJobs();
-        if (resultRows.isEmpty()) {
-            return;
-        }
         try {
             AnalysisManager analysisManager = Env.getCurrentEnv().getAnalysisManager();
-            List<AnalysisTaskInfo> jobInfos = StatisticsUtil.deserializeToAnalysisJob(resultRows);
-            for (AnalysisTaskInfo jobInfo : jobInfos) {
+            List<AnalysisInfo> jobInfos = analysisManager.findPeriodicJobs();
+            for (AnalysisInfo jobInfo : jobInfos) {
                 analysisManager.createAnalysisJob(jobInfo);
             }
-        } catch (TException | DdlException e) {
+        } catch (DdlException e) {
             LOG.warn("Failed to periodically analyze the statistics." + e);
         }
     }
 
     private void analyzeAutomatically() {
-        List<ResultRow> resultRows = StatisticsRepository.fetchAutomaticAnalysisJobs();
-        if (resultRows.isEmpty()) {
-            return;
-        }
         try {
             AnalysisManager analysisManager = Env.getCurrentEnv().getAnalysisManager();
-            List<AnalysisTaskInfo> jobInfos = StatisticsUtil.deserializeToAnalysisJob(resultRows);
-            for (AnalysisTaskInfo jobInfo : jobInfos) {
-                AnalysisTaskInfo checkedJobInfo = checkAutomaticJobInfo(jobInfo);
+            List<AnalysisInfo> jobInfos = analysisManager.findAutomaticAnalysisJobs();
+            for (AnalysisInfo jobInfo : jobInfos) {
+                AnalysisInfo checkedJobInfo = checkAutomaticJobInfo(jobInfo);
                 if (checkedJobInfo != null) {
                     analysisManager.createAnalysisJob(checkedJobInfo);
                 }
@@ -123,7 +113,7 @@ public class StatisticsAutoAnalyzer extends MasterDaemon {
      * @return new job info after check
      * @throws Throwable failed to check
      */
-    private AnalysisTaskInfo checkAutomaticJobInfo(AnalysisTaskInfo jobInfo) throws Throwable {
+    private AnalysisInfo checkAutomaticJobInfo(AnalysisInfo jobInfo) throws Throwable {
         long lastExecTimeInMs = jobInfo.lastExecTimeInMs;
         TableIf table = StatisticsUtil
                 .findTable(jobInfo.catalogName, jobInfo.dbName, jobInfo.tblName);
@@ -206,7 +196,7 @@ public class StatisticsAutoAnalyzer extends MasterDaemon {
         );
     }
 
-    private AnalysisTaskInfo getAnalysisJobInfo(AnalysisTaskInfo jobInfo, TableIf table,
+    private AnalysisInfo getAnalysisJobInfo(AnalysisInfo jobInfo, TableIf table,
             Set<String> needRunPartitions) {
         Map<String, Set<String>> newColToPartitions = Maps.newHashMap();
         Map<String, Set<String>> colToPartitions = jobInfo.colToPartitions;
@@ -216,7 +206,7 @@ public class StatisticsAutoAnalyzer extends MasterDaemon {
                 newColToPartitions.put(colName, needRunPartitions);
             }
         });
-        return new AnalysisTaskInfoBuilder(jobInfo)
+        return new AnalysisInfoBuilder(jobInfo)
                 .setColToPartitions(newColToPartitions).build();
     }
 }
diff --git a/fe/fe-core/src/main/java/org/apache/doris/statistics/StatisticsCleaner.java b/fe/fe-core/src/main/java/org/apache/doris/statistics/StatisticsCleaner.java
index b23310b240..d68eb39dad 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/statistics/StatisticsCleaner.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/statistics/StatisticsCleaner.java
@@ -88,7 +88,6 @@ public class StatisticsCleaner extends MasterDaemon {
         }
         clearStats(colStatsTbl);
         clearStats(histStatsTbl);
-        clearJobTbl();
     }
 
     private void clearStats(OlapTable statsTbl) {
@@ -101,11 +100,6 @@ public class StatisticsCleaner extends MasterDaemon {
         } while (!expiredStats.isEmpty());
     }
 
-    private void clearJobTbl() {
-        clearJobTbl(StatisticsRepository::fetchExpiredAutoJob, true);
-        clearJobTbl(StatisticsRepository::fetchExpiredOnceJobs, false);
-    }
-
     private void clearJobTbl(BiFunction<Integer, Long, List<ResultRow>> fetchFunc, boolean taskOnly) {
         List<String> jobIds = null;
         long offset = 0;
diff --git a/fe/fe-core/src/main/java/org/apache/doris/statistics/StatisticsRepository.java b/fe/fe-core/src/main/java/org/apache/doris/statistics/StatisticsRepository.java
index ae16445942..63e5d1b634 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/statistics/StatisticsRepository.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/statistics/StatisticsRepository.java
@@ -45,7 +45,6 @@ import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.StringJoiner;
-import java.util.concurrent.TimeUnit;
 import java.util.stream.Collectors;
 
 /**
@@ -64,9 +63,6 @@ public class StatisticsRepository {
     private static final String FULL_QUALIFIED_COLUMN_HISTOGRAM_NAME = FULL_QUALIFIED_DB_NAME + "."
             + "`" + StatisticConstants.HISTOGRAM_TBL_NAME + "`";
 
-    private static final String FULL_QUALIFIED_ANALYSIS_JOB_TABLE_NAME = FULL_QUALIFIED_DB_NAME + "."
-            + "`" + StatisticConstants.ANALYSIS_JOB_TABLE + "`";
-
     private static final String FETCH_COLUMN_STATISTIC_TEMPLATE = "SELECT * FROM "
             + FULL_QUALIFIED_COLUMN_STATISTICS_NAME
             + " WHERE `id` = '${id}'";
@@ -79,13 +75,6 @@ public class StatisticsRepository {
             + FULL_QUALIFIED_COLUMN_HISTOGRAM_NAME
             + " WHERE `id` = '${id}'";
 
-    private static final String PERSIST_ANALYSIS_TASK_SQL_TEMPLATE =
-            "INSERT INTO " + FULL_QUALIFIED_ANALYSIS_JOB_TABLE_NAME
-                    + " VALUES(${jobId}, ${taskId}, '${catalogName}', '${dbName}', '${tblName}', "
-                    + "'${colName}', '${indexId}', '${colPartitions}', '${jobType}', '${analysisType}', "
-                    + "'${analysisMode}', '${analysisMethod}', '${scheduleType}', '${state}', ${samplePercent}, "
-                    + "${sampleRows}, ${maxBucketNum}, ${periodTimeInMs}, ${lastExecTimeInMs}, '${message}')";
-
     private static final String INSERT_INTO_COLUMN_STATISTICS = "INSERT INTO "
             + FULL_QUALIFIED_COLUMN_STATISTICS_NAME + " VALUES('${id}', ${catalogId}, ${dbId}, ${tblId}, '${idxId}',"
             + "'${colId}', ${partId}, ${count}, ${ndv}, ${nullCount}, '${min}', '${max}', ${dataSize}, NOW())";
@@ -93,22 +82,6 @@ public class StatisticsRepository {
     private static final String DROP_TABLE_STATISTICS_TEMPLATE = "DELETE FROM " + FeConstants.INTERNAL_DB_NAME
             + "." + "${tblName}" + " WHERE ${condition}";
 
-    private static final String FIND_EXPIRED_ONCE_JOBS = "SELECT job_id FROM "
-            + FULL_QUALIFIED_ANALYSIS_JOB_TABLE_NAME
-            + " WHERE task_id = -1 AND ${now} - last_exec_time_in_ms  > "
-            + TimeUnit.HOURS.toMillis(StatisticConstants.ANALYSIS_JOB_INFO_EXPIRATION_TIME_IN_DAYS)
-            + " AND schedule_type = 'ONCE'"
-            + " ORDER BY last_exec_time_in_ms"
-            + " LIMIT ${limit} OFFSET ${offset}";
-
-    private static final String FIND_EXPIRED_AUTO_JOBS = "SELECT DISTINCT(job_id) FROM (SELECT job_id FROM "
-            + FULL_QUALIFIED_ANALYSIS_JOB_TABLE_NAME
-            + "WHERE task_id != -1 AND ${now} - last_exec_time_in_ms  > "
-            + TimeUnit.HOURS.toMillis(StatisticConstants.ANALYSIS_JOB_INFO_EXPIRATION_TIME_IN_DAYS)
-            + " AND schedule_type = 'PERIOD' OR schedule_type = 'AUTOMATIC'"
-            + " ORDER BY last_exec_time_in_ms"
-            + " LIMIT ${limit} OFFSET ${offset}) t";
-
     private static final String FETCH_RECENT_STATS_UPDATED_COL =
             "SELECT * FROM "
                     + FeConstants.INTERNAL_DB_NAME + "." + StatisticConstants.STATISTIC_TBL_NAME
@@ -127,20 +100,6 @@ public class StatisticsRepository {
             + " WHERE tbl_id = ${tblId}"
             + " AND part_id IS NOT NULL";
 
-    private static final String FETCH_PERIODIC_ANALYSIS_JOB_TEMPLATE = "SELECT * FROM "
-            + FULL_QUALIFIED_ANALYSIS_JOB_TABLE_NAME
-            + " WHERE task_id = -1 "
-            + " AND schedule_type = 'PERIOD' "
-            + " AND state = 'FINISHED' "
-            + " AND (${currentTimeStamp} - last_exec_time_in_ms >= period_time_in_ms)";
-
-    private static final String FETCH_AUTOMATIC_ANALYSIS_JOB_SQL = "SELECT * FROM "
-            + FULL_QUALIFIED_ANALYSIS_JOB_TABLE_NAME
-            + " WHERE task_id = -1 "
-            + " AND schedule_type = 'AUTOMATIC' "
-            + " AND state = 'FINISHED' "
-            + " AND last_exec_time_in_ms > 0";
-
     private static final String PERSIST_TABLE_STATS_TEMPLATE = "INSERT INTO "
             + FeConstants.INTERNAL_DB_NAME + "." + StatisticConstants.ANALYSIS_TBL_NAME
             + " VALUES('${id}', ${catalogId}, ${dbId}, ${tblId}, ${indexId}, ${partId}, ${rowCount},"
@@ -270,32 +229,6 @@ public class StatisticsRepository {
         }
     }
 
-    public static void persistAnalysisTask(AnalysisTaskInfo analysisTaskInfo) throws Exception {
-        Map<String, String> params = new HashMap<>();
-        params.put("jobId", String.valueOf(analysisTaskInfo.jobId));
-        params.put("taskId", String.valueOf(analysisTaskInfo.taskId));
-        params.put("catalogName", analysisTaskInfo.catalogName);
-        params.put("dbName", analysisTaskInfo.dbName);
-        params.put("tblName", analysisTaskInfo.tblName);
-        params.put("colName", analysisTaskInfo.colName == null ? "" : analysisTaskInfo.colName);
-        params.put("indexId", analysisTaskInfo.indexId == null ? "-1" : String.valueOf(analysisTaskInfo.indexId));
-        params.put("colPartitions", analysisTaskInfo.getColToPartitionStr());
-        params.put("jobType", analysisTaskInfo.jobType.toString());
-        params.put("analysisType", analysisTaskInfo.analysisType.toString());
-        params.put("analysisMode", analysisTaskInfo.analysisMode.toString());
-        params.put("analysisMethod", analysisTaskInfo.analysisMethod.toString());
-        params.put("scheduleType", analysisTaskInfo.scheduleType.toString());
-        params.put("state", analysisTaskInfo.state.toString());
-        params.put("samplePercent", String.valueOf(analysisTaskInfo.samplePercent));
-        params.put("sampleRows", String.valueOf(analysisTaskInfo.sampleRows));
-        params.put("maxBucketNum", String.valueOf(analysisTaskInfo.maxBucketNum));
-        params.put("periodTimeInMs", String.valueOf(analysisTaskInfo.periodTimeInMs));
-        params.put("lastExecTimeInMs", String.valueOf(analysisTaskInfo.lastExecTimeInMs));
-        params.put("message", "");
-        StatisticsUtil.execUpdate(
-                new StringSubstitutor(params).replace(PERSIST_ANALYSIS_TASK_SQL_TEMPLATE));
-    }
-
     public static void persistTableStats(Map<String, String> params) throws Exception {
         StatisticsUtil.execUpdate(PERSIST_TABLE_STATS_TEMPLATE, params);
     }
@@ -390,22 +323,6 @@ public class StatisticsRepository {
         return StatisticsUtil.execStatisticQuery(new StringSubstitutor(params).replace(FETCH_STATS_FULL_NAME));
     }
 
-    public static List<ResultRow> fetchExpiredOnceJobs(long limit, long offset) {
-        Map<String, String> params = new HashMap<>();
-        params.put("limit", String.valueOf(limit));
-        params.put("offset", String.valueOf(offset));
-        params.put("now", String.valueOf(System.currentTimeMillis()));
-        return StatisticsUtil.execStatisticQuery(new StringSubstitutor(params).replace(FIND_EXPIRED_ONCE_JOBS));
-    }
-
-    public static List<ResultRow> fetchExpiredAutoJob(long limit, long offset) {
-        Map<String, String> params = new HashMap<>();
-        params.put("limit", String.valueOf(limit));
-        params.put("offset", String.valueOf(offset));
-        params.put("now", String.valueOf(System.currentTimeMillis()));
-        return StatisticsUtil.execStatisticQuery(new StringSubstitutor(params).replace(FIND_EXPIRED_AUTO_JOBS));
-    }
-
     public static Map<String, Set<Long>> fetchColAndPartsForStats(long tblId) {
         Map<String, String> params = Maps.newHashMap();
         params.put("tblId", String.valueOf(tblId));
@@ -419,39 +336,20 @@ public class StatisticsRepository {
             try {
                 String colId = row.getColumnValue("col_id");
                 String partId = row.getColumnValue("part_id");
+                if (partId == null) {
+                    return;
+                }
                 columnToPartitions.computeIfAbsent(colId,
                         k -> new HashSet<>()).add(Long.valueOf(partId));
             } catch (NumberFormatException | DdlException e) {
-                LOG.warn("Failed to obtain the column and partition for statistics.{}",
-                        e.getMessage());
+                LOG.warn("Failed to obtain the column and partition for statistics.",
+                        e);
             }
         });
 
         return columnToPartitions;
     }
 
-    public static List<ResultRow> fetchPeriodicAnalysisJobs() {
-        ImmutableMap<String, String> params = ImmutableMap
-                .of("currentTimeStamp", String.valueOf(System.currentTimeMillis()));
-        try {
-            StringSubstitutor stringSubstitutor = new StringSubstitutor(params);
-            String sql = stringSubstitutor.replace(FETCH_PERIODIC_ANALYSIS_JOB_TEMPLATE);
-            return StatisticsUtil.execStatisticQuery(sql);
-        } catch (Exception e) {
-            LOG.warn("Failed to update status", e);
-            return Collections.emptyList();
-        }
-    }
-
-    public static List<ResultRow> fetchAutomaticAnalysisJobs() {
-        try {
-            return StatisticsUtil.execStatisticQuery(FETCH_AUTOMATIC_ANALYSIS_JOB_SQL);
-        } catch (Exception e) {
-            LOG.warn("Failed to update status", e);
-            return Collections.emptyList();
-        }
-    }
-
     public static TableStatistic fetchTableLevelStats(long tblId) throws DdlException {
         ImmutableMap<String, String> params = ImmutableMap
                 .of("tblId", String.valueOf(tblId));
diff --git a/fe/fe-core/src/main/java/org/apache/doris/statistics/util/StatisticsUtil.java b/fe/fe-core/src/main/java/org/apache/doris/statistics/util/StatisticsUtil.java
index f5a7485f2f..fed9d26165 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/statistics/util/StatisticsUtil.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/statistics/util/StatisticsUtil.java
@@ -49,7 +49,7 @@ import org.apache.doris.qe.AutoCloseConnectContext;
 import org.apache.doris.qe.ConnectContext;
 import org.apache.doris.qe.SessionVariable;
 import org.apache.doris.qe.StmtExecutor;
-import org.apache.doris.statistics.AnalysisTaskInfo;
+import org.apache.doris.statistics.AnalysisInfo;
 import org.apache.doris.statistics.ColumnStatistic;
 import org.apache.doris.statistics.Histogram;
 import org.apache.doris.statistics.StatisticConstants;
@@ -114,13 +114,13 @@ public class StatisticsUtil {
         }
     }
 
-    public static List<AnalysisTaskInfo> deserializeToAnalysisJob(List<ResultRow> resultBatches)
+    public static List<AnalysisInfo> deserializeToAnalysisJob(List<ResultRow> resultBatches)
             throws TException {
         if (CollectionUtils.isEmpty(resultBatches)) {
             return Collections.emptyList();
         }
         return resultBatches.stream()
-                .map(AnalysisTaskInfo::fromResultRow)
+                .map(AnalysisInfo::fromResultRow)
                 .collect(Collectors.toList());
     }
 
@@ -202,6 +202,7 @@ public class StatisticsUtil {
                 return new DateLiteral(columnValue, type);
             case CHAR:
             case VARCHAR:
+            case STRING:
                 return new StringLiteral(columnValue);
             case HLL:
             case BITMAP:
@@ -316,10 +317,14 @@ public class StatisticsUtil {
      * Throw RuntimeException if table not exists.
      */
     @SuppressWarnings({"unchecked", "rawtypes"})
-    public static TableIf findTable(String catalogName, String dbName, String tblName) throws Throwable {
-        DatabaseIf db = findDatabase(catalogName, dbName);
-        return db.getTableOrException(tblName,
-                t -> new RuntimeException("Table: " + t + " not exists"));
+    public static TableIf findTable(String catalogName, String dbName, String tblName) {
+        try {
+            DatabaseIf db = findDatabase(catalogName, dbName);
+            return db.getTableOrException(tblName,
+                    t -> new RuntimeException("Table: " + t + " not exists"));
+        } catch (Throwable t) {
+            throw new RuntimeException("Table: `" + catalogName + "." + dbName + "." + tblName + "` not exists");
+        }
     }
 
     /**
@@ -363,9 +368,6 @@ public class StatisticsUtil {
                             .findTable(InternalCatalog.INTERNAL_CATALOG_NAME,
                                     dbName,
                                     StatisticConstants.HISTOGRAM_TBL_NAME));
-            statsTbls.add((OlapTable) StatisticsUtil.findTable(InternalCatalog.INTERNAL_CATALOG_NAME,
-                    dbName,
-                    StatisticConstants.ANALYSIS_JOB_TABLE));
         } catch (Throwable t) {
             return false;
         }
diff --git a/fe/fe-core/src/test/java/org/apache/doris/statistics/AnalysisJobTest.java b/fe/fe-core/src/test/java/org/apache/doris/statistics/AnalysisJobTest.java
index 5e21efb47c..e8984cd209 100644
--- a/fe/fe-core/src/test/java/org/apache/doris/statistics/AnalysisJobTest.java
+++ b/fe/fe-core/src/test/java/org/apache/doris/statistics/AnalysisJobTest.java
@@ -17,16 +17,15 @@
 
 package org.apache.doris.statistics;
 
-import org.apache.doris.catalog.Env;
 import org.apache.doris.catalog.InternalSchemaInitializer;
 import org.apache.doris.common.FeConstants;
 import org.apache.doris.qe.AutoCloseConnectContext;
 import org.apache.doris.qe.ConnectContext;
 import org.apache.doris.qe.StmtExecutor;
-import org.apache.doris.statistics.AnalysisTaskInfo.AnalysisMethod;
-import org.apache.doris.statistics.AnalysisTaskInfo.AnalysisMode;
-import org.apache.doris.statistics.AnalysisTaskInfo.AnalysisType;
-import org.apache.doris.statistics.AnalysisTaskInfo.JobType;
+import org.apache.doris.statistics.AnalysisInfo.AnalysisMethod;
+import org.apache.doris.statistics.AnalysisInfo.AnalysisMode;
+import org.apache.doris.statistics.AnalysisInfo.AnalysisType;
+import org.apache.doris.statistics.AnalysisInfo.JobType;
 import org.apache.doris.statistics.util.StatisticsUtil;
 import org.apache.doris.utframe.TestWithFeService;
 
@@ -54,8 +53,6 @@ public class AnalysisJobTest extends TestWithFeService {
                     + "DISTRIBUTED BY HASH(col3)\n" + "BUCKETS 1\n"
                     + "PROPERTIES(\n" + "    \"replication_num\"=\"1\"\n"
                     + ");");
-            InternalSchemaInitializer storageInitializer = new InternalSchemaInitializer();
-            Env.getCurrentEnv().createTable(storageInitializer.buildAnalysisJobTblStmt());
         } catch (Exception e) {
             throw new RuntimeException(e);
         }
@@ -116,12 +113,12 @@ public class AnalysisJobTest extends TestWithFeService {
         };
         HashMap<String, Set<String>> colToPartitions = Maps.newHashMap();
         colToPartitions.put("col1", Collections.singleton("t1"));
-        AnalysisTaskInfo analysisJobInfo = new AnalysisTaskInfoBuilder().setJobId(0).setTaskId(0)
+        AnalysisInfo analysisJobInfo = new AnalysisInfoBuilder().setJobId(0).setTaskId(0)
                 .setCatalogName("internal").setDbName("default_cluster:analysis_job_test").setTblName("t1")
                 .setColName("col1").setJobType(JobType.MANUAL)
                 .setAnalysisMode(AnalysisMode.FULL)
                 .setAnalysisMethod(AnalysisMethod.FULL)
-                .setAnalysisType(AnalysisType.COLUMN)
+                .setAnalysisType(AnalysisType.FUNDAMENTALS)
                 .setColToPartitions(colToPartitions)
                 .build();
         new OlapAnalysisTask(analysisJobInfo).execute();
diff --git a/fe/fe-core/src/test/java/org/apache/doris/statistics/AnalysisTaskExecutorTest.java b/fe/fe-core/src/test/java/org/apache/doris/statistics/AnalysisTaskExecutorTest.java
index 0974b438fe..c2b355067d 100644
--- a/fe/fe-core/src/test/java/org/apache/doris/statistics/AnalysisTaskExecutorTest.java
+++ b/fe/fe-core/src/test/java/org/apache/doris/statistics/AnalysisTaskExecutorTest.java
@@ -17,13 +17,12 @@
 
 package org.apache.doris.statistics;
 
-import org.apache.doris.catalog.Env;
 import org.apache.doris.catalog.InternalSchemaInitializer;
 import org.apache.doris.common.jmockit.Deencapsulation;
-import org.apache.doris.statistics.AnalysisTaskInfo.AnalysisMethod;
-import org.apache.doris.statistics.AnalysisTaskInfo.AnalysisMode;
-import org.apache.doris.statistics.AnalysisTaskInfo.AnalysisType;
-import org.apache.doris.statistics.AnalysisTaskInfo.JobType;
+import org.apache.doris.statistics.AnalysisInfo.AnalysisMethod;
+import org.apache.doris.statistics.AnalysisInfo.AnalysisMode;
+import org.apache.doris.statistics.AnalysisInfo.AnalysisType;
+import org.apache.doris.statistics.AnalysisInfo.JobType;
 import org.apache.doris.statistics.util.BlockingCounter;
 import org.apache.doris.utframe.TestWithFeService;
 
@@ -56,8 +55,6 @@ public class AnalysisTaskExecutorTest extends TestWithFeService {
                     + "DISTRIBUTED BY HASH(col3)\n" + "BUCKETS 1\n"
                     + "PROPERTIES(\n" + "    \"replication_num\"=\"1\"\n"
                     + ");");
-            InternalSchemaInitializer storageInitializer = new InternalSchemaInitializer();
-            Env.getCurrentEnv().createTable(storageInitializer.buildAnalysisJobTblStmt());
         } catch (Exception e) {
             throw new RuntimeException(e);
         }
@@ -65,12 +62,12 @@ public class AnalysisTaskExecutorTest extends TestWithFeService {
 
     @Test
     public void testExpiredJobCancellation() throws Exception {
-        AnalysisTaskInfo analysisJobInfo = new AnalysisTaskInfoBuilder().setJobId(0).setTaskId(0)
+        AnalysisInfo analysisJobInfo = new AnalysisInfoBuilder().setJobId(0).setTaskId(0)
                 .setCatalogName("internal").setDbName("default_cluster:analysis_job_test").setTblName("t1")
                 .setColName("col1").setJobType(JobType.MANUAL)
                 .setAnalysisMode(AnalysisMode.FULL)
                 .setAnalysisMethod(AnalysisMethod.FULL)
-                .setAnalysisType(AnalysisType.COLUMN)
+                .setAnalysisType(AnalysisType.FUNDAMENTALS)
                 .build();
         OlapAnalysisTask analysisJob = new OlapAnalysisTask(analysisJobInfo);
 
@@ -100,15 +97,15 @@ public class AnalysisTaskExecutorTest extends TestWithFeService {
         AnalysisTaskExecutor analysisTaskExecutor = new AnalysisTaskExecutor(analysisTaskScheduler);
         HashMap<String, Set<String>> colToPartitions = Maps.newHashMap();
         colToPartitions.put("col1", Collections.singleton("t1"));
-        AnalysisTaskInfo analysisTaskInfo = new AnalysisTaskInfoBuilder().setJobId(0).setTaskId(0)
+        AnalysisInfo analysisInfo = new AnalysisInfoBuilder().setJobId(0).setTaskId(0)
                 .setCatalogName("internal").setDbName("default_cluster:analysis_job_test").setTblName("t1")
                 .setColName("col1").setJobType(JobType.MANUAL)
                 .setAnalysisMode(AnalysisMode.FULL)
                 .setAnalysisMethod(AnalysisMethod.FULL)
-                .setAnalysisType(AnalysisType.COLUMN)
+                .setAnalysisType(AnalysisType.FUNDAMENTALS)
                 .setColToPartitions(colToPartitions)
                 .build();
-        OlapAnalysisTask task = new OlapAnalysisTask(analysisTaskInfo);
+        OlapAnalysisTask task = new OlapAnalysisTask(analysisInfo);
         new MockUp<AnalysisTaskScheduler>() {
             @Mock
             public synchronized BaseAnalysisTask getPendingTasks() {
@@ -117,7 +114,7 @@ public class AnalysisTaskExecutorTest extends TestWithFeService {
         };
         new MockUp<AnalysisManager>() {
             @Mock
-            public void updateTaskStatus(AnalysisTaskInfo info, AnalysisState jobState, String message, long time) {}
+            public void updateTaskStatus(AnalysisInfo info, AnalysisState jobState, String message, long time) {}
         };
         new Expectations() {
             {
diff --git a/fe/fe-core/src/test/java/org/apache/doris/statistics/HistogramTaskTest.java b/fe/fe-core/src/test/java/org/apache/doris/statistics/HistogramTaskTest.java
index c81c16ad60..0c6b507b13 100644
--- a/fe/fe-core/src/test/java/org/apache/doris/statistics/HistogramTaskTest.java
+++ b/fe/fe-core/src/test/java/org/apache/doris/statistics/HistogramTaskTest.java
@@ -21,10 +21,10 @@ import org.apache.doris.catalog.Env;
 import org.apache.doris.common.FeConstants;
 import org.apache.doris.common.jmockit.Deencapsulation;
 import org.apache.doris.qe.StmtExecutor;
-import org.apache.doris.statistics.AnalysisTaskInfo.AnalysisMethod;
-import org.apache.doris.statistics.AnalysisTaskInfo.AnalysisMode;
-import org.apache.doris.statistics.AnalysisTaskInfo.AnalysisType;
-import org.apache.doris.statistics.AnalysisTaskInfo.JobType;
+import org.apache.doris.statistics.AnalysisInfo.AnalysisMethod;
+import org.apache.doris.statistics.AnalysisInfo.AnalysisMode;
+import org.apache.doris.statistics.AnalysisInfo.AnalysisType;
+import org.apache.doris.statistics.AnalysisInfo.JobType;
 import org.apache.doris.system.SystemInfoService;
 import org.apache.doris.utframe.TestWithFeService;
 
@@ -32,7 +32,6 @@ import mockit.Expectations;
 import mockit.Mock;
 import mockit.MockUp;
 import mockit.Mocked;
-import mockit.Tested;
 import org.junit.FixMethodOrder;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Test;
@@ -71,14 +70,12 @@ public class HistogramTaskTest extends TestWithFeService {
         FeConstants.runningUnitTest = true;
     }
 
-    @Tested
-
     @Test
     public void test1TaskCreation() throws Exception {
 
         AnalysisManager analysisManager = Env.getCurrentEnv().getAnalysisManager();
         StmtExecutor executor = getSqlStmtExecutor(
-                "ANALYZE TABLE t1(col1) UPDATE HISTOGRAM");
+                "ANALYZE TABLE t1(col1) WITH HISTOGRAM");
         Assertions.assertNotNull(executor);
 
         ConcurrentMap<Long, Map<Long, BaseAnalysisTask>> taskMap =
@@ -101,7 +98,7 @@ public class HistogramTaskTest extends TestWithFeService {
     @Test
     public void test2TaskExecution() throws Exception {
         AnalysisTaskExecutor analysisTaskExecutor = new AnalysisTaskExecutor(analysisTaskScheduler);
-        AnalysisTaskInfo analysisTaskInfo = new AnalysisTaskInfoBuilder()
+        AnalysisInfo analysisInfo = new AnalysisInfoBuilder()
                 .setJobId(0).setTaskId(0).setCatalogName("internal")
                 .setDbName(SystemInfoService.DEFAULT_CLUSTER + ":" + "histogram_task_test").setTblName("t1")
                 .setColName("col1").setJobType(JobType.MANUAL)
@@ -109,7 +106,7 @@ public class HistogramTaskTest extends TestWithFeService {
                 .setAnalysisMethod(AnalysisMethod.FULL)
                 .setAnalysisType(AnalysisType.HISTOGRAM)
                 .build();
-        HistogramTask task = new HistogramTask(analysisTaskInfo);
+        HistogramTask task = new HistogramTask(analysisInfo);
 
         new MockUp<AnalysisTaskScheduler>() {
             @Mock
@@ -119,7 +116,7 @@ public class HistogramTaskTest extends TestWithFeService {
         };
         new MockUp<AnalysisManager>() {
             @Mock
-            public void updateTaskStatus(AnalysisTaskInfo info, AnalysisState jobState, String message, long time) {}
+            public void updateTaskStatus(AnalysisInfo info, AnalysisState jobState, String message, long time) {}
         };
         new Expectations() {
             {
diff --git a/tools/tpch-tools/conf/doris-cluster.conf b/tools/tpch-tools/conf/doris-cluster.conf
index 9417bcb9e0..21fe5c09ff 100644
--- a/tools/tpch-tools/conf/doris-cluster.conf
+++ b/tools/tpch-tools/conf/doris-cluster.conf
@@ -16,7 +16,7 @@
 # under the License.
 
 # Any of FE host
-export FE_HOST='127.0.0.1'
+export FE_HOST='172.16.1.0'
 # http_port in fe.conf
 export FE_HTTP_PORT=8030
 # query_port in fe.conf
@@ -26,4 +26,4 @@ export USER='root'
 # Doris password
 export PASSWORD=''
 # The database where TPC-H tables located
-export DB='tpch'
+export DB='tpch1G'


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@doris.apache.org
For additional commands, e-mail: commits-help@doris.apache.org