Skip to content
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

Joins typeck is exponential in number of joins #3223

Open
Ten0 opened this issue Jul 7, 2022 · 32 comments
Open

Joins typeck is exponential in number of joins #3223

Ten0 opened this issue Jul 7, 2022 · 32 comments

Comments

@Ten0
Copy link
Member

Ten0 commented Jul 7, 2022

Setup

Versions

  • Rust: rustc 1.64.0-nightly (7665c3543 2022-07-06)
  • Diesel: 2.0.0-rc.0, features postgres, 64-column-tables
  • Operating System: Linux

Problem Description

Joins typeck appears to be exponential in number of joins, despite incremental compilation and not touching the function that contains the joins itself.
That makes getting compiler feedback after touching a crate that uses a lot of Diesel queries take an unreasonable amount of time.

E.g. with just 7 joins:

=> With a few hundred such functions in a crate, getting the smallest amount of feedback from a cargo check when making changes easily takes several minutes.

Steps to reproduce

The following repository gives code and detailed step-by-step on how to observe this behavior:
https://github.com/Ten0/diesel_3223_repro


@lqd It seems you have been investigating a similar performance issue that notably affected Diesel earlier this year. Would you have any insight on what would be the process to follow in order to tackle this? Thanks a lot! 🥰

@Ten0
Copy link
Member Author

Ten0 commented Jul 14, 2022

Maybe related: rust-lang/rust#20304

@lqd
Copy link

lqd commented Jul 14, 2022

It could also be related to rust-lang/rust#99188 which also has exponential behavior (if associated types, and big wrapped items are involved, which I'm not sure is the case here I haven't had the time to look at the repo yet).

what would be the process to follow in order to tackle this

First, it's easier if the reproduction code is minimal. That is, if it doesn't depend on diesel itself, but extracts some of the code that triggers the issue. Then trying to reduce that to a very small size, so that any other piece of code that is not related to the issue doesn't interfere with the measurement or fixing processes.

With that done (it could be done independently of course), one could also easily see if this is a new issue, or an old one, to see if it's a regression or not, and locate the PR that caused it if that's the case. Notifying the PR author and reviewer would then be good, if it is a regression.

In parallel, the easiest first step would be to narrow down the vague area of rustc where the issue happens. One would that looking at the -Zself-profile data. I would guess that either evaluate_obligation or specialization_graph_of would be the likeliest of queries taking a long time in this situation.

These 2 steps would also allow looking for rust issues that could already track the problem, maybe there are workarounds there, or a lack of data that prevents people from working on it. Though, if it's a stress test that doesn't look like real code people use, it may not be seen as high priority: the scalability behavior at higher Ns, while annoying and a bug needing to be fixed, can be pretty rare to hit in practice (and a sign to "not do that and hopefully have a different design if at all possible").

