diff --git a/src/query/db_accessor.hpp b/src/query/db_accessor.hpp
index 71b997d9e..ea958c04e 100644
--- a/src/query/db_accessor.hpp
+++ b/src/query/db_accessor.hpp
@@ -484,7 +484,7 @@ class DbAccessor final {
   }
 
   storage::Result<std::optional<std::pair<std::vector<VertexAccessor>, std::vector<EdgeAccessor>>>> DetachDelete(
-      std::vector<VertexAccessor> nodes, std::vector<EdgeAccessor> edges, bool detach) {
+      std::vector<VertexAccessor> nodes, std::vector<EdgeAccessor> edges, bool detach, bool fast) {
     using ReturnType = std::pair<std::vector<VertexAccessor>, std::vector<EdgeAccessor>>;
 
     std::vector<storage::VertexAccessor *> nodes_impl;
@@ -501,7 +501,7 @@ class DbAccessor final {
       edges_impl.push_back(&edge_accessor.impl_);
     }
 
-    auto res = accessor_->DetachDelete(std::move(nodes_impl), std::move(edges_impl), detach);
+    auto res = accessor_->DetachDelete(std::move(nodes_impl), std::move(edges_impl), detach, fast);
     if (res.HasError()) {
       return res.GetError();
     }
diff --git a/src/query/plan/operator.cpp b/src/query/plan/operator.cpp
index 8dfaac81f..2b08dbba5 100644
--- a/src/query/plan/operator.cpp
+++ b/src/query/plan/operator.cpp
@@ -2790,7 +2790,7 @@ bool Delete::DeleteCursor::Pull(Frame &frame, ExecutionContext &context) {
   }
 
   auto &dba = *context.db_accessor;
-  auto res = dba.DetachDelete(std::move(buffer_.nodes), std::move(buffer_.edges), self_.detach_);
+  auto res = dba.DetachDelete(std::move(buffer_.nodes), std::move(buffer_.edges), self_.detach_, true);
   if (res.HasError()) {
     switch (res.GetError()) {
       case storage::Error::SERIALIZATION_ERROR:
diff --git a/src/storage/v2/disk/storage.cpp b/src/storage/v2/disk/storage.cpp
index adc0e92f4..dc2bfae26 100644
--- a/src/storage/v2/disk/storage.cpp
+++ b/src/storage/v2/disk/storage.cpp
@@ -905,11 +905,11 @@ std::optional<VertexAccessor> DiskStorage::DiskAccessor::FindVertex(storage::Gid
 
 Result<std::optional<std::pair<std::vector<VertexAccessor>, std::vector<EdgeAccessor>>>>
 DiskStorage::DiskAccessor::DetachDelete(std::vector<VertexAccessor *> nodes, std::vector<EdgeAccessor *> edges,
-                                        bool detach) {
+                                        bool detach, bool fast) {
   using ReturnType = std::pair<std::vector<VertexAccessor>, std::vector<EdgeAccessor>>;
 
   /// TODO: (andi) Refactor
-  auto maybe_result = Storage::Accessor::DetachDelete(nodes, edges, detach);
+  auto maybe_result = Storage::Accessor::DetachDelete(nodes, edges, detach, fast);
   if (maybe_result.HasError()) {
     return maybe_result.GetError();
   }
diff --git a/src/storage/v2/disk/storage.hpp b/src/storage/v2/disk/storage.hpp
index 293e102b1..01c327417 100644
--- a/src/storage/v2/disk/storage.hpp
+++ b/src/storage/v2/disk/storage.hpp
@@ -117,7 +117,8 @@ class DiskStorage final : public Storage {
     }
 
     Result<std::optional<std::pair<std::vector<VertexAccessor>, std::vector<EdgeAccessor>>>> DetachDelete(
-        std::vector<VertexAccessor *> nodes, std::vector<EdgeAccessor *> edges, bool detach) override;
+        std::vector<VertexAccessor *> nodes, std::vector<EdgeAccessor *> edges, bool detach,
+        bool fast = false) override;
 
     Result<EdgeAccessor> CreateEdge(VertexAccessor *from, VertexAccessor *to, EdgeTypeId edge_type) override;
 
diff --git a/src/storage/v2/inmemory/storage.cpp b/src/storage/v2/inmemory/storage.cpp
index 0c7bde1a0..12bf56e95 100644
--- a/src/storage/v2/inmemory/storage.cpp
+++ b/src/storage/v2/inmemory/storage.cpp
@@ -242,10 +242,10 @@ std::optional<VertexAccessor> InMemoryStorage::InMemoryAccessor::FindVertex(Gid
 
 Result<std::optional<std::pair<std::vector<VertexAccessor>, std::vector<EdgeAccessor>>>>
 InMemoryStorage::InMemoryAccessor::DetachDelete(std::vector<VertexAccessor *> nodes, std::vector<EdgeAccessor *> edges,
-                                                bool detach) {
+                                                bool detach, bool fast) {
   using ReturnType = std::pair<std::vector<VertexAccessor>, std::vector<EdgeAccessor>>;
 
-  auto maybe_result = Storage::Accessor::DetachDelete(nodes, edges, detach);
+  auto maybe_result = Storage::Accessor::DetachDelete(nodes, edges, detach, fast);
 
   if (maybe_result.HasError()) {
     return maybe_result.GetError();
@@ -276,13 +276,16 @@ InMemoryStorage::InMemoryAccessor::DetachDelete(std::vector<VertexAccessor *> no
     }
   }};
 
-  for (auto const &vertex : deleted_vertices) {
-    transaction_.manyDeltasCache.Invalidate(vertex.vertex_);
-  }
-
-  for (const auto &edge : deleted_edges) {
-    transaction_.manyDeltasCache.Invalidate(edge.from_vertex_, edge.edge_type_, EdgeDirection::OUT);
-    transaction_.manyDeltasCache.Invalidate(edge.to_vertex_, edge.edge_type_, EdgeDirection::IN);
+  if (!fast) {
+    for (auto const &vertex : deleted_vertices) {
+      transaction_.manyDeltasCache.Invalidate(vertex.vertex_);
+    }
+    for (const auto &edge : deleted_edges) {
+      transaction_.manyDeltasCache.Invalidate(edge.from_vertex_, edge.edge_type_, EdgeDirection::OUT);
+      transaction_.manyDeltasCache.Invalidate(edge.to_vertex_, edge.edge_type_, EdgeDirection::IN);
+    }
+  } else {
+    transaction_.manyDeltasCache.Clear();
   }
 
   return maybe_result;
@@ -957,17 +960,21 @@ void InMemoryStorage::InMemoryAccessor::FastDiscardOfDeltas(uint64_t oldest_acti
 
     // 3.b) remove from veretex skip_list
     auto vertex_acc = mem_storage->vertices_.access();
-    for (auto gid : current_deleted_vertices) {
-      vertex_acc.remove(gid);
+    if (!current_deleted_vertices.empty()) {
+      mem_storage->vertices_.clear();
     }
+    // for (auto gid : current_deleted_vertices) {
+    //   vertex_acc.remove(gid);
+    // }
   }
 
   if (!current_deleted_edges.empty()) {
+    mem_storage->edges_.clear();
     // 3.c) remove from edge skip_list
-    auto edge_acc = mem_storage->edges_.access();
-    for (auto gid : current_deleted_edges) {
-      edge_acc.remove(gid);
-    }
+    // auto edge_acc = mem_storage->edges_.access();
+    // for (auto gid : current_deleted_edges) {
+    //   edge_acc.remove(gid);
+    // }
   }
 }
 
@@ -1849,7 +1856,7 @@ bool InMemoryStorage::AppendToWal(const Transaction &transaction, uint64_t final
 
   //////// AF only this calls initialize transaction
   repl_storage_state_.InitializeTransaction(wal_file_->SequenceNumber(), this, db_acc);
-
+  uint64_t i = 0;
   auto append_deltas = [&](auto callback) {
     // Helper lambda that traverses the delta chain on order to find the first
     // delta that should be processed and then appends all discovered deltas.
@@ -1858,6 +1865,7 @@ bool InMemoryStorage::AppendToWal(const Transaction &transaction, uint64_t final
         auto *older = delta->next.load(std::memory_order_acquire);
         if (older == nullptr || older->timestamp->load(std::memory_order_acquire) != current_commit_timestamp) break;
         delta = older;
+        i += 1;
       }
       while (true) {
         if (filter(delta->action)) {
@@ -1867,6 +1875,7 @@ bool InMemoryStorage::AppendToWal(const Transaction &transaction, uint64_t final
         MG_ASSERT(prev.type != PreviousPtr::Type::NULLPTR, "Invalid pointer!");
         if (prev.type != PreviousPtr::Type::DELTA) break;
         delta = prev.delta;
+        i += 1;
       }
     };
 
@@ -1885,115 +1894,125 @@ bool InMemoryStorage::AppendToWal(const Transaction &transaction, uint64_t final
 
     // 1. Process all Vertex deltas and store all operations that create vertices
     // and modify vertex data.
-    for (const auto &delta : transaction.deltas) {
-      auto prev = delta.prev.Get();
-      MG_ASSERT(prev.type != PreviousPtr::Type::NULLPTR, "Invalid pointer!");
-      if (prev.type != PreviousPtr::Type::VERTEX) continue;
-      find_and_apply_deltas(&delta, *prev.vertex, [](auto action) {
-        switch (action) {
-          case Delta::Action::DELETE_DESERIALIZED_OBJECT:
-          case Delta::Action::DELETE_OBJECT:
-          case Delta::Action::SET_PROPERTY:
-          case Delta::Action::ADD_LABEL:
-          case Delta::Action::REMOVE_LABEL:
-            return true;
+    if (transaction.has_vertex_modifying_deltas) {
+      for (const auto &delta : transaction.deltas) {
+        auto prev = delta.prev.Get();
+        MG_ASSERT(prev.type != PreviousPtr::Type::NULLPTR, "Invalid pointer!");
+        if (prev.type != PreviousPtr::Type::VERTEX) continue;
+        find_and_apply_deltas(&delta, *prev.vertex, [](auto action) {
+          switch (action) {
+            case Delta::Action::DELETE_DESERIALIZED_OBJECT:
+            case Delta::Action::DELETE_OBJECT:
+            case Delta::Action::SET_PROPERTY:
+            case Delta::Action::ADD_LABEL:
+            case Delta::Action::REMOVE_LABEL:
+              return true;
 
-          case Delta::Action::RECREATE_OBJECT:
-          case Delta::Action::ADD_IN_EDGE:
-          case Delta::Action::ADD_OUT_EDGE:
-          case Delta::Action::REMOVE_IN_EDGE:
-          case Delta::Action::REMOVE_OUT_EDGE:
-            return false;
-        }
-      });
+            case Delta::Action::RECREATE_OBJECT:
+            case Delta::Action::ADD_IN_EDGE:
+            case Delta::Action::ADD_OUT_EDGE:
+            case Delta::Action::REMOVE_IN_EDGE:
+            case Delta::Action::REMOVE_OUT_EDGE:
+              return false;
+          }
+        });
+      }
     }
     // 2. Process all Vertex deltas and store all operations that create edges.
-    for (const auto &delta : transaction.deltas) {
-      auto prev = delta.prev.Get();
-      MG_ASSERT(prev.type != PreviousPtr::Type::NULLPTR, "Invalid pointer!");
-      if (prev.type != PreviousPtr::Type::VERTEX) continue;
-      find_and_apply_deltas(&delta, *prev.vertex, [](auto action) {
-        switch (action) {
-          case Delta::Action::REMOVE_OUT_EDGE:
-            return true;
-          case Delta::Action::DELETE_DESERIALIZED_OBJECT:
-          case Delta::Action::DELETE_OBJECT:
-          case Delta::Action::RECREATE_OBJECT:
-          case Delta::Action::SET_PROPERTY:
-          case Delta::Action::ADD_LABEL:
-          case Delta::Action::REMOVE_LABEL:
-          case Delta::Action::ADD_IN_EDGE:
-          case Delta::Action::ADD_OUT_EDGE:
-          case Delta::Action::REMOVE_IN_EDGE:
-            return false;
-        }
-      });
+    if (transaction.has_edge_creating_deltas) {
+      for (const auto &delta : transaction.deltas) {
+        auto prev = delta.prev.Get();
+        MG_ASSERT(prev.type != PreviousPtr::Type::NULLPTR, "Invalid pointer!");
+        if (prev.type != PreviousPtr::Type::VERTEX) continue;
+        find_and_apply_deltas(&delta, *prev.vertex, [](auto action) {
+          switch (action) {
+            case Delta::Action::REMOVE_OUT_EDGE:
+              return true;
+            case Delta::Action::DELETE_DESERIALIZED_OBJECT:
+            case Delta::Action::DELETE_OBJECT:
+            case Delta::Action::RECREATE_OBJECT:
+            case Delta::Action::SET_PROPERTY:
+            case Delta::Action::ADD_LABEL:
+            case Delta::Action::REMOVE_LABEL:
+            case Delta::Action::ADD_IN_EDGE:
+            case Delta::Action::ADD_OUT_EDGE:
+            case Delta::Action::REMOVE_IN_EDGE:
+              return false;
+          }
+        });
+      }
     }
     // 3. Process all Edge deltas and store all operations that modify edge data.
-    for (const auto &delta : transaction.deltas) {
-      auto prev = delta.prev.Get();
-      MG_ASSERT(prev.type != PreviousPtr::Type::NULLPTR, "Invalid pointer!");
-      if (prev.type != PreviousPtr::Type::EDGE) continue;
-      find_and_apply_deltas(&delta, *prev.edge, [](auto action) {
-        switch (action) {
-          case Delta::Action::SET_PROPERTY:
-            return true;
-          case Delta::Action::DELETE_DESERIALIZED_OBJECT:
-          case Delta::Action::DELETE_OBJECT:
-          case Delta::Action::RECREATE_OBJECT:
-          case Delta::Action::ADD_LABEL:
-          case Delta::Action::REMOVE_LABEL:
-          case Delta::Action::ADD_IN_EDGE:
-          case Delta::Action::ADD_OUT_EDGE:
-          case Delta::Action::REMOVE_IN_EDGE:
-          case Delta::Action::REMOVE_OUT_EDGE:
-            return false;
-        }
-      });
+    if (transaction.has_edge_modifying_deltas) {
+      for (const auto &delta : transaction.deltas) {
+        auto prev = delta.prev.Get();
+        MG_ASSERT(prev.type != PreviousPtr::Type::NULLPTR, "Invalid pointer!");
+        if (prev.type != PreviousPtr::Type::EDGE) continue;
+        find_and_apply_deltas(&delta, *prev.edge, [](auto action) {
+          switch (action) {
+            case Delta::Action::SET_PROPERTY:
+              return true;
+            case Delta::Action::DELETE_DESERIALIZED_OBJECT:
+            case Delta::Action::DELETE_OBJECT:
+            case Delta::Action::RECREATE_OBJECT:
+            case Delta::Action::ADD_LABEL:
+            case Delta::Action::REMOVE_LABEL:
+            case Delta::Action::ADD_IN_EDGE:
+            case Delta::Action::ADD_OUT_EDGE:
+            case Delta::Action::REMOVE_IN_EDGE:
+            case Delta::Action::REMOVE_OUT_EDGE:
+              return false;
+          }
+        });
+      }
     }
     // 4. Process all Vertex deltas and store all operations that delete edges.
-    for (const auto &delta : transaction.deltas) {
-      auto prev = delta.prev.Get();
-      MG_ASSERT(prev.type != PreviousPtr::Type::NULLPTR, "Invalid pointer!");
-      if (prev.type != PreviousPtr::Type::VERTEX) continue;
-      find_and_apply_deltas(&delta, *prev.vertex, [](auto action) {
-        switch (action) {
-          case Delta::Action::ADD_OUT_EDGE:
-            return true;
-          case Delta::Action::DELETE_DESERIALIZED_OBJECT:
-          case Delta::Action::DELETE_OBJECT:
-          case Delta::Action::RECREATE_OBJECT:
-          case Delta::Action::SET_PROPERTY:
-          case Delta::Action::ADD_LABEL:
-          case Delta::Action::REMOVE_LABEL:
-          case Delta::Action::ADD_IN_EDGE:
-          case Delta::Action::REMOVE_IN_EDGE:
-          case Delta::Action::REMOVE_OUT_EDGE:
-            return false;
-        }
-      });
+    if (transaction.has_edge_deleting_deltas) {
+      for (const auto &delta : transaction.deltas) {
+        auto prev = delta.prev.Get();
+        MG_ASSERT(prev.type != PreviousPtr::Type::NULLPTR, "Invalid pointer!");
+        if (prev.type != PreviousPtr::Type::VERTEX) continue;
+        find_and_apply_deltas(&delta, *prev.vertex, [](auto action) {
+          switch (action) {
+            case Delta::Action::ADD_OUT_EDGE:
+              return true;
+            case Delta::Action::DELETE_DESERIALIZED_OBJECT:
+            case Delta::Action::DELETE_OBJECT:
+            case Delta::Action::RECREATE_OBJECT:
+            case Delta::Action::SET_PROPERTY:
+            case Delta::Action::ADD_LABEL:
+            case Delta::Action::REMOVE_LABEL:
+            case Delta::Action::ADD_IN_EDGE:
+            case Delta::Action::REMOVE_IN_EDGE:
+            case Delta::Action::REMOVE_OUT_EDGE:
+              return false;
+          }
+        });
+      }
     }
     // 5. Process all Vertex deltas and store all operations that delete vertices.
-    for (const auto &delta : transaction.deltas) {
-      auto prev = delta.prev.Get();
-      MG_ASSERT(prev.type != PreviousPtr::Type::NULLPTR, "Invalid pointer!");
-      if (prev.type != PreviousPtr::Type::VERTEX) continue;
-      find_and_apply_deltas(&delta, *prev.vertex, [](auto action) {
-        switch (action) {
-          case Delta::Action::RECREATE_OBJECT:
-            return true;
-          case Delta::Action::DELETE_DESERIALIZED_OBJECT:
-          case Delta::Action::DELETE_OBJECT:
-          case Delta::Action::SET_PROPERTY:
-          case Delta::Action::ADD_LABEL:
-          case Delta::Action::REMOVE_LABEL:
-          case Delta::Action::ADD_IN_EDGE:
-          case Delta::Action::ADD_OUT_EDGE:
-          case Delta::Action::REMOVE_IN_EDGE:
-          case Delta::Action::REMOVE_OUT_EDGE:
-            return false;
-        }
-      });
+    if (transaction.has_vertex_deleting_deltas) {
+      for (const auto &delta : transaction.deltas) {
+        auto prev = delta.prev.Get();
+        MG_ASSERT(prev.type != PreviousPtr::Type::NULLPTR, "Invalid pointer!");
+        if (prev.type != PreviousPtr::Type::VERTEX) continue;
+        find_and_apply_deltas(&delta, *prev.vertex, [](auto action) {
+          switch (action) {
+            case Delta::Action::RECREATE_OBJECT:
+              return true;
+            case Delta::Action::DELETE_DESERIALIZED_OBJECT:
+            case Delta::Action::DELETE_OBJECT:
+            case Delta::Action::SET_PROPERTY:
+            case Delta::Action::ADD_LABEL:
+            case Delta::Action::REMOVE_LABEL:
+            case Delta::Action::ADD_IN_EDGE:
+            case Delta::Action::ADD_OUT_EDGE:
+            case Delta::Action::REMOVE_IN_EDGE:
+            case Delta::Action::REMOVE_OUT_EDGE:
+              return false;
+          }
+        });
+      }
     }
   };
 
@@ -2005,6 +2024,8 @@ bool InMemoryStorage::AppendToWal(const Transaction &transaction, uint64_t final
     });
   }
 
+  spdlog::debug("Number of iterations done: {}", i);
+
   // Handle metadata deltas
   for (const auto &md_delta : transaction.md_deltas) {
     switch (md_delta.action) {
diff --git a/src/storage/v2/inmemory/storage.hpp b/src/storage/v2/inmemory/storage.hpp
index 26abe4faf..e871db8f5 100644
--- a/src/storage/v2/inmemory/storage.hpp
+++ b/src/storage/v2/inmemory/storage.hpp
@@ -182,7 +182,8 @@ class InMemoryStorage final : public Storage {
     bool DeleteLabelIndexStats(const storage::LabelId &label) override;
 
     Result<std::optional<std::pair<std::vector<VertexAccessor>, std::vector<EdgeAccessor>>>> DetachDelete(
-        std::vector<VertexAccessor *> nodes, std::vector<EdgeAccessor *> edges, bool detach) override;
+        std::vector<VertexAccessor *> nodes, std::vector<EdgeAccessor *> edges, bool detach,
+        bool fast = false) override;
 
     /// @throw std::bad_alloc
     Result<EdgeAccessor> CreateEdge(VertexAccessor *from, VertexAccessor *to, EdgeTypeId edge_type) override;
diff --git a/src/storage/v2/mvcc.hpp b/src/storage/v2/mvcc.hpp
index 1cf057d9d..2dd2359d1 100644
--- a/src/storage/v2/mvcc.hpp
+++ b/src/storage/v2/mvcc.hpp
@@ -189,6 +189,36 @@ inline void CreateAndLinkDelta(Transaction *transaction, TObj *object, Args &&..
   // modification is being done, everybody else will wait until we are fully
   // done with our modification before they read the object's delta value.
   object->delta = delta;
+
+  auto pointer_type = object->delta->prev.Get().type;
+  if (pointer_type == PreviousPtr::Type::VERTEX) {
+    switch (delta->action) {
+      case Delta::Action::DELETE_DESERIALIZED_OBJECT:
+      case Delta::Action::DELETE_OBJECT:
+      case Delta::Action::SET_PROPERTY:
+      case Delta::Action::ADD_LABEL:
+      case Delta::Action::REMOVE_LABEL:
+        transaction->has_vertex_modifying_deltas = true;
+        break;
+      case Delta::Action::ADD_OUT_EDGE:
+        transaction->has_edge_deleting_deltas = true;
+        break;
+      case Delta::Action::REMOVE_OUT_EDGE:
+        transaction->has_edge_creating_deltas = true;
+        break;
+      case Delta::Action::RECREATE_OBJECT:
+        transaction->has_vertex_deleting_deltas = true;
+      default:
+        break;
+    }
+  } else if (pointer_type == PreviousPtr::Type::EDGE) {
+    switch (delta->action) {
+      case Delta::Action::SET_PROPERTY:
+        transaction->has_edge_modifying_deltas = true;
+      default:
+        break;
+    }
+  }
 }
 
 }  // namespace memgraph::storage
diff --git a/src/storage/v2/storage.cpp b/src/storage/v2/storage.cpp
index 536a504a0..5508c8f52 100644
--- a/src/storage/v2/storage.cpp
+++ b/src/storage/v2/storage.cpp
@@ -222,7 +222,8 @@ Result<std::optional<EdgeAccessor>> Storage::Accessor::DeleteEdge(EdgeAccessor *
 }
 
 Result<std::optional<std::pair<std::vector<VertexAccessor>, std::vector<EdgeAccessor>>>>
-Storage::Accessor::DetachDelete(std::vector<VertexAccessor *> nodes, std::vector<EdgeAccessor *> edges, bool detach) {
+Storage::Accessor::DetachDelete(std::vector<VertexAccessor *> nodes, std::vector<EdgeAccessor *> edges, bool detach,
+                                bool fast) {
   using ReturnType = std::pair<std::vector<VertexAccessor>, std::vector<EdgeAccessor>>;
   if (storage_->storage_mode_ == StorageMode::ON_DISK_TRANSACTIONAL) {
     for (const auto *vertex : nodes) {
@@ -238,6 +239,15 @@ Storage::Accessor::DetachDelete(std::vector<VertexAccessor *> nodes, std::vector
     }
   }
 
+  if (detach && fast) {
+    auto maybe_deleted_entities = DeleteVerticesFast(nodes);
+    if (maybe_deleted_entities.HasError()) {
+      return maybe_deleted_entities.GetError();
+    }
+
+    return maybe_deleted_entities.GetValue();
+  }
+
   // 1. Gather nodes which are not deleted yet in the system
   auto maybe_nodes_to_delete = PrepareDeletableNodes(nodes);
   if (maybe_nodes_to_delete.HasError()) {
@@ -365,6 +375,84 @@ EdgeInfoForDeletion Storage::Accessor::PrepareDeletableEdges(const std::unordere
                              .partial_dest_vertices = std::move(partial_dest_vertices)};
 }
 
+Result<std::optional<std::pair<std::vector<VertexAccessor>, std::vector<EdgeAccessor>>>>
+Storage::Accessor::DeleteVerticesFast(const std::vector<VertexAccessor *> &vertices) {
+  using ReturnType = std::pair<std::vector<VertexAccessor>, std::vector<EdgeAccessor>>;
+
+  std::vector<VertexAccessor> deleted_vertices;
+  deleted_vertices.reserve(vertices.size());
+  std::vector<EdgeAccessor> deleted_edges;
+  for (auto *vertex_accessor : vertices) {
+    auto vertex_ptr = vertex_accessor->vertex_;
+    auto vertex_lock = std::unique_lock{vertex_ptr->lock};
+
+    if (!PrepareForWrite(&transaction_, vertex_ptr)) return Error::SERIALIZATION_ERROR;
+    MG_ASSERT(!vertex_ptr->deleted, "Invalid database state!");
+
+    while (!vertex_ptr->in_edges.empty()) {
+      auto const &[edge_type, opposing_vertex, edge_ref] = *vertex_ptr->in_edges.rbegin();
+      std::unique_lock<utils::RWSpinLock> guard;
+      if (storage_->config_.salient.items.properties_on_edges) {
+        auto *edge_ptr = edge_ref.ptr;
+        guard = std::unique_lock{edge_ptr->lock};
+
+        if (!PrepareForWrite(&transaction_, edge_ptr)) return Error::SERIALIZATION_ERROR;
+      }
+
+      // MarkEdgeAsDeleted allocates additional memory
+      // and CreateAndLinkDelta needs memory
+      utils::AtomicMemoryBlock atomic_memory_block{[in_edges = &vertex_ptr->in_edges, &vertex_ptr,
+                                                    edge_type = edge_type, opposing_vertex = opposing_vertex,
+                                                    edge_ref = edge_ref, this]() {
+        in_edges->pop_back();
+        if (this->storage_->config_.salient.items.properties_on_edges) {
+          auto *edge_ptr = edge_ref.ptr;
+          MarkEdgeAsDeleted(edge_ptr);
+        }
+
+        CreateAndLinkDelta(&transaction_, vertex_ptr, Delta::AddInEdgeTag(), edge_type, opposing_vertex, edge_ref);
+      }};
+      std::invoke(atomic_memory_block);
+    }
+    while (!vertex_ptr->out_edges.empty()) {
+      auto const &[edge_type, opposing_vertex, edge_ref] = *vertex_ptr->out_edges.rbegin();
+      std::unique_lock<utils::RWSpinLock> guard;
+      if (storage_->config_.salient.items.properties_on_edges) {
+        auto *edge_ptr = edge_ref.ptr;
+        guard = std::unique_lock{edge_ptr->lock};
+
+        if (!PrepareForWrite(&transaction_, edge_ptr)) return Error::SERIALIZATION_ERROR;
+      }
+
+      // MarkEdgeAsDeleted allocates additional memory
+      // and CreateAndLinkDelta needs memory
+      utils::AtomicMemoryBlock atomic_memory_block{[out_edges = &vertex_ptr->out_edges, &vertex_ptr, &deleted_edges,
+                                                    edge_type = edge_type, opposing_vertex = opposing_vertex,
+                                                    edge_ref = edge_ref, this]() {
+        out_edges->pop_back();
+        if (this->storage_->config_.salient.items.properties_on_edges) {
+          auto *edge_ptr = edge_ref.ptr;
+          MarkEdgeAsDeleted(edge_ptr);
+        }
+
+        CreateAndLinkDelta(&transaction_, vertex_ptr, Delta::AddOutEdgeTag(), edge_type, opposing_vertex, edge_ref);
+        deleted_edges.emplace_back(edge_ref, edge_type, vertex_ptr, opposing_vertex, storage_, &transaction_, true);
+      }};
+      std::invoke(atomic_memory_block);
+    }
+
+    if (!vertex_ptr->in_edges.empty() || !vertex_ptr->out_edges.empty()) {
+      return Error::VERTEX_HAS_EDGES;
+    }
+
+    CreateAndLinkDelta(&transaction_, vertex_ptr, Delta::RecreateObjectTag());
+    vertex_ptr->deleted = true;
+
+    deleted_vertices.emplace_back(vertex_ptr, storage_, &transaction_, true);
+  }
+  return std::make_optional<ReturnType>(deleted_vertices, deleted_edges);
+}
+
 Result<std::optional<std::vector<EdgeAccessor>>> Storage::Accessor::ClearEdgesOnVertices(
     const std::unordered_set<Vertex *> &vertices, std::unordered_set<Gid> &deleted_edge_ids) {
   // We want to gather all edges that we delete in this step so that we can proceed with
diff --git a/src/storage/v2/storage.hpp b/src/storage/v2/storage.hpp
index a096f27fd..218d294de 100644
--- a/src/storage/v2/storage.hpp
+++ b/src/storage/v2/storage.hpp
@@ -178,7 +178,7 @@ class Storage {
         VertexAccessor *vertex);
 
     virtual Result<std::optional<std::pair<std::vector<VertexAccessor>, std::vector<EdgeAccessor>>>> DetachDelete(
-        std::vector<VertexAccessor *> nodes, std::vector<EdgeAccessor *> edges, bool detach);
+        std::vector<VertexAccessor *> nodes, std::vector<EdgeAccessor *> edges, bool detach, bool fast = false);
 
     virtual uint64_t ApproximateVertexCount() const = 0;
 
@@ -289,6 +289,8 @@ class Storage {
     bool is_transaction_active_;
 
     // Detach delete private methods
+    Result<std::optional<std::pair<std::vector<VertexAccessor>, std::vector<EdgeAccessor>>>> DeleteVerticesFast(
+        const std::vector<VertexAccessor *> &vertices);
     Result<std::optional<std::unordered_set<Vertex *>>> PrepareDeletableNodes(
         const std::vector<VertexAccessor *> &vertices);
     EdgeInfoForDeletion PrepareDeletableEdges(const std::unordered_set<Vertex *> &vertices,
diff --git a/src/storage/v2/transaction.hpp b/src/storage/v2/transaction.hpp
index 9f973cbf0..2777a46dd 100644
--- a/src/storage/v2/transaction.hpp
+++ b/src/storage/v2/transaction.hpp
@@ -90,6 +90,11 @@ struct Transaction {
 
   std::deque<Delta> deltas;
   utils::pmr::list<MetadataDelta> md_deltas;
+  bool has_vertex_modifying_deltas{false};
+  bool has_edge_creating_deltas{false};
+  bool has_edge_modifying_deltas{false};
+  bool has_edge_deleting_deltas{false};
+  bool has_vertex_deleting_deltas{false};
   bool must_abort{};
   IsolationLevel isolation_level{};
   StorageMode storage_mode{};