Sqlite explain plan log efficiency (#2091)

* capture operation codes by reference

* use Vec instead of HashSet for results

* check logging enabled before cloning result
This commit is contained in:
tyrelr 2022-09-12 19:22:15 -06:00 committed by GitHub
parent f38c739f7f
commit 8fca76065a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 32 additions and 22 deletions

View File

@ -85,32 +85,41 @@ impl<'q> Drop for QueryLogger<'q> {
}
#[cfg(feature = "sqlite")]
pub(crate) struct QueryPlanLogger<'q, O: Debug + Hash + Eq, R: Debug + Hash + Eq, P: Debug> {
pub(crate) struct QueryPlanLogger<'q, O: Debug + Hash + Eq, R: Debug, P: Debug> {
sql: &'q str,
unknown_operations: HashSet<O>,
results: HashSet<R>,
program: Vec<P>,
results: Vec<R>,
program: &'q [P],
settings: LogSettings,
}
#[cfg(feature = "sqlite")]
impl<'q, O: Debug + Hash + Eq, R: Debug + Hash + Eq, P: Debug> QueryPlanLogger<'q, O, R, P> {
pub(crate) fn new(sql: &'q str, settings: LogSettings) -> Self {
impl<'q, O: Debug + Hash + Eq, R: Debug, P: Debug> QueryPlanLogger<'q, O, R, P> {
pub(crate) fn new(sql: &'q str, program: &'q [P], settings: LogSettings) -> Self {
Self {
sql,
unknown_operations: HashSet::new(),
results: HashSet::new(),
program: Vec::new(),
results: Vec::new(),
program,
settings,
}
}
pub(crate) fn add_result(&mut self, result: R) {
self.results.insert(result);
pub(crate) fn log_enabled(&self) -> bool {
if let Some(_lvl) = self
.settings
.statements_level
.to_level()
.filter(|lvl| log::log_enabled!(target: "sqlx::explain", *lvl))
{
return true;
} else {
return false;
}
}
pub(crate) fn add_program(&mut self, program: Vec<P>) {
self.program = program;
pub(crate) fn add_result(&mut self, result: R) {
self.results.push(result);
}
pub(crate) fn add_unknown_operation(&mut self, operation: O) {
@ -156,9 +165,7 @@ impl<'q, O: Debug + Hash + Eq, R: Debug + Hash + Eq, P: Debug> QueryPlanLogger<'
}
#[cfg(feature = "sqlite")]
impl<'q, O: Debug + Hash + Eq, R: Debug + Hash + Eq, P: Debug> Drop
for QueryPlanLogger<'q, O, R, P>
{
impl<'q, O: Debug + Hash + Eq, R: Debug, P: Debug> Drop for QueryPlanLogger<'q, O, R, P> {
fn drop(&mut self) {
self.finish();
}

View File

@ -328,17 +328,17 @@ pub(super) fn explain(
conn: &mut ConnectionState,
query: &str,
) -> Result<(Vec<SqliteTypeInfo>, Vec<Option<bool>>), Error> {
let mut logger = crate::logger::QueryPlanLogger::new(query, conn.log_settings.clone());
let root_block_cols = root_block_columns(conn)?;
let program: Vec<(i64, String, i64, i64, i64, Vec<u8>)> =
execute::iter(conn, &format!("EXPLAIN {}", query), None, false)?
.filter_map(|res| res.map(|either| either.right()).transpose())
.map(|row| FromRow::from_row(&row?))
.collect::<Result<Vec<_>, Error>>()?;
logger.add_program(program.clone());
let program_size = program.len();
let mut logger =
crate::logger::QueryPlanLogger::new(query, &program, conn.log_settings.clone());
let mut states = vec![QueryState {
visited: vec![false; program_size],
history: Vec::new(),
@ -588,7 +588,7 @@ pub(super) fn explain(
);
}
_ => logger.add_unknown_operation(program[state.program_i].clone()),
_ => logger.add_unknown_operation(&program[state.program_i]),
}
}
@ -753,9 +753,12 @@ pub(super) fn explain(
.collect(),
);
let program_history: Vec<(i64, String, i64, i64, i64, Vec<u8>)> =
state.history.iter().map(|i| program[*i].clone()).collect();
logger.add_result((program_history, state.result.clone()));
if logger.log_enabled() {
let program_history: Vec<&(i64, String, i64, i64, i64, Vec<u8>)> =
state.history.iter().map(|i| &program[*i]).collect();
logger.add_result((program_history, state.result.clone()));
}
result_states.push(state.clone());
}
@ -766,7 +769,7 @@ pub(super) fn explain(
_ => {
// ignore unsupported operations
// if we fail to find an r later, we just give up
logger.add_unknown_operation(program[state.program_i].clone());
logger.add_unknown_operation(&program[state.program_i]);
}
}