There are many issues filed already, and sometimes they conflict with each other: a bunch of such regressions happened because of incorrect handling for incremental compilation, and slower compile times in rare cases are a compromise compared to having possible soundness issues. A lot have been fixed already (for example, #99188 was also impacted by some trait system caching removal in 1.56 to fix incremental compilation soundness issues, there was a 1000x slowdown in that stress test. Until some of that was improved in 1.59 and performance is now better than in 1.55) and more will be in the future. But some of those are very hard to fix, and there are not many people with the time and knowledge to do so (and most of them are volunteer contributors with limited time).

All the above will help gather data to have all the information to understand the issue, and help people who could fix it.

@Ten0
Copy link
Member Author

Ten0 commented Jul 14, 2022

Thanks a lot for your answer!

It could also be related to rust-lang/rust#99188 which also has exponential behavior (if associated types, and big wrapped items are involved, which I'm not sure is the case here I haven't had the time to look at the repo yet).

I looked into this yesterday as it seemed to be a very close issue (this here is indeed is an issue when evaluating a trait bound on a large wrapped type) but I think that is not the exact same issue because:

replacing the for<'x> T: Trait<'x, ... with T: Trait<'static, ... removes the exponential slowdown

(rust-lang/rust#99188 (comment))
and everything is 'static in our case.

Also according to this writeup the error from 99188 happens at the borrow checking step, while this one happens at the type_check_crate step.

looking at the -Zself-profile data

So I had done that (screenshots from the reproduction repository linked above) and evaluate_obligation seems to be a good part of what takes an unreasonable amount of time indeed, although half of the time appears to be spent in typeck itself.

evaluate_obligation's parameters (-Zself-profile-events=default,args) are to evaluate whether the super long type that represents the sequence of joins satisfies QuerySource. That notably depends on whether the contained joins satisfy QuerySource themselves.

one could also easily see if this is a new issue, or an old one

Would that be going through https://github.com/rust-lang/rust/issues?q=is%3Aopen+label%3AI-compiletime+label%3AA-traits and looking for similarities or is there another method? (or is "one" somebody specifically? ^^)

Thanks again!

@weiznich
Copy link
Member

I've tried to create a minimal reproducible example without diesel here, but I failed. The example compiles, but does not reproduce the exponential behaviour. I post it nevertheless here, maybe that's helpful anyway.

@lqd
Copy link

lqd commented Jul 14, 2022

I suggest:

  • making a reproduction without diesel by using automatic reduction tools, starting from the repro with e.g. rust-reduce, perses, and similar tools, since it seems manually building it up from scratch is very difficult.
  • trying to see if it's a regression: manually look back at old releases. If that's the case, use cargo-bisect-rust to locate the nightly and PR.
  • if not, looking at open issues, not necessarily going through that exact filtering combination (even though it's possible there's one): they're not always tagged with I-compiletime or A-traits. If there is none, open a new issue with the self-contained repro. Ping the types team on the issue, and/or discuss it on their dedicated zulip stream.
  • with the queries & arguments you've looked at, the next step would be to understand the part of rustc that's causing the issue, seeing if it's easy to fix or not via debugging, adding logging, bisecting the code, etc: this is not necessarily something you would have to do, but anyone wanting to fix the issue would need to. Such an issue is likely hard to debug/fix, but you never know.

@weiznich
Copy link
Member

weiznich commented Jul 15, 2022

I've tried to just reproduce @Ten0 results locally and I've failed doing that. So here is what I done so far:

  • Modify the linked repo to include up to 17 tables. The linked table cites ~6s for typeck for this. I've observed clean build times (cargo clean -p compile_time_test + cargo check) for the affected crate of ~8s, so that seems to fit
  • Now if I just modify the other function, that does not touch the joins I get check times of less than a second, if I modify the joins (even just whitespace changes there) I get check times of ~ 8-9s, which are in line with the results above.

That means at least for me the check times are heavily dependent on what is cached by incremental compilation and what not.

(This happens with the latest nightly as well as the referenced compiler version)

@Ten0
Copy link
Member Author

Ten0 commented Jul 15, 2022

  • Now if I just modify the other function

Incremental compilation cache is actually pretty smart here: if you modify the value in the println, or the value of a number, etc, it will actually hit the cache and not recheck the whole crate. Have you done the comment/uncomment stuff and added a new println for each measured run? (steps 2 and 6)
In my case this little amount of changes - actually adding instructions - is necessary to trigger the issue.
(It's also something that happens all the time in regular coding so the compiler being smart in this case doesn't help that much with the original issue)

@weiznich
Copy link
Member

Incremental compilation cache is actually pretty smart here: if you modify the value in the println, or the value of a number, etc, it will actually hit the cache and not recheck the whole crate. Have you done the comment/uncomment stuff and added a new println for each measured run? (steps 2 and 6)
In my case this little amount of changes - actually adding instructions - is necessary to trigger the issue.
(It's also something that happens all the time in regular coding so the compiler being smart in this case doesn't help that much with the original issue)

I should have been more precise about this. The following changes do not result in a large check time:

  • Commenting in/out a single println! in different_each_regen
  • Commenting in/out the whole different_each_regen function

The following changes do result in large check times:

  • Adding/removing a println! statement to different_each_regen
  • Adding any empty line before the body_0 function
  • Changing some whitespace inside the body_0 function

I assume that all of the later changes just invalidate the incremental compilation cache.

In my opinion that gives two issues to maybe report to the rustc team:

  • Caching should not be dependent on unrelated changes, especially adding stuff into some function before should not invalid a cache entry at all in my eyes.
  • Typeck being slow for this case, although that likely needs a minimal example.

@lqd
Copy link

lqd commented Jul 15, 2022

Caching should not be dependent on unrelated changes, especially adding stuff into some function before should not invalid a cache entry at all in my eyes

This is a known issue and is being worked on: adding things above a function currently changes the spans of all the items following it, invalidating them since they can be used to refer to other items' locations in diagnostics for example.

It could be interesting to try the WIP work supposed to fix some of these cases: -Zincremental-relative-spans, although IIRC it currently still pessimizes diesel, so it's both not ready yet and may not change anything here 😓.

@Ten0
Copy link
Member Author

Ten0 commented Jul 15, 2022

The following changes do result in large check times:
* Adding/removing a println! statement to different_each_regen

So it looks like you did succeed to reproduce my results. :)

-Zincremental-relative-spans

Indeed doesn't change anything for this particular reproduction case.

adding things above a function currently changes the spans of all the items following it, invalidating them since they can be used to refer to other items' locations in diagnostics for example

It looks like I failed to correctly extract the repro from my original crate then:

  • Here when I update a module, only the functions below it are rechecked and take tons of time.
  • In my original crate I can see all the functions being rechecked and taking that unreasonable amount of time upon typecheck, not only those whose position in a given file have changed.

Any clue of why that could be?
That would probably help me to extract another example.

@weiznich
Copy link
Member

Thanks for this information. It's good to hear that this is already worked on.

I've run some more profiling on this. Everything that follows is with 17 tables + recorded with -Z self-profile -Z self-profile-events=default,args

  • Summarize says that it is spending 6.2s out of 8s in evaluate_obligation (so 74% of the time is spend there)
  • Exporting the profile into the chrome profile viewer shows the following trace: Profile

It's not clear for my why exatly this bounds show up as beeing that expensive to evaluate, while other bounds seems to be fine even if they involve similar types.

First `evaluate_obligation` in a block This one takes 60ms

arg0:

Canonical { max_universe: U0, variables: [], value: ParamEnvAnd { param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst }, value: Binder(TraitPredicate(<compile_time_test_schema::some_table_1::table as diesel::JoinTo<diesel::internal::table_macro::SelectStatement<diesel::internal::table_macro::FromClause<diesel::internal::table_macro::JoinOn<diesel::internal::table_macro::Join<compile_time_test_schema::some_table_2::table, diesel::internal::table_macro::SelectStatement<diesel::internal::table_macro::FromClause<diesel::internal::table_macro::JoinOn<diesel::internal::table_macro::Join<compile_time_test_schema::some_table_3::table, diesel::internal::table_macro::SelectStatement<diesel::internal::table_macro::FromClause<diesel::internal::table_macro::JoinOn<diesel::internal::table_macro::Join<compile_time_test_schema::some_table_4::table, diesel::internal::table_macro::SelectStatement<diesel::internal::table_macro::FromClause<diesel::internal::table_macro::JoinOn<diesel::internal::table_macro::Join<compile_time_test_schema::some_table_5::table, diesel::internal::table_macro::SelectStatement<diesel::internal::table_macro::FromClause<diesel::internal::table_macro::JoinOn<diesel::internal::table_macro::Join<compile_time_test_schema::some_table_6::table, diesel::internal::table_macro::SelectStatement<diesel::internal::table_macro::FromClause<diesel::internal::table_macro::JoinOn<diesel::internal::table_macro::Join<compile_time_test_schema::some_table_7::table, diesel::internal::table_macro::SelectStatement<diesel::internal::table_macro::FromClause<diesel::internal::table_macro::JoinOn<diesel::internal::table_macro::Join<compile_time_test_schema::some_table_8::table, diesel::internal::table_macro::SelectStatement<diesel::internal::table_macro::FromClause<diesel::internal::table_macro::JoinOn<diesel::internal::table_macro::Join<compile_time_test_schema::some_table_9::table, diesel::internal::table_macro::SelectStatement<diesel::internal::table_macro::FromClause<diesel::internal::table_macro::JoinOn<diesel::internal::table_macro::Join<compile_time_test_schema::some_table_10::table, diesel::internal::table_macro::SelectStatement<diesel::internal::table_macro::FromClause<diesel::internal::table_macro::JoinOn<diesel::internal::table_macro::Join<compile_time_test_schema::some_table_11::table, diesel::internal::table_macro::SelectStatement<diesel::internal::table_macro::FromClause<diesel::internal::table_macro::JoinOn<diesel::internal::table_macro::Join<compile_time_test_schema::some_table_12::table, diesel::internal::table_macro::SelectStatement<diesel::internal::table_macro::FromClause<diesel::internal::table_macro::JoinOn<diesel::internal::table_macro::Join<compile_time_test_schema::some_table_13::table, diesel::internal::table_macro::SelectStatement<diesel::internal::table_macro::FromClause<diesel::internal::table_macro::JoinOn<diesel::internal::table_macro::Join<compile_time_test_schema::some_table_14::table, diesel::internal::table_macro::SelectStatement<diesel::internal::table_macro::FromClause<diesel::internal::table_macro::JoinOn<diesel::internal::table_macro::Join<compile_time_test_schema::some_table_15::table, diesel::internal::table_macro::SelectStatement<diesel::internal::table_macro::FromClause<diesel::internal::table_macro::JoinOn<diesel::internal::table_macro::Join<compile_time_test_schema::some_table_16::table, compile_time_test_schema::some_table_17::table, diesel::internal::table_macro::Inner>, diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_16::id>, diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_17::id>>>>>>, diesel::internal::table_macro::Inner>, diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_15::id>, diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_16::id>>>>>>, diesel::internal::table_macro::Inner>, diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_14::id>, diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_15::id>>>>>>, diesel::internal::table_macro::Inner>, diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_13::id>, diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_14::id>>>>>>, diesel::internal::table_macro::Inner>, diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_12::id>, diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_13::id>>>>>>, diesel::internal::table_macro::Inner>, diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_11::id>, diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_12::id>>>>>>, diesel::internal::table_macro::Inner>, diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_10::id>, diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_11::id>>>>>>, diesel::internal::table_macro::Inner>, diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_9::id>, diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_10::id>>>>>>, diesel::internal::table_macro::Inner>, diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_8::id>, diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_9::id>>>>>>, diesel::internal::table_macro::Inner>, diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_7::id>, diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_8::id>>>>>>, diesel::internal::table_macro::Inner>, diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_6::id>, diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_7::id>>>>>>, diesel::internal::table_macro::Inner>, diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_5::id>, diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_6::id>>>>>>, diesel::internal::table_macro::Inner>, diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_4::id>, diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_5::id>>>>>>, diesel::internal::table_macro::Inner>, diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_3::id>, diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_4::id>>>>>>, diesel::internal::table_macro::Inner>, diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_2::id>, diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_3::id>>>>>>>>, polarity:Positive), []) } }
Second `evaluate_obligation` in a block This one takes 320ms

arg0:

