diff --git a/src/datanode/src/instance/sql.rs b/src/datanode/src/instance/sql.rs
index cf1a461940fb..40cfd191c10e 100644
--- a/src/datanode/src/instance/sql.rs
+++ b/src/datanode/src/instance/sql.rs
@@ -165,7 +165,7 @@ impl Instance {
         promql: &PromQuery,
         query_ctx: QueryContextRef,
     ) -> Result<Output> {
-        let _timer = timer!(metrics::METRIC_HANDLE_PROMQL_ELAPSED);
+        let _timer = timer!(metrics::HANDLE_PROMQL_ELAPSED);
 
         let stmt = QueryLanguageParser::parse_promql(promql).context(ExecuteSqlSnafu)?;
 
diff --git a/src/datanode/src/metrics.rs b/src/datanode/src/metrics.rs
index 75da00c8eb4f..755b84a40d95 100644
--- a/src/datanode/src/metrics.rs
+++ b/src/datanode/src/metrics.rs
@@ -14,5 +14,5 @@
 
 //! datanode metrics
 
-pub const METRIC_HANDLE_SQL_ELAPSED: &str = "datanode.handle_sql_elapsed";
-pub const METRIC_HANDLE_PROMQL_ELAPSED: &str = "datanode.handle_promql_elapsed";
+pub const HANDLE_SQL_ELAPSED: &str = "datanode.handle_sql_elapsed";
+pub const HANDLE_PROMQL_ELAPSED: &str = "datanode.handle_promql_elapsed";
diff --git a/src/frontend/src/instance/distributed.rs b/src/frontend/src/instance/distributed.rs
index 4b924593389f..9e62f7fff4da 100644
--- a/src/frontend/src/instance/distributed.rs
+++ b/src/frontend/src/instance/distributed.rs
@@ -93,6 +93,7 @@ impl DistInstance {
         create_table: &mut CreateTableExpr,
         partitions: Option<Partitions>,
     ) -> Result<TableRef> {
+        let _timer = common_telemetry::timer!(crate::metrics::DIST_CREATE_TABLE);
         let table_name = TableName::new(
             &create_table.catalog_name,
             &create_table.schema_name,
@@ -189,6 +190,7 @@ impl DistInstance {
                 create_table, datanode, create_expr_for_region.region_ids,
             );
 
+            let _timer = common_telemetry::timer!(crate::metrics::DIST_CREATE_TABLE_IN_DATANODE);
             client
                 .create(create_expr_for_region)
                 .await
@@ -460,6 +462,7 @@ impl DistInstance {
         partitions: Option<Partitions>,
         table_info: &RawTableInfo,
     ) -> Result<RouteResponse> {
+        let _timer = common_telemetry::timer!(crate::metrics::DIST_CREATE_TABLE_IN_META);
         let mut catalog_name = create_table.catalog_name.clone();
         if catalog_name.is_empty() {
             catalog_name = DEFAULT_CATALOG_NAME.to_string();
diff --git a/src/frontend/src/lib.rs b/src/frontend/src/lib.rs
index e30f7ddc976f..51bc340a6500 100644
--- a/src/frontend/src/lib.rs
+++ b/src/frontend/src/lib.rs
@@ -24,6 +24,7 @@ pub mod grpc;
 pub mod influxdb;
 pub mod instance;
 pub(crate) mod metric;
+mod metrics;
 pub mod mysql;
 pub mod opentsdb;
 pub mod postgres;
diff --git a/src/frontend/src/metrics.rs b/src/frontend/src/metrics.rs
new file mode 100644
index 000000000000..968d9b1b3c2c
--- /dev/null
+++ b/src/frontend/src/metrics.rs
@@ -0,0 +1,22 @@
+// Copyright 2023 Greptime Team
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+//! frontend metrics
+
+/// Metrics for creating table in dist mode.
+pub const DIST_CREATE_TABLE: &str = "frontend.dist.create_table";
+
+pub const DIST_CREATE_TABLE_IN_META: &str = "frontend.dist.create_table.update_meta";
+
+pub const DIST_CREATE_TABLE_IN_DATANODE: &str = "frontend.dist.create_table.invoke_datanode";
diff --git a/src/mito/src/engine.rs b/src/mito/src/engine.rs
index 339a189ad35c..9084df5e7f3e 100644
--- a/src/mito/src/engine.rs
+++ b/src/mito/src/engine.rs
@@ -55,6 +55,7 @@ use crate::error::{
     MissingTimestampIndexSnafu, RegionNotFoundSnafu, Result, TableExistsSnafu,
 };
 use crate::manifest::TableManifest;
+use crate::metrics;
 use crate::table::MitoTable;
 pub const INIT_COLUMN_ID: ColumnId = 0;
 const INIT_TABLE_VERSION: TableVersion = 0;
@@ -95,6 +96,7 @@ impl<S: StorageEngine> TableEngine for MitoEngine<S> {
         ctx: &EngineContext,
         request: CreateTableRequest,
     ) -> TableResult<TableRef> {
+        let _timer = common_telemetry::timer!(metrics::MITO_CREATE_TABLE_ELAPSED);
         self.inner
             .create_table(ctx, request)
             .await
@@ -107,6 +109,7 @@ impl<S: StorageEngine> TableEngine for MitoEngine<S> {
         ctx: &EngineContext,
         request: OpenTableRequest,
     ) -> TableResult<Option<TableRef>> {
+        let _timer = common_telemetry::timer!(metrics::MITO_OPEN_TABLE_ELAPSED);
         self.inner
             .open_table(ctx, request)
             .await
@@ -119,6 +122,7 @@ impl<S: StorageEngine> TableEngine for MitoEngine<S> {
         ctx: &EngineContext,
         req: AlterTableRequest,
     ) -> TableResult<TableRef> {
+        let _timer = common_telemetry::timer!(metrics::MITO_ALTER_TABLE_ELAPSED);
         self.inner
             .alter_table(ctx, req)
             .await
@@ -423,12 +427,14 @@ impl<S: StorageEngine> MitoEngineInner<S> {
                 compaction_time_window: request.table_options.compaction_time_window,
             };
 
-            let region = self
-                .storage_engine
-                .create_region(&StorageEngineContext::default(), region_descriptor, &opts)
-                .await
-                .map_err(BoxedError::new)
-                .context(error::CreateRegionSnafu)?;
+            let region = {
+                let _timer = common_telemetry::timer!(crate::metrics::MITO_CREATE_REGION_ELAPSED);
+                self.storage_engine
+                    .create_region(&StorageEngineContext::default(), region_descriptor, &opts)
+                    .await
+                    .map_err(BoxedError::new)
+                    .context(error::CreateRegionSnafu)?
+            };
             info!(
                 "Mito engine created region: {}, id: {}",
                 region.name(),
diff --git a/src/mito/src/lib.rs b/src/mito/src/lib.rs
index 2a856ce7c96f..9b04fa24907b 100644
--- a/src/mito/src/lib.rs
+++ b/src/mito/src/lib.rs
@@ -16,4 +16,5 @@ pub mod config;
 pub mod engine;
 pub mod error;
 mod manifest;
+mod metrics;
 pub mod table;
diff --git a/src/mito/src/metrics.rs b/src/mito/src/metrics.rs
new file mode 100644
index 000000000000..63137279c4e0
--- /dev/null
+++ b/src/mito/src/metrics.rs
@@ -0,0 +1,27 @@
+// Copyright 2023 Greptime Team
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// ! mito table engine metrics
+
+/// Elapsed time of creating tables
+pub const MITO_CREATE_TABLE_ELAPSED: &str = "datanode.mito.create_table";
+/// Elapsed time of creating single region when creating tables.
+pub const MITO_CREATE_REGION_ELAPSED: &str = "datanode.mito.create_table.create_region";
+/// Elapsed time of updating table manifest when creating tables.
+pub const MITO_CREATE_TABLE_UPDATE_MANIFEST_ELAPSED: &str =
+    "datanode.mito.create_table.update_manifest";
+/// Elapsed time of opening tables
+pub const MITO_OPEN_TABLE_ELAPSED: &str = "datanode.mito.open_table";
+/// Elapsed time of altering tables
+pub const MITO_ALTER_TABLE_ELAPSED: &str = "datanode.mito.alter_table";
diff --git a/src/mito/src/table.rs b/src/mito/src/table.rs
index 917f179d964d..eecb74ac081a 100644
--- a/src/mito/src/table.rs
+++ b/src/mito/src/table.rs
@@ -478,6 +478,8 @@ impl<R: Region> MitoTable<R> {
     ) -> Result<MitoTable<R>> {
         let manifest = TableManifest::create(&table_manifest_dir(table_dir), object_store);
 
+        let _timer =
+            common_telemetry::timer!(crate::metrics::MITO_CREATE_TABLE_UPDATE_MANIFEST_ELAPSED);
         // TODO(dennis): save manifest version into catalog?
         let _manifest_version = manifest
             .update(TableMetaActionList::with_action(TableMetaAction::Change(
diff --git a/src/storage/src/lib.rs b/src/storage/src/lib.rs
index 0a42d66f32c0..9be0890bf485 100644
--- a/src/storage/src/lib.rs
+++ b/src/storage/src/lib.rs
@@ -41,6 +41,7 @@ pub mod write_batch;
 
 pub use engine::EngineImpl;
 mod file_purger;
+mod metrics;
 
 pub use sst::parquet::ParquetWriter;
 pub use sst::Source;
diff --git a/src/storage/src/metrics.rs b/src/storage/src/metrics.rs
new file mode 100644
index 000000000000..89347f171172
--- /dev/null
+++ b/src/storage/src/metrics.rs
@@ -0,0 +1,18 @@
+// Copyright 2023 Greptime Team
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+//! storage metrics
+
+/// Elapsed time of updating manifest when creating regions.
+pub const CREATE_REGION_UPDATE_MANIFEST: &str = "storage.create_region.update_manifest";
diff --git a/src/storage/src/region.rs b/src/storage/src/region.rs
index 1b17c6c32f50..8c41d84f55c6 100644
--- a/src/storage/src/region.rs
+++ b/src/storage/src/region.rs
@@ -188,17 +188,21 @@ impl<S: LogStore> RegionImpl<S> {
         store_config: StoreConfig<S>,
     ) -> Result<RegionImpl<S>> {
         let metadata = Arc::new(metadata);
+
         // Try to persist region data to manifest, ensure the new region could be recovered from
         // the manifest.
-        let manifest_version = store_config
-            .manifest
-            .update(RegionMetaActionList::with_action(RegionMetaAction::Change(
-                RegionChange {
-                    metadata: metadata.as_ref().into(),
-                    committed_sequence: INIT_COMMITTED_SEQUENCE,
-                },
-            )))
-            .await?;
+        let manifest_version = {
+            let _timer = common_telemetry::timer!(crate::metrics::CREATE_REGION_UPDATE_MANIFEST);
+            store_config
+                .manifest
+                .update(RegionMetaActionList::with_action(RegionMetaAction::Change(
+                    RegionChange {
+                        metadata: metadata.as_ref().into(),
+                        committed_sequence: INIT_COMMITTED_SEQUENCE,
+                    },
+                )))
+                .await?
+        };
 
         let mutable_memtable = store_config
             .memtable_builder