-
-
Notifications
You must be signed in to change notification settings - Fork 866
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Better query plan viewing experience #4285
Merged
Merged
Changes from 21 commits
Commits
Show all changes
40 commits
Select commit
Hold shift + click to select a range
4fe1dd9
stuff
dullbananas ea6f391
Merge remote-tracking branch 'upstream/main' into change-test-db
dullbananas fdebc85
stuff including batch_upsert function
dullbananas 9b9314a
stuff
dullbananas 869a246
do things
dullbananas ad2af54
stuff
dullbananas 191e2f0
different timestamps
dullbananas 82e37f7
stuff
dullbananas f54a350
Revert changes to comment.rs
dullbananas d896109
Update comment.rs
dullbananas ef654b1
Update comment.rs
dullbananas 49ca4da
Update post_view.rs
dullbananas fc30008
Update utils.rs
dullbananas 23c64ea
Merge branch 'main' into change-test-db
dullbananas 4654404
Update up.sql
dullbananas f4dd788
Update up.sql
dullbananas 1fcf2f7
Update down.sql
dullbananas 22030b5
Update up.sql
dullbananas abcf331
Update main.rs
dullbananas 029cb25
use anyhow macro
dullbananas 9e32072
Merge branch 'main' into change-test-db
dullbananas 41ac26d
Merge branch 'main' into change-test-db
dullbananas eef2eb1
Merge branch 'main' into change-test-db
dullbananas bf046b2
replace get(0) with first()
dullbananas 6fe3fe5
as_slice
dullbananas 1db0493
Merge branch 'main' into change-test-db
dullbananas d93e7f1
Update series.rs
dullbananas 193a936
Update db_perf.sh
dullbananas b9959e5
Merge branch 'main' into change-test-db
dullbananas 31ecf0a
Merge branch 'main' into change-test-db
Nutomic 06e3209
Update and rename crates/db_schema/src/utils/series.rs to crates/db_p…
dullbananas 6aa4b14
Update utils.rs
dullbananas 7deec2a
Update main.rs
dullbananas 8ecd74e
Update main.rs
dullbananas 2a79cb6
Update .woodpecker.yml
dullbananas a61a213
fmt main.rs
dullbananas 439f700
Update .woodpecker.yml
dullbananas b0075b5
Instance::delete at end
dullbananas dcbd190
Update main.rs
dullbananas 6fd6041
Update Cargo.toml
dullbananas File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
[package] | ||
name = "lemmy_db_perf" | ||
version.workspace = true | ||
edition.workspace = true | ||
description.workspace = true | ||
license.workspace = true | ||
homepage.workspace = true | ||
documentation.workspace = true | ||
repository.workspace = true | ||
|
||
|
||
[lints] | ||
workspace = true | ||
|
||
[dependencies] | ||
clap = { workspace = true } | ||
diesel = { workspace = true } | ||
diesel-async = { workspace = true } | ||
lemmy_db_schema = { workspace = true } | ||
lemmy_db_views = { workspace = true, features = ["full"] } | ||
lemmy_utils = { workspace = true } | ||
tokio = { workspace = true } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,174 @@ | ||
use clap::Parser; | ||
use diesel::{ | ||
dsl::{self, sql}, | ||
sql_types, | ||
ExpressionMethods, | ||
IntoSql, | ||
}; | ||
use diesel_async::{RunQueryDsl, SimpleAsyncConnection}; | ||
use lemmy_db_schema::{ | ||
schema::post, | ||
source::{ | ||
community::{Community, CommunityInsertForm}, | ||
instance::Instance, | ||
person::{Person, PersonInsertForm}, | ||
}, | ||
traits::Crud, | ||
utils::{ | ||
build_db_pool, | ||
get_conn, | ||
now, | ||
series::{self, ValuesFromSeries}, | ||
}, | ||
SortType, | ||
}; | ||
use lemmy_db_views::{post_view::PostQuery, structs::PaginationCursor}; | ||
use lemmy_utils::error::LemmyResult; | ||
use std::num::NonZeroU32; | ||
|
||
#[derive(Parser, Debug)] | ||
struct CmdArgs { | ||
#[arg(long, default_value_t = 3.try_into().unwrap())] | ||
communities: NonZeroU32, | ||
#[arg(long, default_value_t = 3.try_into().unwrap())] | ||
people: NonZeroU32, | ||
#[arg(long, default_value_t = 100000.try_into().unwrap())] | ||
posts: NonZeroU32, | ||
#[arg(long, default_value_t = 0)] | ||
read_post_pages: u32, | ||
#[arg(long)] | ||
explain_insertions: bool, | ||
} | ||
|
||
#[tokio::main] | ||
async fn main() -> LemmyResult<()> { | ||
if let Err(err) = try_main().await { | ||
println!("😂 Error: {err:?}"); | ||
} | ||
if let Ok(path) = std::env::var("PGDATA") { | ||
println!("🪵 query plans and error details written in {path}/log"); | ||
} | ||
|
||
Ok(()) | ||
} | ||
|
||
async fn try_main() -> LemmyResult<()> { | ||
let args = CmdArgs::parse(); | ||
let pool = &build_db_pool().await?; | ||
let pool = &mut pool.into(); | ||
let conn = &mut get_conn(pool).await?; | ||
|
||
if args.explain_insertions { | ||
// log_nested_statements is enabled to log trigger execution | ||
conn | ||
.batch_execute( | ||
"SET auto_explain.log_min_duration = 0; SET auto_explain.log_nested_statements = on;", | ||
) | ||
.await?; | ||
} | ||
|
||
let instance = Instance::read_or_create(&mut conn.into(), "reddit.com".to_owned()).await?; | ||
|
||
println!("🫃 creating {} people", args.people); | ||
let mut person_ids = vec![]; | ||
for i in 0..args.people.get() { | ||
let form = PersonInsertForm::builder() | ||
.name(format!("p{i}")) | ||
.public_key("pubkey".to_owned()) | ||
.instance_id(instance.id) | ||
.build(); | ||
person_ids.push(Person::create(&mut conn.into(), &form).await?.id); | ||
} | ||
|
||
println!("🌍 creating {} communities", args.communities); | ||
let mut community_ids = vec![]; | ||
for i in 0..args.communities.get() { | ||
let form = CommunityInsertForm::builder() | ||
.name(format!("c{i}")) | ||
.title(i.to_string()) | ||
.instance_id(instance.id) | ||
.build(); | ||
community_ids.push(Community::create(&mut conn.into(), &form).await?.id); | ||
} | ||
|
||
let post_batches = args.people.get() * args.communities.get(); | ||
let posts_per_batch = args.posts.get() / post_batches; | ||
let num_posts = post_batches * posts_per_batch; | ||
println!( | ||
"📜 creating {} posts ({} featured in community)", | ||
num_posts, post_batches | ||
); | ||
let mut num_inserted_posts = 0; | ||
// TODO: progress bar | ||
for person_id in &person_ids { | ||
for community_id in &community_ids { | ||
let n = dsl::insert_into(post::table) | ||
.values(ValuesFromSeries { | ||
start: 1, | ||
stop: posts_per_batch.into(), | ||
selection: ( | ||
"AAAAAAAAAAA".into_sql::<sql_types::Text>(), | ||
person_id.into_sql::<sql_types::Integer>(), | ||
community_id.into_sql::<sql_types::Integer>(), | ||
series::current_value.eq(1), | ||
now() | ||
- sql::<sql_types::Interval>("make_interval(secs => ") | ||
.bind::<sql_types::BigInt, _>(series::current_value) | ||
.sql(")"), | ||
), | ||
}) | ||
.into_columns(( | ||
post::name, | ||
post::creator_id, | ||
post::community_id, | ||
post::featured_community, | ||
post::published, | ||
)) | ||
.execute(conn) | ||
.await?; | ||
num_inserted_posts += n; | ||
} | ||
} | ||
// Make sure the println above shows the correct amount | ||
assert_eq!(num_inserted_posts, num_posts as usize); | ||
|
||
// Enable auto_explain | ||
conn | ||
.batch_execute( | ||
"SET auto_explain.log_min_duration = 0; SET auto_explain.log_nested_statements = off;", | ||
) | ||
.await?; | ||
|
||
// TODO: show execution duration stats | ||
let mut page_after = None; | ||
for page_num in 1..=args.read_post_pages { | ||
println!( | ||
"👀 getting page {page_num} of posts (pagination cursor used: {})", | ||
page_after.is_some() | ||
); | ||
|
||
// TODO: include local_user | ||
let post_views = PostQuery { | ||
community_id: community_ids.get(0).cloned(), | ||
sort: Some(SortType::New), | ||
limit: Some(20), | ||
page_after, | ||
..Default::default() | ||
} | ||
.list(&mut conn.into()) | ||
.await?; | ||
|
||
if let Some(post_view) = post_views.into_iter().last() { | ||
println!("👀 getting pagination cursor data for next page"); | ||
let cursor_data = PaginationCursor::after_post(&post_view) | ||
.read(&mut conn.into()) | ||
.await?; | ||
page_after = Some(cursor_data); | ||
} else { | ||
println!("👀 reached empty page"); | ||
break; | ||
} | ||
} | ||
|
||
Ok(()) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -96,16 +96,18 @@ impl LocalUserLanguage { | |
.execute(conn) | ||
.await?; | ||
|
||
for l in lang_ids { | ||
let form = LocalUserLanguageForm { | ||
let forms = lang_ids | ||
.into_iter() | ||
.map(|l| LocalUserLanguageForm { | ||
local_user_id: for_local_user_id, | ||
language_id: l, | ||
}; | ||
insert_into(local_user_language) | ||
.values(form) | ||
.get_result::<Self>(conn) | ||
.await?; | ||
} | ||
}) | ||
.collect::<Vec<_>>(); | ||
|
||
insert_into(local_user_language) | ||
.values(forms) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nice, this should be much better. |
||
.execute(conn) | ||
.await?; | ||
Ok(()) | ||
}) as _ | ||
}) | ||
|
@@ -164,16 +166,18 @@ impl SiteLanguage { | |
.execute(conn) | ||
.await?; | ||
|
||
for l in lang_ids { | ||
let form = SiteLanguageForm { | ||
let forms = lang_ids | ||
.into_iter() | ||
.map(|l| SiteLanguageForm { | ||
site_id: for_site_id, | ||
language_id: l, | ||
}; | ||
insert_into(site_language) | ||
.values(form) | ||
.get_result::<Self>(conn) | ||
.await?; | ||
} | ||
}) | ||
.collect::<Vec<_>>(); | ||
|
||
insert_into(site_language) | ||
.values(forms) | ||
.get_result::<Self>(conn) | ||
.await?; | ||
|
||
CommunityLanguage::limit_languages(conn, instance_id).await?; | ||
|
||
|
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I dont see the purpose of this wrapper, Rust should handle errors from main just fine.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also can you run this code from CI with low number of posts and communities to make sure it doesnt break in the future?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The custom error handling makes it possible to show the log path when an error happens. I now changed it to be cleaner and return the correct exit code.
I also made it run in CI.