"Canonical { max_universe: U0, variables: [], value: ParamEnvAnd { param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst }, value: Binder(TraitPredicate(<diesel::internal::table_macro::SelectStatement<diesel::internal::table_macro::FromClause<diesel::internal::table_macro::JoinOn<diesel::internal::table_macro::Join<compile_time_test_schema::some_table_2::table, diesel::internal::table_macro::SelectStatement<diesel::internal::table_macro::FromClause<diesel::internal::table_macro::JoinOn<diesel::internal::table_macro::Join<compile_time_test_schema::some_table_3::table, diesel::internal::table_macro::SelectStatement<diesel::internal::table_macro::FromClause<diesel::internal::table_macro::JoinOn<diesel::internal::table_macro::Join<compile_time_test_schema::some_table_4::table, diesel::internal::table_macro::SelectStatement<diesel::internal::table_macro::FromClause<diesel::internal::table_macro::JoinOn<diesel::internal::table_macro::Join<compile_time_test_schema::some_table_5::table, diesel::internal::table_macro::SelectStatement<diesel::internal::table_macro::FromClause<diesel::internal::table_macro::JoinOn<diesel::internal::table_macro::Join<compile_time_test_schema::some_table_6::table, diesel::internal::table_macro::SelectStatement<diesel::internal::table_macro::FromClause<diesel::internal::table_macro::JoinOn<diesel::internal::table_macro::Join<compile_time_test_schema::some_table_7::table, diesel::internal::table_macro::SelectStatement<diesel::internal::table_macro::FromClause<diesel::internal::table_macro::JoinOn<diesel::internal::table_macro::Join<compile_time_test_schema::some_table_8::table, diesel::internal::table_macro::SelectStatement<diesel::internal::table_macro::FromClause<diesel::internal::table_macro::JoinOn<diesel::internal::table_macro::Join<compile_time_test_schema::some_table_9::table, diesel::internal::table_macro::SelectStatement<diesel::internal::table_macro::FromClause<diesel::internal::table_macro::JoinOn<diesel::internal::table_macro::Join<compile_time_test_schema::some_table_10::table, diesel::internal::table_macro::SelectStatement<diesel::internal::table_macro::FromClause<diesel::internal::table_macro::JoinOn<diesel::internal::table_macro::Join<compile_time_test_schema::some_table_11::table, diesel::internal::table_macro::SelectStatement<diesel::internal::table_macro::FromClause<diesel::internal::table_macro::JoinOn<diesel::internal::table_macro::Join<compile_time_test_schema::some_table_12::table, diesel::internal::table_macro::SelectStatement<diesel::internal::table_macro::FromClause<diesel::internal::table_macro::JoinOn<diesel::internal::table_macro::Join<compile_time_test_schema::some_table_13::table, diesel::internal::table_macro::SelectStatement<diesel::internal::table_macro::FromClause<diesel::internal::table_macro::JoinOn<diesel::internal::table_macro::Join<compile_time_test_schema::some_table_14::table, diesel::internal::table_macro::SelectStatement<diesel::internal::table_macro::FromClause<diesel::internal::table_macro::JoinOn<diesel::internal::table_macro::Join<compile_time_test_schema::some_table_15::table, diesel::internal::table_macro::SelectStatement<diesel::internal::table_macro::FromClause<diesel::internal::table_macro::JoinOn<diesel::internal::table_macro::Join<compile_time_test_schema::some_table_16::table, compile_time_test_schema::some_table_17::table, diesel::internal::table_macro::Inner>, diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_16::id>, diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_17::id>>>>>>, diesel::internal::table_macro::Inner>, diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_15::id>, diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_16::id>>>>>>, diesel::internal::table_macro::Inner>, diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_14::id>, diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_15::id>>>>>>, diesel::internal::table_macro::Inner>, diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_13::id>, diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_14::id>>>>>>, diesel::internal::table_macro::Inner>, diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_12::id>, diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_13::id>>>>>>, diesel::internal::table_macro::Inner>, diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_11::id>, diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_12::id>>>>>>, diesel::internal::table_macro::Inner>, diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_10::id>, diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_11::id>>>>>>, diesel::internal::table_macro::Inner>, diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_9::id>, diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_10::id>>>>>>, diesel::internal::table_macro::Inner>, diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_8::id>, diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_9::id>>>>>>, diesel::internal::table_macro::Inner>, diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_7::id>, diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_8::id>>>>>>, diesel::internal::table_macro::Inner>, diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_6::id>, diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_7::id>>>>>>, diesel::internal::table_macro::Inner>, diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_5::id>, diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_6::id>>>>>>, diesel::internal::table_macro::Inner>, diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_4::id>, diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_5::id>>>>>>, diesel::internal::table_macro::Inner>, diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_3::id>, diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_4::id>>>>>>, diesel::internal::table_macro::Inner>, diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_2::id>, diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_3::id>>>>>> as diesel::QuerySource>, polarity:Positive), []) } }"
Third `evaluate_obligation` in a block

This one takes 32ms

arg0:

"Canonical { max_universe: U0, variables: [], value: ParamEnvAnd { param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst }, value: Binder(TraitPredicate(<diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_1::id>, diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_2::id>>> as diesel::AppearsOnTable<diesel::internal::table_macro::Join<compile_time_test_schema::some_table_1::table, diesel::internal::table_macro::SelectStatement<diesel::internal::table_macro::FromClause<diesel::internal::table_macro::JoinOn<diesel::internal::table_macro::Join<compile_time_test_schema::some_table_2::table, diesel::internal::table_macro::SelectStatement<diesel::internal::table_macro::FromClause<diesel::internal::table_macro::JoinOn<diesel::internal::table_macro::Join<compile_time_test_schema::some_table_3::table, diesel::internal::table_macro::SelectStatement<diesel::internal::table_macro::FromClause<diesel::internal::table_macro::JoinOn<diesel::internal::table_macro::Join<compile_time_test_schema::some_table_4::table, diesel::internal::table_macro::SelectStatement<diesel::internal::table_macro::FromClause<diesel::internal::table_macro::JoinOn<diesel::internal::table_macro::Join<compile_time_test_schema::some_table_5::table, diesel::internal::table_macro::SelectStatement<diesel::internal::table_macro::FromClause<diesel::internal::table_macro::JoinOn<diesel::internal::table_macro::Join<compile_time_test_schema::some_table_6::table, diesel::internal::table_macro::SelectStatement<diesel::internal::table_macro::FromClause<diesel::internal::table_macro::JoinOn<diesel::internal::table_macro::Join<compile_time_test_schema::some_table_7::table, diesel::internal::table_macro::SelectStatement<diesel::internal::table_macro::FromClause<diesel::internal::table_macro::JoinOn<diesel::internal::table_macro::Join<compile_time_test_schema::some_table_8::table, diesel::internal::table_macro::SelectStatement<diesel::internal::table_macro::FromClause<diesel::internal::table_macro::JoinOn<diesel::internal::table_macro::Join<compile_time_test_schema::some_table_9::table, diesel::internal::table_macro::SelectStatement<diesel::internal::table_macro::FromClause<diesel::internal::table_macro::JoinOn<diesel::internal::table_macro::Join<compile_time_test_schema::some_table_10::table, diesel::internal::table_macro::SelectStatement<diesel::internal::table_macro::FromClause<diesel::internal::table_macro::JoinOn<diesel::internal::table_macro::Join<compile_time_test_schema::some_table_11::table, diesel::internal::table_macro::SelectStatement<diesel::internal::table_macro::FromClause<diesel::internal::table_macro::JoinOn<diesel::internal::table_macro::Join<compile_time_test_schema::some_table_12::table, diesel::internal::table_macro::SelectStatement<diesel::internal::table_macro::FromClause<diesel::internal::table_macro::JoinOn<diesel::internal::table_macro::Join<compile_time_test_schema::some_table_13::table, diesel::internal::table_macro::SelectStatement<diesel::internal::table_macro::FromClause<diesel::internal::table_macro::JoinOn<diesel::internal::table_macro::Join<compile_time_test_schema::some_table_14::table, diesel::internal::table_macro::SelectStatement<diesel::internal::table_macro::FromClause<diesel::internal::table_macro::JoinOn<diesel::internal::table_macro::Join<compile_time_test_schema::some_table_15::table, diesel::internal::table_macro::SelectStatement<diesel::internal::table_macro::FromClause<diesel::internal::table_macro::JoinOn<diesel::internal::table_macro::Join<compile_time_test_schema::some_table_16::table, compile_time_test_schema::some_table_17::table, diesel::internal::table_macro::Inner>, diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_16::id>, diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_17::id>>>>>>, diesel::internal::table_macro::Inner>, diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_15::id>, diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_16::id>>>>>>, diesel::internal::table_macro::Inner>, diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_14::id>, diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_15::id>>>>>>, diesel::internal::table_macro::Inner>, diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_13::id>, diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_14::id>>>>>>, diesel::internal::table_macro::Inner>, diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_12::id>, diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_13::id>>>>>>, diesel::internal::table_macro::Inner>, diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_11::id>, diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_12::id>>>>>>, diesel::internal::table_macro::Inner>, diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_10::id>, diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_11::id>>>>>>, diesel::internal::table_macro::Inner>, diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_9::id>, diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_10::id>>>>>>, diesel::internal::table_macro::Inner>, diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_8::id>, diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_9::id>>>>>>, diesel::internal::table_macro::Inner>, diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_7::id>, diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_8::id>>>>>>, diesel::internal::table_macro::Inner>, diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_6::id>, diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_7::id>>>>>>, diesel::internal::table_macro::Inner>, diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_5::id>, diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_6::id>>>>>>, diesel::internal::table_macro::Inner>, diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_4::id>, diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_5::id>>>>>>, diesel::internal::table_macro::Inner>, diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_3::id>, diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_4::id>>>>>>, diesel::internal::table_macro::Inner>, diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_2::id>, diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_3::id>>>>>>, diesel::internal::table_macro::Inner>>>, polarity:Positive), []) } }"
Fourth `evaluate_obligation` in a block

