Skip to content

Commit

Permalink
perf: remove select before deleteMany (prisma#4249)
Browse files Browse the repository at this point in the history
* perf: remove select before deleteMany

* fix nested delete many

* fix: set selectors in graph to avoid double read
  • Loading branch information
Weakky authored Sep 29, 2023
1 parent 2b2ffb4 commit 18f3e40
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 31 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -362,23 +362,23 @@ pub(crate) async fn delete_records(
ctx: &Context<'_>,
) -> crate::Result<usize> {
let filter_condition = FilterBuilder::without_top_level_joins().visit_filter(record_filter.clone().filter, ctx);
let ids = conn.filter_selectors(model, record_filter, ctx).await?;
let ids: Vec<&SelectionResult> = ids.iter().collect();
let count = ids.len();

if count == 0 {
return Ok(count);
}
// If we have selectors, then we must chunk the mutation into multiple if necessary and add the ids to the filter.
let row_count = if record_filter.has_selectors() {
let ids: Vec<_> = record_filter.selectors.as_ref().unwrap().iter().collect();
let mut row_count = 0;

let mut row_count = 0;
for delete in write::delete_many(model, ids.as_slice(), filter_condition, ctx) {
row_count += conn.execute(delete).await?;
}
for delete in write::delete_many_from_ids_and_filter(model, ids.as_slice(), filter_condition, ctx) {
row_count += conn.execute(delete).await?;
}

match usize::try_from(row_count) {
Ok(row_count) => Ok(row_count),
Err(_) => Ok(count),
}
row_count
} else {
conn.execute(write::delete_many_from_filter(model, filter_condition, ctx))
.await?
};

Ok(row_count as usize)
}

/// Connect relations defined in `child_ids` to a parent defined in `parent_id`.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,19 @@ pub(crate) fn chunk_update_with_ids(
Ok(query)
}

pub(crate) fn delete_many(
pub(crate) fn delete_many_from_filter(
model: &Model,
filter_condition: ConditionTree<'static>,
ctx: &Context<'_>,
) -> Query<'static> {
Delete::from_table(model.as_table(ctx))
.so_that(filter_condition)
.append_trace(&Span::current())
.add_trace_id(ctx.trace_id)
.into()
}

pub(crate) fn delete_many_from_ids_and_filter(
model: &Model,
ids: &[&SelectionResult],
filter_condition: ConditionTree<'static>,
Expand All @@ -201,10 +213,7 @@ pub(crate) fn delete_many(
.collect();

super::chunked_conditions(&columns, ids, |conditions| {
Delete::from_table(model.as_table(ctx))
.so_that(conditions.and(filter_condition.clone()))
.append_trace(&Span::current())
.add_trace_id(ctx.trace_id)
delete_many_from_filter(model, conditions.and(filter_condition.clone()), ctx)
})
}

Expand Down
39 changes: 27 additions & 12 deletions query-engine/core/src/query_graph_builder/write/delete.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use super::*;
use crate::{
query_ast::*,
query_graph::{QueryGraph, QueryGraphDependency},
query_graph::{Node, QueryGraph, QueryGraphDependency},
ArgumentListLookup, FilteredQuery, ParsedField,
};
use connector::filter::Filter;
Expand Down Expand Up @@ -52,6 +52,7 @@ pub(crate) fn delete_record(
)?;

graph.add_result_node(&read_node);

Ok(())
}

Expand All @@ -62,31 +63,45 @@ pub fn delete_many_records(
model: Model,
mut field: ParsedField<'_>,
) -> QueryGraphBuilderResult<()> {
graph.flag_transactional();

let filter = match field.arguments.lookup(args::WHERE) {
Some(where_arg) => extract_filter(where_arg.value.try_into()?, &model)?,
None => Filter::empty(),
};

let model_id = model.primary_identifier();
let read_query = utils::read_ids_infallible(model.clone(), model_id, filter.clone());
let record_filter = filter.into();
let record_filter = filter.clone().into();
let delete_many = WriteQuery::DeleteManyRecords(DeleteManyRecords {
model: model.clone(),
record_filter,
});

let read_query_node = graph.create_node(read_query);
let delete_many_node = graph.create_node(Query::Write(delete_many));

utils::insert_emulated_on_delete(graph, query_schema, &model, &read_query_node, &delete_many_node)?;
if query_schema.relation_mode().is_prisma() {
graph.flag_transactional();

graph.create_edge(
&read_query_node,
&delete_many_node,
QueryGraphDependency::ExecutionOrder,
)?;
let read_query = utils::read_ids_infallible(model.clone(), model_id.clone(), filter);
let read_query_node = graph.create_node(read_query);

utils::insert_emulated_on_delete(graph, query_schema, &model, &read_query_node, &delete_many_node)?;

graph.create_edge(
&read_query_node,
&delete_many_node,
QueryGraphDependency::ProjectedDataDependency(
model_id,
Box::new(|mut delete_many_node, ids| {
if let Node::Query(Query::Write(WriteQuery::DeleteManyRecords(ref mut dmr))) = delete_many_node {
dmr.record_filter = ids.into();
}

Ok(delete_many_node)
}),
),
)?;
}

graph.add_result_node(&delete_many_node);

Ok(())
}

0 comments on commit 18f3e40

Please sign in to comment.