This one takes 412ms

arg0:

"Canonical { max_universe: U0, variables: [], value: ParamEnvAnd { param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst }, value: Binder(TraitPredicate(<((compile_time_test_schema::some_table_2::id, compile_time_test_schema::some_table_2::field_0, compile_time_test_schema::some_table_2::field_1, compile_time_test_schema::some_table_2::field_2, compile_time_test_schema::some_table_2::field_3, compile_time_test_schema::some_table_2::field_4, compile_time_test_schema::some_table_2::field_5, compile_time_test_schema::some_table_2::field_6, compile_time_test_schema::some_table_2::field_7, compile_time_test_schema::some_table_2::field_8, compile_time_test_schema::some_table_2::field_9), ((compile_time_test_schema::some_table_3::id, compile_time_test_schema::some_table_3::field_0, compile_time_test_schema::some_table_3::field_1, compile_time_test_schema::some_table_3::field_2, compile_time_test_schema::some_table_3::field_3, compile_time_test_schema::some_table_3::field_4, compile_time_test_schema::some_table_3::field_5, compile_time_test_schema::some_table_3::field_6, compile_time_test_schema::some_table_3::field_7, compile_time_test_schema::some_table_3::field_8, compile_time_test_schema::some_table_3::field_9), ((compile_time_test_schema::some_table_4::id, compile_time_test_schema::some_table_4::field_0, compile_time_test_schema::some_table_4::field_1, compile_time_test_schema::some_table_4::field_2, compile_time_test_schema::some_table_4::field_3, compile_time_test_schema::some_table_4::field_4, compile_time_test_schema::some_table_4::field_5, compile_time_test_schema::some_table_4::field_6, compile_time_test_schema::some_table_4::field_7, compile_time_test_schema::some_table_4::field_8, compile_time_test_schema::some_table_4::field_9), ((compile_time_test_schema::some_table_5::id, compile_time_test_schema::some_table_5::field_0, compile_time_test_schema::some_table_5::field_1, compile_time_test_schema::some_table_5::field_2, compile_time_test_schema::some_table_5::field_3, compile_time_test_schema::some_table_5::field_4, compile_time_test_schema::some_table_5::field_5, compile_time_test_schema::some_table_5::field_6, compile_time_test_schema::some_table_5::field_7, compile_time_test_schema::some_table_5::field_8, compile_time_test_schema::some_table_5::field_9), ((compile_time_test_schema::some_table_6::id, compile_time_test_schema::some_table_6::field_0, compile_time_test_schema::some_table_6::field_1, compile_time_test_schema::some_table_6::field_2, compile_time_test_schema::some_table_6::field_3, compile_time_test_schema::some_table_6::field_4, compile_time_test_schema::some_table_6::field_5, compile_time_test_schema::some_table_6::field_6, compile_time_test_schema::some_table_6::field_7, compile_time_test_schema::some_table_6::field_8, compile_time_test_schema::some_table_6::field_9), ((compile_time_test_schema::some_table_7::id, compile_time_test_schema::some_table_7::field_0, compile_time_test_schema::some_table_7::field_1, compile_time_test_schema::some_table_7::field_2, compile_time_test_schema::some_table_7::field_3, compile_time_test_schema::some_table_7::field_4, compile_time_test_schema::some_table_7::field_5, compile_time_test_schema::some_table_7::field_6, compile_time_test_schema::some_table_7::field_7, compile_time_test_schema::some_table_7::field_8, compile_time_test_schema::some_table_7::field_9), ((compile_time_test_schema::some_table_8::id, compile_time_test_schema::some_table_8::field_0, compile_time_test_schema::some_table_8::field_1, compile_time_test_schema::some_table_8::field_2, compile_time_test_schema::some_table_8::field_3, compile_time_test_schema::some_table_8::field_4, compile_time_test_schema::some_table_8::field_5, compile_time_test_schema::some_table_8::field_6, compile_time_test_schema::some_table_8::field_7, compile_time_test_schema::some_table_8::field_8, compile_time_test_schema::some_table_8::field_9), ((compile_time_test_schema::some_table_9::id, compile_time_test_schema::some_table_9::field_0, compile_time_test_schema::some_table_9::field_1, compile_time_test_schema::some_table_9::field_2, compile_time_test_schema::some_table_9::field_3, compile_time_test_schema::some_table_9::field_4, compile_time_test_schema::some_table_9::field_5, compile_time_test_schema::some_table_9::field_6, compile_time_test_schema::some_table_9::field_7, compile_time_test_schema::some_table_9::field_8, compile_time_test_schema::some_table_9::field_9), ((compile_time_test_schema::some_table_10::id, compile_time_test_schema::some_table_10::field_0, compile_time_test_schema::some_table_10::field_1, compile_time_test_schema::some_table_10::field_2, compile_time_test_schema::some_table_10::field_3, compile_time_test_schema::some_table_10::field_4, compile_time_test_schema::some_table_10::field_5, compile_time_test_schema::some_table_10::field_6, compile_time_test_schema::some_table_10::field_7, compile_time_test_schema::some_table_10::field_8, compile_time_test_schema::some_table_10::field_9), ((compile_time_test_schema::some_table_11::id, compile_time_test_schema::some_table_11::field_0, compile_time_test_schema::some_table_11::field_1, compile_time_test_schema::some_table_11::field_2, compile_time_test_schema::some_table_11::field_3, compile_time_test_schema::some_table_11::field_4, compile_time_test_schema::some_table_11::field_5, compile_time_test_schema::some_table_11::field_6, compile_time_test_schema::some_table_11::field_7, compile_time_test_schema::some_table_11::field_8, compile_time_test_schema::some_table_11::field_9), ((compile_time_test_schema::some_table_12::id, compile_time_test_schema::some_table_12::field_0, compile_time_test_schema::some_table_12::field_1, compile_time_test_schema::some_table_12::field_2, compile_time_test_schema::some_table_12::field_3, compile_time_test_schema::some_table_12::field_4, compile_time_test_schema::some_table_12::field_5, compile_time_test_schema::some_table_12::field_6, compile_time_test_schema::some_table_12::field_7, compile_time_test_schema::some_table_12::field_8, compile_time_test_schema::some_table_12::field_9), ((compile_time_test_schema::some_table_13::id, compile_time_test_schema::some_table_13::field_0, compile_time_test_schema::some_table_13::field_1, compile_time_test_schema::some_table_13::field_2, compile_time_test_schema::some_table_13::field_3, compile_time_test_schema::some_table_13::field_4, compile_time_test_schema::some_table_13::field_5, compile_time_test_schema::some_table_13::field_6, compile_time_test_schema::some_table_13::field_7, compile_time_test_schema::some_table_13::field_8, compile_time_test_schema::some_table_13::field_9), ((compile_time_test_schema::some_table_14::id, compile_time_test_schema::some_table_14::field_0, compile_time_test_schema::some_table_14::field_1, compile_time_test_schema::some_table_14::field_2, compile_time_test_schema::some_table_14::field_3, compile_time_test_schema::some_table_14::field_4, compile_time_test_schema::some_table_14::field_5, compile_time_test_schema::some_table_14::field_6, compile_time_test_schema::some_table_14::field_7, compile_time_test_schema::some_table_14::field_8, compile_time_test_schema::some_table_14::field_9), ((compile_time_test_schema::some_table_15::id, compile_time_test_schema::some_table_15::field_0, compile_time_test_schema::some_table_15::field_1, compile_time_test_schema::some_table_15::field_2, compile_time_test_schema::some_table_15::field_3, compile_time_test_schema::some_table_15::field_4, compile_time_test_schema::some_table_15::field_5, compile_time_test_schema::some_table_15::field_6, compile_time_test_schema::some_table_15::field_7, compile_time_test_schema::some_table_15::field_8, compile_time_test_schema::some_table_15::field_9), ((compile_time_test_schema::some_table_16::id, compile_time_test_schema::some_table_16::field_0, compile_time_test_schema::some_table_16::field_1, compile_time_test_schema::some_table_16::field_2, compile_time_test_schema::some_table_16::field_3, compile_time_test_schema::some_table_16::field_4, compile_time_test_schema::some_table_16::field_5, compile_time_test_schema::some_table_16::field_6, compile_time_test_schema::some_table_16::field_7, compile_time_test_schema::some_table_16::field_8, compile_time_test_schema::some_table_16::field_9), (compile_time_test_schema::some_table_17::id, compile_time_test_schema::some_table_17::field_0, compile_time_test_schema::some_table_17::field_1, compile_time_test_schema::some_table_17::field_2, compile_time_test_schema::some_table_17::field_3, compile_time_test_schema::some_table_17::field_4, compile_time_test_schema::some_table_17::field_5, compile_time_test_schema::some_table_17::field_6, compile_time_test_schema::some_table_17::field_7, compile_time_test_schema::some_table_17::field_8, compile_time_test_schema::some_table_17::field_9)))))))))))))))) as diesel::SelectableExpression<diesel::internal::table_macro::Join<compile_time_test_schema::some_table_1::table, diesel::internal::table_macro::SelectStatement<diesel::internal::table_macro::FromClause<diesel::internal::table_macro::JoinOn<diesel::internal::table_macro::Join<compile_time_test_schema::some_table_2::table, diesel::internal::table_macro::SelectStatement<diesel::internal::table_macro::FromClause<diesel::internal::table_macro::JoinOn<diesel::internal::table_macro::Join<compile_time_test_schema::some_table_3::table, diesel::internal::table_macro::SelectStatement<diesel::internal::table_macro::FromClause<diesel::internal::table_macro::JoinOn<diesel::internal::table_macro::Join<compile_time_test_schema::some_table_4::table, diesel::internal::table_macro::SelectStatement<diesel::internal::table_macro::FromClause<diesel::internal::table_macro::JoinOn<diesel::internal::table_macro::Join<compile_time_test_schema::some_table_5::table, diesel::internal::table_macro::SelectStatement<diesel::internal::table_macro::FromClause<diesel::internal::table_macro::JoinOn<diesel::internal::table_macro::Join<compile_time_test_schema::some_table_6::table, diesel::internal::table_macro::SelectStatement<diesel::internal::table_macro::FromClause<diesel::internal::table_macro::JoinOn<diesel::internal::table_macro::Join<compile_time_test_schema::some_table_7::table, diesel::internal::table_macro::SelectStatement<diesel::internal::table_macro::FromClause<diesel::internal::table_macro::JoinOn<diesel::internal::table_macro::Join<compile_time_test_schema::some_table_8::table, diesel::internal::table_macro::SelectStatement<diesel::internal::table_macro::FromClause<diesel::internal::table_macro::JoinOn<diesel::internal::table_macro::Join<compile_time_test_schema::some_table_9::table, diesel::internal::table_macro::SelectStatement<diesel::internal::table_macro::FromClause<diesel::internal::table_macro::JoinOn<diesel::internal::table_macro::Join<compile_time_test_schema::some_table_10::table, diesel::internal::table_macro::SelectStatement<diesel::internal::table_macro::FromClause<diesel::internal::table_macro::JoinOn<diesel::internal::table_macro::Join<compile_time_test_schema::some_table_11::table, diesel::internal::table_macro::SelectStatement<diesel::internal::table_macro::FromClause<diesel::internal::table_macro::JoinOn<diesel::internal::table_macro::Join<compile_time_test_schema::some_table_12::table, diesel::internal::table_macro::SelectStatement<diesel::internal::table_macro::FromClause<diesel::internal::table_macro::JoinOn<diesel::internal::table_macro::Join<compile_time_test_schema::some_table_13::table, diesel::internal::table_macro::SelectStatement<diesel::internal::table_macro::FromClause<diesel::internal::table_macro::JoinOn<diesel::internal::table_macro::Join<compile_time_test_schema::some_table_14::table, diesel::internal::table_macro::SelectStatement<diesel::internal::table_macro::FromClause<diesel::internal::table_macro::JoinOn<diesel::internal::table_macro::Join<compile_time_test_schema::some_table_15::table, diesel::internal::table_macro::SelectStatement<diesel::internal::table_macro::FromClause<diesel::internal::table_macro::JoinOn<diesel::internal::table_macro::Join<compile_time_test_schema::some_table_16::table, compile_time_test_schema::some_table_17::table, diesel::internal::table_macro::Inner>, diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_16::id>, diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_17::id>>>>>>, diesel::internal::table_macro::Inner>, diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_15::id>, diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_16::id>>>>>>, diesel::internal::table_macro::Inner>, diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_14::id>, diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_15::id>>>>>>, diesel::internal::table_macro::Inner>, diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_13::id>, diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_14::id>>>>>>, diesel::internal::table_macro::Inner>, diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_12::id>, diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_13::id>>>>>>, diesel::internal::table_macro::Inner>, diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_11::id>, diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_12::id>>>>>>, diesel::internal::table_macro::Inner>, diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_10::id>, diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_11::id>>>>>>, diesel::internal::table_macro::Inner>, diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_9::id>, diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_10::id>>>>>>, diesel::internal::table_macro::Inner>, diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_8::id>, diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_9::id>>>>>>, diesel::internal::table_macro::Inner>, diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_7::id>, diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_8::id>>>>>>, diesel::internal::table_macro::Inner>, diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_6::id>, diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_7::id>>>>>>, diesel::internal::table_macro::Inner>, diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_5::id>, diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_6::id>>>>>>, diesel::internal::table_macro::Inner>, diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_4::id>, diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_5::id>>>>>>, diesel::internal::table_macro::Inner>, diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_3::id>, diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_4::id>>>>>>, diesel::internal::table_macro::Inner>, diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_2::id>, diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_3::id>>>>>>, diesel::internal::table_macro::Inner>>>, polarity:Positive), []) } }"

Fifth `evaluate_obligation` in a block

This one takes 376ms

arg0:

"Canonical { max_universe: U0, variables: [], value: ParamEnvAnd { param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst }, value: Binder(TraitPredicate(<((compile_time_test_schema::some_table_2::id, compile_time_test_schema::some_table_2::field_0, compile_time_test_schema::some_table_2::field_1, compile_time_test_schema::some_table_2::field_2, compile_time_test_schema::some_table_2::field_3, compile_time_test_schema::some_table_2::field_4, compile_time_test_schema::some_table_2::field_5, compile_time_test_schema::some_table_2::field_6, compile_time_test_schema::some_table_2::field_7, compile_time_test_schema::some_table_2::field_8, compile_time_test_schema::some_table_2::field_9), ((compile_time_test_schema::some_table_3::id, compile_time_test_schema::some_table_3::field_0, compile_time_test_schema::some_table_3::field_1, compile_time_test_schema::some_table_3::field_2, compile_time_test_schema::some_table_3::field_3, compile_time_test_schema::some_table_3::field_4, compile_time_test_schema::some_table_3::field_5, compile_time_test_schema::some_table_3::field_6, compile_time_test_schema::some_table_3::field_7, compile_time_test_schema::some_table_3::field_8, compile_time_test_schema::some_table_3::field_9), ((compile_time_test_schema::some_table_4::id, compile_time_test_schema::some_table_4::field_0, compile_time_test_schema::some_table_4::field_1, compile_time_test_schema::some_table_4::field_2, compile_time_test_schema::some_table_4::field_3, compile_time_test_schema::some_table_4::field_4, compile_time_test_schema::some_table_4::field_5, compile_time_test_schema::some_table_4::field_6, compile_time_test_schema::some_table_4::field_7, compile_time_test_schema::some_table_4::field_8, compile_time_test_schema::some_table_4::field_9), ((compile_time_test_schema::some_table_5::id, compile_time_test_schema::some_table_5::field_0, compile_time_test_schema::some_table_5::field_1, compile_time_test_schema::some_table_5::field_2, compile_time_test_schema::some_table_5::field_3, compile_time_test_schema::some_table_5::field_4, compile_time_test_schema::some_table_5::field_5, compile_time_test_schema::some_table_5::field_6, compile_time_test_schema::some_table_5::field_7, compile_time_test_schema::some_table_5::field_8, compile_time_test_schema::some_table_5::field_9), ((compile_time_test_schema::some_table_6::id, compile_time_test_schema::some_table_6::field_0, compile_time_test_schema::some_table_6::field_1, compile_time_test_schema::some_table_6::field_2, compile_time_test_schema::some_table_6::field_3, compile_time_test_schema::some_table_6::field_4, compile_time_test_schema::some_table_6::field_5, compile_time_test_schema::some_table_6::field_6, compile_time_test_schema::some_table_6::field_7, compile_time_test_schema::some_table_6::field_8, compile_time_test_schema::some_table_6::field_9), ((compile_time_test_schema::some_table_7::id, compile_time_test_schema::some_table_7::field_0, compile_time_test_schema::some_table_7::field_1, compile_time_test_schema::some_table_7::field_2, compile_time_test_schema::some_table_7::field_3, compile_time_test_schema::some_table_7::field_4, compile_time_test_schema::some_table_7::field_5, compile_time_test_schema::some_table_7::field_6, compile_time_test_schema::some_table_7::field_7, compile_time_test_schema::some_table_7::field_8, compile_time_test_schema::some_table_7::field_9), ((compile_time_test_schema::some_table_8::id, compile_time_test_schema::some_table_8::field_0, compile_time_test_schema::some_table_8::field_1, compile_time_test_schema::some_table_8::field_2, compile_time_test_schema::some_table_8::field_3, compile_time_test_schema::some_table_8::field_4, compile_time_test_schema::some_table_8::field_5, compile_time_test_schema::some_table_8::field_6, compile_time_test_schema::some_table_8::field_7, compile_time_test_schema::some_table_8::field_8, compile_time_test_schema::some_table_8::field_9), ((compile_time_test_schema::some_table_9::id, compile_time_test_schema::some_table_9::field_0, compile_time_test_schema::some_table_9::field_1, compile_time_test_schema::some_table_9::field_2, compile_time_test_schema::some_table_9::field_3, compile_time_test_schema::some_table_9::field_4, compile_time_test_schema::some_table_9::field_5, compile_time_test_schema::some_table_9::field_6, compile_time_test_schema::some_table_9::field_7, compile_time_test_schema::some_table_9::field_8, compile_time_test_schema::some_table_9::field_9), ((compile_time_test_schema::some_table_10::id, compile_time_test_schema::some_table_10::field_0, compile_time_test_schema::some_table_10::field_1, compile_time_test_schema::some_table_10::field_2, compile_time_test_schema::some_table_10::field_3, compile_time_test_schema::some_table_10::field_4, compile_time_test_schema::some_table_10::field_5, compile_time_test_schema::some_table_10::field_6, compile_time_test_schema::some_table_10::field_7, compile_time_test_schema::some_table_10::field_8, compile_time_test_schema::some_table_10::field_9), ((compile_time_test_schema::some_table_11::id, compile_time_test_schema::some_table_11::field_0, compile_time_test_schema::some_table_11::field_1, compile_time_test_schema::some_table_11::field_2, compile_time_test_schema::some_table_11::field_3, compile_time_test_schema::some_table_11::field_4, compile_time_test_schema::some_table_11::field_5, compile_time_test_schema::some_table_11::field_6, compile_time_test_schema::some_table_11::field_7, compile_time_test_schema::some_table_11::field_8, compile_time_test_schema::some_table_11::field_9), ((compile_time_test_schema::some_table_12::id, compile_time_test_schema::some_table_12::field_0, compile_time_test_schema::some_table_12::field_1, compile_time_test_schema::some_table_12::field_2, compile_time_test_schema::some_table_12::field_3, compile_time_test_schema::some_table_12::field_4, compile_time_test_schema::some_table_12::field_5, compile_time_test_schema::some_table_12::field_6, compile_time_test_schema::some_table_12::field_7, compile_time_test_schema::some_table_12::field_8, compile_time_test_schema::some_table_12::field_9), ((compile_time_test_schema::some_table_13::id, compile_time_test_schema::some_table_13::field_0, compile_time_test_schema::some_table_13::field_1, compile_time_test_schema::some_table_13::field_2, compile_time_test_schema::some_table_13::field_3, compile_time_test_schema::some_table_13::field_4, compile_time_test_schema::some_table_13::field_5, compile_time_test_schema::some_table_13::field_6, compile_time_test_schema::some_table_13::field_7, compile_time_test_schema::some_table_13::field_8, compile_time_test_schema::some_table_13::field_9), ((compile_time_test_schema::some_table_14::id, compile_time_test_schema::some_table_14::field_0, compile_time_test_schema::some_table_14::field_1, compile_time_test_schema::some_table_14::field_2, compile_time_test_schema::some_table_14::field_3, compile_time_test_schema::some_table_14::field_4, compile_time_test_schema::some_table_14::field_5, compile_time_test_schema::some_table_14::field_6, compile_time_test_schema::some_table_14::field_7, compile_time_test_schema::some_table_14::field_8, compile_time_test_schema::some_table_14::field_9), ((compile_time_test_schema::some_table_15::id, compile_time_test_schema::some_table_15::field_0, compile_time_test_schema::some_table_15::field_1, compile_time_test_schema::some_table_15::field_2, compile_time_test_schema::some_table_15::field_3, compile_time_test_schema::some_table_15::field_4, compile_time_test_schema::some_table_15::field_5, compile_time_test_schema::some_table_15::field_6, compile_time_test_schema::some_table_15::field_7, compile_time_test_schema::some_table_15::field_8, compile_time_test_schema::some_table_15::field_9), ((compile_time_test_schema::some_table_16::id, compile_time_test_schema::some_table_16::field_0, compile_time_test_schema::some_table_16::field_1, compile_time_test_schema::some_table_16::field_2, compile_time_test_schema::some_table_16::field_3, compile_time_test_schema::some_table_16::field_4, compile_time_test_schema::some_table_16::field_5, compile_time_test_schema::some_table_16::field_6, compile_time_test_schema::some_table_16::field_7, compile_time_test_schema::some_table_16::field_8, compile_time_test_schema::some_table_16::field_9), (compile_time_test_schema::some_table_17::id, compile_time_test_schema::some_table_17::field_0, compile_time_test_schema::some_table_17::field_1, compile_time_test_schema::some_table_17::field_2, compile_time_test_schema::some_table_17::field_3, compile_time_test_schema::some_table_17::field_4, compile_time_test_schema::some_table_17::field_5, compile_time_test_schema::some_table_17::field_6, compile_time_test_schema::some_table_17::field_7, compile_time_test_schema::some_table_17::field_8, compile_time_test_schema::some_table_17::field_9)))))))))))))))) as diesel::SelectableExpression<diesel::internal::table_macro::JoinOn<diesel::internal::table_macro::Join<compile_time_test_schema::some_table_1::table, diesel::internal::table_macro::SelectStatement<diesel::internal::table_macro::FromClause<diesel::internal::table_macro::JoinOn<diesel::internal::table_macro::Join<compile_time_test_schema::some_table_2::table, diesel::internal::table_macro::SelectStatement<diesel::internal::table_macro::FromClause<diesel::internal::table_macro::JoinOn<diesel::internal::table_macro::Join<compile_time_test_schema::some_table_3::table, diesel::internal::table_macro::SelectStatement<diesel::internal::table_macro::FromClause<diesel::internal::table_macro::JoinOn<diesel::internal::table_macro::Join<compile_time_test_schema::some_table_4::table, diesel::internal::table_macro::SelectStatement<diesel::internal::table_macro::FromClause<diesel::internal::table_macro::JoinOn<diesel::internal::table_macro::Join<compile_time_test_schema::some_table_5::table, diesel::internal::table_macro::SelectStatement<diesel::internal::table_macro::FromClause<diesel::internal::table_macro::JoinOn<diesel::internal::table_macro::Join<compile_time_test_schema::some_table_6::table, diesel::internal::table_macro::SelectStatement<diesel::internal::table_macro::FromClause<diesel::internal::table_macro::JoinOn<diesel::internal::table_macro::Join<compile_time_test_schema::some_table_7::table, diesel::internal::table_macro::SelectStatement<diesel::internal::table_macro::FromClause<diesel::internal::table_macro::JoinOn<diesel::internal::table_macro::Join<compile_time_test_schema::some_table_8::table, diesel::internal::table_macro::SelectStatement<diesel::internal::table_macro::FromClause<diesel::internal::table_macro::JoinOn<diesel::internal::table_macro::Join<compile_time_test_schema::some_table_9::table, diesel::internal::table_macro::SelectStatement<diesel::internal::table_macro::FromClause<diesel::internal::table_macro::JoinOn<diesel::internal::table_macro::Join<compile_time_test_schema::some_table_10::table, diesel::internal::table_macro::SelectStatement<diesel::internal::table_macro::FromClause<diesel::internal::table_macro::JoinOn<diesel::internal::table_macro::Join<compile_time_test_schema::some_table_11::table, diesel::internal::table_macro::SelectStatement<diesel::internal::table_macro::FromClause<diesel::internal::table_macro::JoinOn<diesel::internal::table_macro::Join<compile_time_test_schema::some_table_12::table, diesel::internal::table_macro::SelectStatement<diesel::internal::table_macro::FromClause<diesel::internal::table_macro::JoinOn<diesel::internal::table_macro::Join<compile_time_test_schema::some_table_13::table, diesel::internal::table_macro::SelectStatement<diesel::internal::table_macro::FromClause<diesel::internal::table_macro::JoinOn<diesel::internal::table_macro::Join<compile_time_test_schema::some_table_14::table, diesel::internal::table_macro::SelectStatement<diesel::internal::table_macro::FromClause<diesel::internal::table_macro::JoinOn<diesel::internal::table_macro::Join<compile_time_test_schema::some_table_15::table, diesel::internal::table_macro::SelectStatement<diesel::internal::table_macro::FromClause<diesel::internal::table_macro::JoinOn<diesel::internal::table_macro::Join<compile_time_test_schema::some_table_16::table, compile_time_test_schema::some_table_17::table, diesel::internal::table_macro::Inner>, diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_16::id>, diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_17::id>>>>>>, diesel::internal::table_macro::Inner>, diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_15::id>, diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_16::id>>>>>>, diesel::internal::table_macro::Inner>, diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_14::id>, diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_15::id>>>>>>, diesel::internal::table_macro::Inner>, diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_13::id>, diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_14::id>>>>>>, diesel::internal::table_macro::Inner>, diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_12::id>, diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_13::id>>>>>>, diesel::internal::table_macro::Inner>, diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_11::id>, diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_12::id>>>>>>, diesel::internal::table_macro::Inner>, diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_10::id>, diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_11::id>>>>>>, diesel::internal::table_macro::Inner>, diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_9::id>, diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_10::id>>>>>>, diesel::internal::table_macro::Inner>, diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_8::id>, diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_9::id>>>>>>, diesel::internal::table_macro::Inner>, diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_7::id>, diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_8::id>>>>>>, diesel::internal::table_macro::Inner>, diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_6::id>, diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_7::id>>>>>>, diesel::internal::table_macro::Inner>, diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_5::id>, diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_6::id>>>>>>, diesel::internal::table_macro::Inner>, diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_4::id>, diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_5::id>>>>>>, diesel::internal::table_macro::Inner>, diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_3::id>, diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_4::id>>>>>>, diesel::internal::table_macro::Inner>, diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_2::id>, diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_3::id>>>>>>, diesel::internal::table_macro::Inner>, diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_1::id>, diesel::internal::table_macro::NullableExpression<compile_time_test_schema::some_table_2::id>>>>>>, polarity:Positive), []) } }"

@Ten0
Copy link
Member Author

Ten0 commented Jul 15, 2022

About notably fourth block:

Looks like the fields of the table (even if unused afterwards) intervene a lot here.
Removing them from there by doing something similar to this:
Ten0@b4fcea0
appears to significantly reduce compilation time, but does not remove the exponential behavior.

NB: that commit is based on an older version of Diesel that would make it easier to try and remove the QuerySource bound from building the join sequence to see if that works around the issue, which is hard in current version because of the lifetime requirement in the query builder (#2931) that makes it necessary to have the bound on the Join type. (That could probably be fixed by using the first design suggested at #2984 (comment) but I figured it would probably be easier to just test on an old version whether that actually fixes the issue before doing that huge work)

@weiznich
Copy link
Member

It's interesting that not appending to the large tuple is expensive, but rather than that checking if a select clause is valid. The corresponding trait impl is rather simple:

impl<$($T,)+ QS> SelectableExpression<QS> for ($($T,)+) where

Btw: @Ten0 It would be great to land the postgres row-by-row PR soon, so that I can at least release a 2.0.0-rc.1 version.

@weiznich
Copy link
Member

weiznich commented Aug 9, 2022

I spend a bit more time to look into this. Commenting out the following trait bounds reduces compilation time drastically for me (from 5s to < 1s for 17 joins)

$($T: SelectableExpression<QS>,)+

$($T: AppearsOnTable<QS>,)+

Interestingly both impls needs to be removed. Unfortunately are both impls required for checking whether something is selectable for a given table or not.

The following traits are involved there:

pub trait SelectableExpression<QS: ?Sized>: AppearsOnTable<QS> {}
pub trait AppearsOnTable<QS: ?Sized>: Expression {}
pub trait Expression {
    type SqlType: TypedExpressionType;
}
pub trait TypedExpressionType {}

They are all implemented for tuples of various sizes. I guess that rustc is doing a lot more work as required there. Something like it starts checking if (some, large, tuple, (nested, tuple)): SelectableExpression<QS> holds by first checking the bound T: SelectableExpression<QS> for all tuple members. This implies checking all of the parent traits as well. Some of the tuple members are tuples itself, so this is a quite recursive process. Likely it is checking all of the parent traits again later on because there is Self: AppearsOnTable<QS> bound there as well. The same thing likely happens for resolving the parent traits as well, as they also depend on another level of parent traits.

I've tried to put that observation in a minimal example, but I haven't been able to reproduce it there yet. Likely I miss an important detail or just choose too small tuple sizes. @lqd are there any easy ways to check that hypothesis through rustc logging/instrumentation?

@Ten0
Copy link
Member Author

Ten0 commented Aug 18, 2022

So I started the work on this again today, findings/recap:

We have 3 separate sub-issues:

  1. Diesel has the compiler check a ton of trait bounds when building a plain join sequence. In particular, SelectableExpression and AppearsOnTable.
  2. Compiler seems to be extremely slow at checking these bounds.
  3. On our biggest crate (but no minimal repro as of yet) we re-typecheck the whole crate no matter what we change. That seems to not be the case for my current minimal repro.

I tackled part of 1:
a. https://github.com/Ten0/diesel/tree/f013252e34151431d405d8abd26b6e038e38377e (removing default selection) shows very noticeable improvement (from 2m10s to 20s on our largest crate). This seems to be essentially a sound approach to avoid checking so many SelectableExpression and AppearsOnTable bounds. (couldn't think of unsoundness/broken stuff but you're welcome to think about it as well)
That seems to be a reasonable first step (obviously will need some cleaning/feature flagging or table! setting...)
I think not having a default select expression would be a reasonable default, esp. since we now have Selectable and we (me & coworkers) have deemed leaving the default clause a bad enough practice that we prohibit it because it:

  • Selects unnecessary stuff
  • Is error-prone as it relies on default field order, and that field order is declared very far apart from the query (in schema.rs) and subject to somewhat-automated change through migrations that would not have the user reconsider all the related queries.

Next steps to further improve on 1 enough to get to a reasonable compile time would be:
b. since even after that most of the time is still spent checking trait bounds on huge nested SelectStatement<Join<SelectStatement... sequences, trying to simplify the output structs for join-related stuff. Ideally I'd like to not even go through select statement and not check validity of each such inner select statement before building a final one that's not nested so much.
Possibly we would then run into requiring refactoring serialization to allow serializing stuff that is not pre-allocated in the query, allowing to nest less stuff. (as mentionned here).

Pushing further on 1 or 2 or 3 would probably make dev flow reasonable. (we aim for <~2s before we get typecheck feedback in IDE)
I estimate 3 to be more likely than 2 to uncover something that would be actionable, and less time-consuming to work on for now than 1.b.

So my next steps will probably be to:
A. PR 1.a
B. Try and minimize a repro for sub-issue 3, but if 3 turns out to be a dead end then I may come back to 1.b.

@lsunsi
Copy link

lsunsi commented Aug 18, 2022

@Ten0 Just wanted to thank you on this investigation. I've been subscribed to this issue because I have a production codebase suffering from this typeck issue as well.

@Ten0
Copy link
Member Author

Ten0 commented Aug 18, 2022

Just wanted to thank you on this investigation. I've been subscribed to this issue because I have a production codebase suffering from this typeck issue as well.

Thank you! :)
In this kind of scenario you may generally want to upvote the opening message as that gives a simple way to have an idea of how many people are impacted. :)

@Ten0
Copy link
Member Author

Ten0 commented Aug 19, 2022

feature flagging or table! setting

@weiznich any strong preference for either of these two?

@weiznich
Copy link
Member

Sorry to say that, but I would like to avoid both. In my opinion it is a really bad idea to make this behaviour configurable, as it makes it even harder to document what joins will do in diesel. That's already a large issue as it's not obvious for may users. Adding further configurations there will really hurt and have non-local effects.

It might be a better solution to just somehow skip the checks to AppearsOnTable + SelectableExpression for those nested default select clauses at all. We already know that they are valid, because the default select clause of each table is valid.

@Ten0
Copy link
Member Author

Ten0 commented Aug 19, 2022

Sorry to say that, but I would like to avoid both. In my opinion it is a really bad idea to make this behaviour configurable, as it makes it even harder to document what joins will do in diesel. That's already a large issue as it's not obvious for may users. Adding further configurations there will really hurt and have non-local effects.

It might be a better solution to just somehow skip the checks to AppearsOnTable + SelectableExpression for those nested default select clauses at all. We already know that they are valid, because the default select clause of each table is valid.

How about just removing default select clauses altogether then?
Looks like this would avoid:

  • "makes it even harder to document what joins will do in diesel"
  • "have non-local effects"
  • "Selects unnecessary stuff"
  • "Is error-prone"

That seems particularly acceptable now that we have Selectable. Overall that would simplify a bunch of things.

weiznich added a commit to weiznich/diesel that referenced this issue Aug 19, 2022
`DefaultSelection` type of joins

This commit introduces infrastructure that allows to skip type checking
the `DefaultSelection` of joins. diesel-rs#3223 discovered that this is
responsible for a substantial amount of compile time for larger
joins/codebases. We do not need to check this constraint there as it is
always true because each of the tables/sides of the join already have an
valid `DefaultSelection`. Therefore the resulting `DefaultSelection`
must be valid for the join too (if there is no bug in diesel itself).
@weiznich
Copy link
Member

Removing the default select clause would be an option and I agree that it might be desirable for the reasons listed. But I feel that's a too large breaking change for now. Basically all existing code (that does use a stable release from crates.io) relies on this. So just removing it now would unfortunately impact to much code in a non-trivial way. If we plan to do this someday we should introduce a proper deprecation period for this feature + offer a complete migration story before finally removing this feature.

I've put together weiznich@567bb1d which skips the SelectableExpression check for the DefaultSelection of inner joins. This should not be a breaking change at all and this shows quite significant reductions in compile times for your example above. Please note that this approach would require additional work to figure out which other traits can be skipped as well. Maybe it's even possible to delay checking the Expression and ValidGrouing<> bound as well until the query is actually executed. This would allow to always set a custom select clause to avoid this checks too. In my opinion that's the better approach for now.

@Ten0
Copy link
Member Author

Ten0 commented Aug 22, 2022

I've pushed to your speedup_compile_times_for_joins one extra commit that was required to make stuff like this compile:

let q = schema::some_table_1::table
		.inner_join(schema::some_table_2::table)
		.inner_join(schema::some_table_3::table.inner_join(schema::some_table_4::table));

With this additional change I was able to compile our main crate, and that took 25s (instead of 20s for the no-default-selection approach). (I suspect the difference is due to the still-present requirement of checking AppearsOnTable for the default select clauses for each table present in the join - although only once now - which I also wish we could skip.)

However, this approach seems to start allowing invalid queries of this kind:

	let q: (
		(i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32),
		(i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32),
		(
			(i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32),
			(i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32),
		),
	) = schema::some_table_1::table
		.inner_join(schema::some_table_4::table)
		.inner_join(schema::some_table_3::table.inner_join(schema::some_table_4::table))
		.get_result(db)
		.unwrap();

(notice how some_table_4appears twice in this query)

In other words, the following statement seems to be invalid when several join chains come into play:
"combining two valid selectable expressions for both tables will always yield a valid selectable expressions for the whole join".

On the current master, this correctly fails to typecheck.

NB: Another advantage of allowing to remove default selections for tables would be that it's not required anymore to increase diesel's compilation time a ton with the n-column-tables features as long as you never select all of those columns at the same time (which is also the case for us).

NB2: No-default-selection seems to suffer from a similar issue where the following also typechecks:

	let q: i32 = schema::some_table_1::table
		.inner_join(schema::some_table_4::table)
		.inner_join(schema::some_table_3::table.inner_join(schema::some_table_4::table))
		.select(schema::some_table_1::id)
		.get_result(db)
		.unwrap();

My guess would be this means that AppearsOnTable for the on clauses is never checked.

@weiznich
Copy link
Member

weiznich commented Aug 23, 2022

@Ten0 I've pushed another update that addresses the issues you've found. I continue to see an speedup from ~5s down to < 1s for your example repository with an example join with 17 tables for cases where the incremental compilation does not cache the results. Rustc self compile does report that the longest typecheck query now takes less than 20ms (400ms overall for typecheck). I feel that are good results without doing major breaking changes. (As outlined above I feel that's not possible that close to a release anymore).

The next step for future speedups on your code base would likely to check the self compile output again to see where the time is spend now. It's quite possible that there are other places with could need some optimization as well.

@Ten0
Copy link
Member Author

Ten0 commented Aug 24, 2022

The current state of #3288 looks good to me (almost) for merge, and the state of the investigation on this issue is such that I'm fine with 2.0 release at this point :) (looks like further improvements are unlikely to be easy breaking changes)

On the topic of this issue still, I get 28s of compilation with this (vs 20 and 25 with previous iterations - that weren't completely sound). The self-profiling output of my crate seems to show that the vast majority of the time is still spent checking Diesel trait bounds - so I don't think we can resolve this issue just yet (although it will probably require a rename ^^).

On other news, I've found #2931 to be responsible for some part of the compilation time there, as it introduces this kind of bounds checks:
https://github.com/diesel-rs/diesel/pull/2931/files#diff-7ca93b1537271394be3fa89ae39f924f906c98c2f01520247ee2a38a38fcb029R228-R231
a bit everywhere

All because of:
https://github.com/diesel-rs/diesel/pull/2931/files#diff-4c3c5e08e6c23444455157fb9a8be55d84d7df7198e8c69114d664bb354d2e61R48-R51

On the issue reproduction crate I get:

  • 14 Joins: before: 2.3s, after: 3.2s
  • 17 Joins: before: 3.9s after: 6.42s

(#3288 performs much better than both)

-> Attempting to decouple QueryFragment implementations from the query builder representations using this design (re-allowing https://github.com/diesel-rs/diesel/pull/2931/files#diff-7ca93b1537271394be3fa89ae39f924f906c98c2f01520247ee2a38a38fcb029L162) would consequently be likely to show significant compilation time improvement (while also overall simplifying the query builder representations) - although we have to keep in mind the following comment.

That however is a large enough work (if it even works) that I'm fine with not delaying 2.0 further, esp. since I still want to investigate 3 before. :)

@weiznich
Copy link
Member

On other news, I've found #2931 to be responsible for some part of the compilation time there, as it introduces this kind of bounds checks:
https://github.com/diesel-rs/diesel/pull/2931/files#diff-7ca93b1537271394be3fa89ae39f924f906c98c2f01520247ee2a38a38fcb029R228-R231
a bit everywhere

All because of:
https://github.com/diesel-rs/diesel/pull/2931/files#diff-4c3c5e08e6c23444455157fb9a8be55d84d7df7198e8c69114d664bb354d2e61R48-R51

Thanks for doing this investigation. Those links are broken for me, or at least they do not jump to any line. Maybe you can replace them with links to the corresponding trait bounds on the master branch?

@Ten0
Copy link
Member Author

Ten0 commented Aug 25, 2022

Those links are broken for me, or at least they do not jump to any line

behavior for me on Firefox and Chromium is that they end up jumping to the correct place if you wait long enough (~15s ^^)

@lsunsi
Copy link

lsunsi commented Aug 25, 2022

@Ten0 Same for me, 15s! haha

@weiznich
Copy link
Member

Seems like I did not wait long enough. It's working now 👍

@dancixx

This comment was marked as off-topic.

@weiznich
Copy link
Member

weiznich commented Apr 5, 2023

@dancixx As long as you don't provide any new information these kind of posts is highly discouraged as they are not helpful at all. At least you would need to provide an reproducible example here, otherwise please stop posting to old issues.

@dancixx

This comment was marked as off-topic.

@weiznich

This comment was marked as off-topic.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants